diff --git a/include/client/fuse/fuse_client.hpp b/include/client/fuse/fuse_client.hpp index cbc0a6feda3b203db21074fb0c6e178cb0a7ab73..a9e9db0223e91cc1b7c7adb6134944bf5a56971f 100644 --- a/include/client/fuse/fuse_client.hpp +++ b/include/client/fuse/fuse_client.hpp @@ -64,6 +64,7 @@ extern "C" { #include #include #include +#include #include #include #include diff --git a/src/client/fuse/fuse_client.cpp b/src/client/fuse/fuse_client.cpp index 3b758da169badd4f208a4b16d4cd600e87d80a66..23f592b077a41fd1d400115ee05edfe519a5ff3f 100644 --- a/src/client/fuse/fuse_client.cpp +++ b/src/client/fuse/fuse_client.cpp @@ -59,6 +59,13 @@ static const std::string fifo_path = "/tmp/gekkofs_fifos/"; #define DEBUG_INFO(...) /* No debug output */ #endif +#include + +namespace gkfs::syscall { +int +gkfs_statfs(struct statfs* buf); +} + static fuse_ino_t alloc_inode(const std::string& path) { std::lock_guard lk(ino_mutex); @@ -314,7 +321,7 @@ lookup_handler(fuse_req_t req, fuse_ino_t parent, const char* name) { fuse_entry_param e = {}; int rc = fill_fuse_entry_param(ud, child, e); if(rc < 0) { - fuse_reply_err(req, ENOENT); + fuse_reply_err(req, errno); return; } fuse_reply_entry(req, &e); @@ -389,7 +396,7 @@ open_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) { int fd = gkfs::syscall::gkfs_open(inode->path, mode, fi->flags); // TODO mode! if(fd < 0) { - fuse_reply_err(req, ENOENT); + fuse_reply_err(req, errno); return; } fi->fh = fd; @@ -404,7 +411,7 @@ lseek_handler(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, DEBUG_INFO(ud, "lseek handler"); int lc = gkfs::syscall::gkfs_lseek(fi->fh, off, whence); if(lc < 0) { - fuse_reply_err(req, 1); + fuse_reply_err(req, errno); return; } fuse_reply_lseek(req, lc); @@ -489,7 +496,7 @@ create_handler(fuse_req_t req, fuse_ino_t parent, const char* name, mode_t mode, fuse_entry_param e = {}; int sc = fill_fuse_entry_param(ud, path, e, false); if(sc < 0) { - fuse_reply_err(req, ENOENT); + fuse_reply_err(req, errno); return; } fuse_reply_create(req, &e, fi); @@ -522,7 +529,7 @@ unlink_handler(fuse_req_t req, fuse_ino_t parent, const char* name) { int rc = gkfs::syscall::gkfs_remove(path); remove_inode_by_path(path); if(rc == -1) { - fuse_reply_err(req, 1); + fuse_reply_err(req, errno); return; } fuse_reply_err(req, 0); @@ -635,6 +642,32 @@ readdir_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, free(buf); } +static void +statfs_handler(fuse_req_t req, fuse_ino_t ino) { + auto* ud = udata(req); + DEBUG_INFO(ud, "statfs handler ino %u", ino); + struct statfs stfs{}; + int rc = gkfs::syscall::gkfs_statfs(&stfs); + if(rc < 0) { + fuse_reply_err(req, errno); + return; + } + struct statvfs stvfs{}; + stvfs.f_bsize = stfs.f_bsize; + stvfs.f_frsize = stfs.f_frsize; + stvfs.f_blocks = stfs.f_blocks; + stvfs.f_bfree = stfs.f_bfree; + stvfs.f_bavail = stfs.f_bavail; + stvfs.f_files = stfs.f_files; + stvfs.f_ffree = stfs.f_ffree; + stvfs.f_favail = stfs.f_ffree; + stvfs.f_fsid = stfs.f_fsid.__val[0]; // Simplified + stvfs.f_flag = stfs.f_flags; + stvfs.f_namemax = stfs.f_namelen; + + fuse_reply_statfs(req, &stvfs); +} + static void readdirplus_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info* fi) { @@ -767,7 +800,7 @@ release_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) { } int lc = gkfs::syscall::gkfs_close(fi->fh); if(lc < 0) { - fuse_reply_err(req, 1); + fuse_reply_err(req, errno); return; } fuse_reply_err(req, 0); @@ -812,7 +845,7 @@ flush_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) { } int lc = gkfs::syscall::gkfs_fsync(fi->fh); if(lc < 0) { - fuse_reply_err(req, 1); + fuse_reply_err(req, errno); return; } fuse_reply_err(req, 0); @@ -837,7 +870,7 @@ access_handler(fuse_req_t req, fuse_ino_t ino, int mask) { } int lc = gkfs::syscall::gkfs_access(inode->path, mask, true); if(lc < 0) { - fuse_reply_err(req, 1); + fuse_reply_err(req, errno); return; } fuse_reply_err(req, 0); @@ -861,7 +894,7 @@ mkdir_handler(fuse_req_t req, fuse_ino_t parent, const char* name, DEBUG_INFO(ud, "mkdir parent %s name %s", parent_inode->path.c_str(), name); int rc = gkfs::syscall::gkfs_create(path, mode | S_IFDIR); if(rc == -1) { - fuse_reply_err(req, 1); + fuse_reply_err(req, errno); return; } @@ -904,7 +937,7 @@ readlink_handler(fuse_req_t req, fuse_ino_t ino) { char link[PATH_MAX]; int rc = gkfs::syscall::gkfs_readlink(inode->path, link, PATH_MAX); if(rc == -1) { - fuse_reply_err(req, 1); + fuse_reply_err(req, errno); return; } link[rc] = '\0'; @@ -936,7 +969,7 @@ symlink_handler(fuse_req_t req, const char* linkname, fuse_ino_t parent, int rc = gkfs::syscall::gkfs_mk_symlink(path, target); if(rc < 0) { - fuse_reply_err(req, 1); + fuse_reply_err(req, errno); return; } @@ -996,20 +1029,18 @@ rename_handler(fuse_req_t req, fuse_ino_t old_parent, const char* old_name, return; } + errno = 0; int rc = gkfs::syscall::gkfs_rename(old_path, new_path); if(rc < 0) { - fuse_reply_err(req, 1); + fuse_reply_err(req, errno); return; } ino_mutex.lock(); - auto it_end = path_map.end(); auto it_src = path_map.find(old_path); - ino_mutex.unlock(); - fuse_ino_t src_ino = 0; - if(it_src != it_end) { + if(it_src != path_map.end()) { src_ino = it_src->second; path_map.erase(it_src); path_map[new_path] = src_ino; @@ -1017,6 +1048,8 @@ rename_handler(fuse_req_t req, fuse_ino_t old_parent, const char* old_name, src_ino = alloc_inode(new_path); path_map[new_path] = src_ino; } + ino_mutex.unlock(); + auto* inode = get_inode(src_ino); if(inode) { inode->path = new_path; @@ -1166,7 +1199,7 @@ init_ll_ops(fuse_lowlevel_ops* ops) { ops->destroy = destroy_handler; // ops->tmpfile // not supported in fuse < 3 - // ops->statfs = nullptr; + ops->statfs = statfs_handler; // ops->flock // ops->getlk // ops->setlk diff --git a/src/client/gkfs_metadata.cpp b/src/client/gkfs_metadata.cpp index 3fe78cbf4891c34f42609858e5cd94ab4df940b8..5be1ab7879f8734363af07757b9a2c4e2992a8a6 100644 --- a/src/client/gkfs_metadata.cpp +++ b/src/client/gkfs_metadata.cpp @@ -577,7 +577,6 @@ gkfs_rename(const string& old_path, const string& new_path) { return -1; } - auto md_new = gkfs::utils::get_metadata(new_path, false); if(md_new) { // the new file exists... check for circular... @@ -608,6 +607,7 @@ gkfs_rename(const string& old_path, const string& new_path) { } return 0; } + errno = EPERM; return -1; } else { @@ -623,6 +623,9 @@ gkfs_rename(const string& old_path, const string& new_path) { md_old = gkfs::utils::get_metadata(original_path, false); if(!md_old) { + fprintf(stderr, + "GKFS_RENAME: md_old missing intermediate %d\n", + errno); return -1; } } @@ -637,15 +640,20 @@ gkfs_rename(const string& old_path, const string& new_path) { if(!S_ISLNK(md_old->mode())) { err = gkfs::rpc::forward_rename(original_path, new_path, md_old.value()); + fprintf(stderr, "GKFS_RENAME: forward_rename err=%d\n", err); } else { // Was a link so do a forward symlink to regenerate it err = gkfs_mk_symlink(new_path, original_path); + fprintf(stderr, "GKFS_RENAME: gkfs_mk_symlink err=%d\n", err); } if(err) { errno = err; + fprintf(stderr, "GKFS_RENAME: forward failed setting errno=%d\n", + errno); return -1; } } + fprintf(stderr, "GKFS_RENAME: success returning 0\n"); return 0; } #endif diff --git a/src/client/path.cpp b/src/client/path.cpp index b27c08ef6be5884b92c8a635cfa40d1bfd944afc..087f0c1da061ea2abe0d049fbc66775a0c388695 100644 --- a/src/client/path.cpp +++ b/src/client/path.cpp @@ -462,7 +462,20 @@ init_cwd() { void set_cwd(const string& path, bool internal) { if(internal) { - set_sys_cwd(CTX->mountdir()); + // If the mountdir does not exist physically (virtual mountpoint), + // chdir will fail. This is common when using LD_PRELOAD without + // actually creating the mountpoint directory. + struct stat st; + if(syscall_no_intercept(SYS_newfstatat, AT_FDCWD, + CTX->mountdir().c_str(), &st, 0) == 0 && + S_ISDIR(st.st_mode)) { + set_sys_cwd(CTX->mountdir()); + } else { + LOG(WARNING, + "Mountdir '{}' does not exist locally. Falling back to '/' for system CWD.", + CTX->mountdir()); + set_sys_cwd("/"); + } set_env_cwd(path); CTX->cwd(path); } else {