Commit 07dcf660 authored by sevenuz's avatar sevenuz Committed by Julius Athenstaedt
Browse files

renaming support

parent aec76d22
Loading
Loading
Loading
Loading
+88 −4
Original line number Diff line number Diff line
@@ -678,7 +678,8 @@ symlink_handler(fuse_req_t req, const char* linkname, fuse_ino_t parent,

    if(target.rfind(ud->source, 0) == 0) {
        // starts with mount path
        target = get_path(parent_inode, target.substr(strlen(ud->source)).c_str());
        target = get_path(parent_inode,
                          target.substr(strlen(ud->source)).c_str());
    }

    fuse_log(FUSE_LOG_DEBUG, "mk symlink path %s target %s\n", path.c_str(),
@@ -712,6 +713,89 @@ symlink_handler(fuse_req_t req, const char* linkname, fuse_ino_t parent,
#endif
}

static void
rename_handler(fuse_req_t req, fuse_ino_t old_parent, const char* old_name,
               fuse_ino_t new_parent, const char* new_name,
               unsigned int flags) {

#ifdef HAS_RENAME
    auto* old_parent_inode = get_inode(old_parent);
    if(!old_parent_inode) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    auto* new_parent_inode = get_inode(new_parent);
    if(!new_parent_inode) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    std::string old_path = get_path(old_parent_inode, old_name);
    std::string new_path = get_path(new_parent_inode, new_name);

    struct stat st_src{};
    if(gkfs::syscall::gkfs_stat(old_path, &st_src) < 0) {
        fuse_reply_err(req, errno == 0 ? ENOENT : errno);
        return;
    }

    struct stat st_dst{};
    const bool dst_exists = (gkfs::syscall::gkfs_stat(new_path, &st_dst) == 0);

    if((flags & RENAME_NOREPLACE) && dst_exists) {
        fuse_reply_err(req, EEXIST);
        return;
    }

    if(flags & RENAME_EXCHANGE) {
        fuse_reply_err(req, EOPNOTSUPP);
        return;
    }

    int rc = gkfs::syscall::gkfs_rename(old_path, new_path);
    if(rc < 0) {
        fuse_reply_err(req, 1);
        return;
    }

    fuse_ino_t src_ino = 0;
    auto it_src = path_map.find(old_path);
    if(it_src != path_map.end()) {
        src_ino = it_src->second;
        path_map.erase(it_src);
        path_map[new_path] = src_ino;
        ino_map[src_ino].path = new_path;
    } else {
        src_ino = alloc_inode(new_path);
        path_map[new_path] = src_ino;
        ino_map[src_ino].path = new_path;
        ino_map[src_ino].st = st_src;
    }

    // If destination existed and was overwritten, detach its mapping
    if(dst_exists) {
        auto it_dst = path_map.find(new_path);
        if(it_dst != path_map.end()) {
            fuse_ino_t dst_ino = it_dst->second;
            path_map.erase(it_dst);

            // Mark the old dst inode as disconnected (no pathname).
            // Keep it alive until lookup_count==0 and open_count==0, then free
            // in forget().
            auto& dst_rec = ino_map[dst_ino];
            dst_rec.path.clear();
        }
    }

    // Refresh src inode attributes under its new name
    struct stat st_new{};
    if(gkfs::syscall::gkfs_stat(new_path, &st_new) == 0) {
        ino_map[src_ino].st = st_new;
    }
    fuse_reply_err(req, 0);
#else
    fuse_reply_err(req, ENOTSUP);
#endif
}

static void
init_gekkofs() {
@@ -754,7 +838,7 @@ init_ll_ops(fuse_lowlevel_ops* ops) {
    ops->readlink = readlink_handler;
    // ops->mknod
    ops->symlink = symlink_handler;
    // ops->rename
    ops->rename = rename_handler;
    // ops->link
    ops->flush = flush_handler;
    ops->release = release_handler;
+4 −0
Original line number Diff line number Diff line
@@ -86,3 +86,7 @@ def test_read(gkfs_daemon, fuse_client):
    sh.ln("-s", str(file), "link")
    assert sh.ls(str(dir)) == "link\n"
    assert sh.cat("link") == "baum\n"

    # renaming
    sh.mv("link", "../lonk")
    assert sh.ls("..") == "dir  file  lonk\n"