Commit bd9b2117 authored by Ramon Nou's avatar Ramon Nou
Browse files

Fuse errno fix

parent d412bf3d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ extern "C" {
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <sys/stat.h>
#include <filesystem>
#include <unistd.h>
+50 −17
Original line number Diff line number Diff line
@@ -59,6 +59,13 @@ static const std::string fifo_path = "/tmp/gekkofs_fifos/";
#define DEBUG_INFO(...) /* No debug output */
#endif

#include <sys/statfs.h>

namespace gkfs::syscall {
int
gkfs_statfs(struct statfs* buf);
}

static fuse_ino_t
alloc_inode(const std::string& path) {
    std::lock_guard<std::mutex> 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
+9 −1
Original line number Diff line number Diff line
@@ -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
+14 −1
Original line number Diff line number Diff line
@@ -462,7 +462,20 @@ init_cwd() {
void
set_cwd(const string& path, bool internal) {
    if(internal) {
        // 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 {