Commit 91f7740e authored by sevenuz's avatar sevenuz Committed by Julius Athenstaedt
Browse files

first draft for gkfs

parent b8888a57
Loading
Loading
Loading
Loading
+171 −7
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@
#ifndef GKFS_CLIENT_FUSE_CONTEXT_HPP
#define GKFS_CLIENT_FUSE_CONTEXT_HPP

#include "fuse_log.h"
#include <utility>
extern "C" {
#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
#include <fuse3/fuse_lowlevel.h>
@@ -81,13 +83,26 @@ struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <filesystem>
#include <unordered_map>
#include <string>
#include <mutex>

#ifdef __FreeBSD__
#include <sys/socket.h>
#include <sys/un.h>
#endif

// GekkoFS Project Headers
#include <common/path_util.hpp>
#include <client/hooks.hpp>
#include <client/logging.hpp> // Assumed to provide LOG and CTX
#include <client/open_dir.hpp>
#include <client/open_file_map.hpp>
#include <client/preload.hpp>
#include <client/preload_context.hpp>
#include <client/user_functions.hpp>
#include <client/gkfs_libc.hpp>

static inline int
do_fallocate(int fd, int mode, off_t offset, off_t length) {
@@ -119,6 +134,142 @@ do_fallocate(int fd, int mode, off_t offset, off_t length) {
#endif // HAVE_FALLOCATE
}

// all from the gkfs_libc
enum class PathStatus { External, Internal, Error };

/**
 * @brief Resolves a path in the context of GekkoFS.
 * (Details as in original comment)
 */
static inline PathStatus
resolve_gkfs_path(int dirfd, const char* path, std::string& resolved,
                  int flags = 0, bool resolve_last_link = true) {
    const auto status = CTX->relativize_fd_path(dirfd, path, resolved, flags,
                                                resolve_last_link);
    switch(status) {
        case gkfs::preload::RelativizeStatus::internal:
            return PathStatus::Internal;
        case gkfs::preload::RelativizeStatus::fd_not_a_dir:
            errno = ENOTDIR;
            return PathStatus::Error;
        case gkfs::preload::RelativizeStatus::fd_unknown:
            errno = EBADF;
            return PathStatus::Error;
        default: // Assuming other statuses mean external or not applicable
            return PathStatus::External;
    }
}

#define DEBUG_INFO(...)                                                        \
    do {                                                                       \
        if(CTX->interception_enabled())                                        \
            LOG(DEBUG, __VA_ARGS__);                                           \
    } while(0)

#define GKFS_PATH_OPERATION(name, dirfd, path, ...)                            \
    if(CTX->interception_enabled()) {                                          \
        std::string resolved;                                                  \
        switch(resolve_gkfs_path(dirfd, path, resolved)) {                     \
            case PathStatus::Internal:                                         \
                fuse_log(FUSE_LOG_DEBUG, "[GKFS] {}(path='{}')\n", #name,      \
                         resolved.c_str());                                    \
                return gkfs::syscall::gkfs_##name(resolved, __VA_ARGS__);      \
            case PathStatus::Error:                                            \
                return -1;                                                     \
            default: /* External */                                            \
                break;                                                         \
        }                                                                      \
    }

#define GKFS_PATH_OPERATION1(name, dirfd, path)                                \
    if(CTX->interception_enabled()) {                                          \
        std::string resolved;                                                  \
        switch(resolve_gkfs_path(dirfd, path, resolved)) {                     \
            case PathStatus::Internal:                                         \
                fuse_log(FUSE_LOG_DEBUG, "[GKFS] {}(path='{}')\n", #name,      \
                         resolved.c_str());                                    \
                gkfs::syscall::gkfs_##name(resolved);                          \
            case PathStatus::Error:                                            \
                fuse_reply_err(req, -1);                                       \
            default: /* External */                                            \
                fuse_reply_err(req, -1);                                       \
        }                                                                      \
    }

struct GkfsDir { // Hypothetical structure that might be used if DIR is cast
    int fd;
    long int tell_pos; // for telldir/seekdir
    char* path;
    // other members libc DIR might have
};

static inline std::pair<int, std::string>
lol_path(int dfd, const char* path, int flags) {
    std::string resolved = "";
    int err = 0;
    if(CTX->interception_enabled()) {
        // AT_SYMLINK_NOFOLLOW means lstat behavior, otherwise stat behavior.
        bool follow_link = !(flags & AT_SYMLINK_NOFOLLOW);
        // Path resolution needs to know if it's for lstat or stat context for
        // the final component. resolve_gkfs_path's `resolve_last_link`
        // parameter handles this.
        switch(resolve_gkfs_path(dfd, path, resolved, flags, follow_link)) {
            case PathStatus::Internal:
                break;
            case PathStatus::Error:
                err = -1;
                break;
            default: // External
                break;
        }
    }
    return std::make_pair(err, resolved);
}

static inline int
lol_fstatat(int dfd, const char* path, struct stat* buf, int flags) {

    if(CTX->interception_enabled()) {
        std::string resolved;
        // AT_SYMLINK_NOFOLLOW means lstat behavior, otherwise stat behavior.
        bool follow_link = !(flags & AT_SYMLINK_NOFOLLOW);
        // Path resolution needs to know if it's for lstat or stat context for
        // the final component. resolve_gkfs_path's `resolve_last_link`
        // parameter handles this.
        switch(resolve_gkfs_path(dfd, path, resolved, flags, follow_link)) {
            case PathStatus::Internal:
                return gkfs::syscall::gkfs_stat(resolved, buf, follow_link);
            case PathStatus::Error:
                return -1; // errno set
            default:       // External
                break;
        }
    }
    return -1;
}

static inline int
lol_openat(int dfd, const char* path, mode_t mode, int flags) {
    if(CTX->interception_enabled()) {
        std::string resolved;
        // AT_SYMLINK_NOFOLLOW means lstat behavior, otherwise stat behavior.
        bool follow_link = !(flags & AT_SYMLINK_NOFOLLOW);
        // Path resolution needs to know if it's for lstat or stat context for
        // the final component. resolve_gkfs_path's `resolve_last_link`
        // parameter handles this.
        switch(resolve_gkfs_path(dfd, path, resolved, flags, follow_link)) {
            case PathStatus::Internal:
                fuse_log(FUSE_LOG_DEBUG, "lol_openat internal\n");
                return gkfs::syscall::gkfs_open(resolved, mode, follow_link);
            case PathStatus::Error:
                return -1; // errno set
            default:       // External
                break;
        }
    }
    return -1;
}

/*
 * Creates files on the underlying file system in response to a FUSE_MKNOD
 * operation
@@ -126,18 +277,28 @@ do_fallocate(int fd, int mode, off_t offset, off_t length) {
static inline int
mknod_wrapper(int dirfd, const char* path, const char* link, int mode,
              dev_t rdev) {
    int res;
    fuse_log(FUSE_LOG_DEBUG, "mknod_wrapper \n");
    int res = -1;

    if(S_ISREG(mode)) {
        res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode);
        res = lol_openat(dirfd, path, mode, O_CREAT | O_EXCL | O_WRONLY);
        fuse_log(FUSE_LOG_DEBUG, "lol_openat internal %s\n", res);
        if(res >= 0)
            res = close(res);
            res = gkfs::syscall::gkfs_close(res);
    } else if(S_ISDIR(mode)) {
        res = mkdirat(dirfd, path, mode);
        GKFS_PATH_OPERATION(create, dirfd, path, mode | S_IFDIR)
        // res = gkfs::syscall::gkfs_create(resolved, mode | S_IFDIR);
        //  res = mkdirat(dirfd, path, mode);
    } else if(S_ISLNK(mode) && link != NULL) {
        res = symlinkat(link, dirfd, path);
        fuse_log(FUSE_LOG_ERR, "fifo in mknod_wrapper not supported\n");
        errno = ENOTSUP;
        return -1;
        // res = symlinkat(link, dirfd, path);
    } else if(S_ISFIFO(mode)) {
        res = mkfifoat(dirfd, path, mode);
        fuse_log(FUSE_LOG_ERR, "fifo in mknod_wrapper not supported\n");
        errno = ENOTSUP;
        return -1;
        // res = mkfifoat(dirfd, path, mode);
#ifdef __FreeBSD__
    } else if(S_ISSOCK(mode)) {
        struct sockaddr_un su;
@@ -164,7 +325,10 @@ mknod_wrapper(int dirfd, const char* path, const char* link, int mode,
        }
#endif
    } else {
        res = mknodat(dirfd, path, mode, rdev);
        fuse_log(FUSE_LOG_ERR, "mknodat in mknod_wrapper not supported\n");
        errno = ENOTSUP;
        return -1;
        // res = mknodat(dirfd, path, mode, rdev);
    }

    return res;
+2 −0
Original line number Diff line number Diff line
@@ -118,8 +118,10 @@ target_sources(fuse_client
    )

target_link_libraries(fuse_client
    PRIVATE gkfs_common metadata distributor env_util arithmetic path_util rpc_utils
    ${FUSE3_LIBRARIES}
    gkfs_user_lib
    gkfs_libc_intercept
    )

target_include_directories(fuse_client
+320 −1079

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -664,7 +664,7 @@ forward_get_metadentry_size(const std::string& path, const int copy) {
/**
 * Send an RPC request to receive all entries of a directory.
 * @param open_dir
 * @return error code
 * @return error code, OpenDir
 */
pair<int, shared_ptr<gkfs::filemap::OpenDir>>
forward_get_dirents(const string& path) {