Loading include/client/fuse/fuse_client.hpp +171 −7 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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) { Loading Loading @@ -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 Loading @@ -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; Loading @@ -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; Loading src/client/CMakeLists.txt +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading src/client/fuse/fuse_client.cpp +320 −1079 File changed.Preview size limit exceeded, changes collapsed. Show changes src/client/rpc/forward_metadata.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading
include/client/fuse/fuse_client.hpp +171 −7 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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) { Loading Loading @@ -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 Loading @@ -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; Loading @@ -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; Loading
src/client/CMakeLists.txt +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
src/client/fuse/fuse_client.cpp +320 −1079 File changed.Preview size limit exceeded, changes collapsed. Show changes
src/client/rpc/forward_metadata.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -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) { Loading