Loading include/client/path.hpp +2 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ unsigned int match_components(const std::string& path, unsigned int& path_compon bool resolve(const std::string& path, std::string& resolved, bool resolve_last_link = true); std::string normalize(const std::string& path); std::string get_sys_cwd(); void set_sys_cwd(const std::string& path); Loading include/client/preload_context.hpp +7 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ struct FsConfig { }; enum class RelativizeStatus { ok, internal, external, fd_unknown, Loading Loading @@ -123,6 +124,12 @@ public: void local_host_id(uint64_t id); bool is_gkfs_path(std::string& path); RelativizeStatus normalize_path(int dirfd, const char* raw_path, std::string& normalized_path); RelativizeStatus normalize_path(const char* raw_path, std::string& normalized_path); RelativizeStatus relativize_fd_path(int dirfd, const char* raw_path, std::string& relative_path, Loading src/client/hooks.cpp +32 −10 Original line number Diff line number Diff line Loading @@ -43,28 +43,50 @@ namespace hook { int hook_openat(int dirfd, const char* cpath, int flags, mode_t mode) { LOG(DEBUG, "{}() called with fd: {}, path: \"{}\", flags: {}, mode: {}", LOG(INFO, "{}() called with fd: {}, path: \"{}\", flags: {}, mode: {}", __func__, dirfd, cpath, flags, mode); std::string resolved; auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved); switch (rstatus) { std::string normalized_path{}; auto status = CTX->normalize_path(dirfd, cpath, normalized_path); switch (status) { case gkfs::preload::RelativizeStatus::fd_unknown: return syscall_no_intercept(SYS_openat, dirfd, cpath, flags, mode); case gkfs::preload::RelativizeStatus::external: return syscall_no_intercept(SYS_openat, dirfd, resolved.c_str(), flags, mode); case gkfs::preload::RelativizeStatus::fd_not_a_dir: return -ENOTDIR; case gkfs::preload::RelativizeStatus::internal: return with_errno(gkfs::syscall::gkfs_open(resolved, mode, flags)); case gkfs::preload::RelativizeStatus::ok: if (CTX->is_gkfs_path(normalized_path)) return with_errno(gkfs::syscall::gkfs_open(normalized_path, mode, flags)); else return syscall_no_intercept(SYS_openat, dirfd, normalized_path.c_str(), flags, mode); default: LOG(ERROR, "{}() relativize status unknown: {}", __func__); return -EINVAL; } // // // // std::string resolved; // auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved); // switch (rstatus) { // case gkfs::preload::RelativizeStatus::fd_unknown: // return syscall_no_intercept(SYS_openat, dirfd, cpath, flags, mode); // // case gkfs::preload::RelativizeStatus::external: // return syscall_no_intercept(SYS_openat, dirfd, resolved.c_str(), flags, mode); // // case gkfs::preload::RelativizeStatus::fd_not_a_dir: // return -ENOTDIR; // // case gkfs::preload::RelativizeStatus::internal: // return with_errno(gkfs::syscall::gkfs_open(resolved, mode, flags)); // // default: // LOG(ERROR, "{}() relativize status unknown: {}", __func__); // return -EINVAL; // } } int hook_close(int fd) { Loading src/client/path.cpp +55 −1 Original line number Diff line number Diff line Loading @@ -78,6 +78,60 @@ unsigned int match_components(const string& path, unsigned int& path_components, return matched; } /** * Normalize a given path with `.` and `..` components. This will not resolve symlinks * @param path * @return normalized path */ string normalize(const string& path) { string normalized{}; // final normalized path normalized.reserve(path.size()); string::size_type comp_size = 0; // size of current component string::size_type start = 0; // start index of curr component string::size_type end = 0; // end index of curr component (last processed Path Separator "separator") stack<string::size_type> slash_idx{}; slash_idx.push(0); // index of all slashes in resolved path (used for rollback due to `..`) while (++end < path.size()) { start = end; // Skip sequence of multiple path-separators. while (start < path.size() && path[start] == path::separator) { start++; } // Find next component end = path.find_first_of(path::separator, start); if (end == string::npos) { end = path.size(); } comp_size = end - start; // component is empty (this must be the last component) if (comp_size == 0) { break; } // component is '.', we skip it if (comp_size == 1 && path.at(start) == '.') { continue; } // component is '..' we need to rollback normalized path if (comp_size == 2 && path.at(start) == '.' && path.at(start + 1) == '.') { if (!normalized.empty()) { normalized.erase(slash_idx.top()); slash_idx.pop(); } continue; } // add `/<component>` to the normalized path normalized.push_back(path::separator); slash_idx.push(normalized.size() - 1); normalized.append(path, start, comp_size); } LOG(INFO, "path: '{}', normalized: '{}'", path, normalized); return normalized; } /** Resolve path to its canonical representation * * Populate `resolved` with the canonical representation of `path`. Loading Loading @@ -126,7 +180,7 @@ bool resolve(const string& path, string& resolved, bool resolve_last_link) { } // Find next component end = path.find(path::separator, start); end = path.find_first_of(path::separator, start); if (end == string::npos) { end = path.size(); } Loading src/client/preload_context.cpp +66 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,72 @@ void PreloadContext::local_host_id(uint64_t id) { local_host_id_ = id; } bool PreloadContext::is_gkfs_path(std::string& path) { return path.rfind(mountdir_, 0) != std::string::npos; } RelativizeStatus PreloadContext::normalize_path(int dirfd, const char* raw_path, std::string& normalized_path) { // TODO when LEAF is available: return concated path and throw Status instead. // Relativize path should be called only after the library constructor has been executed assert(interception_enabled_); // If we run the constructor we also already setup the mountdir assert(!mountdir_.empty()); // We assume raw path is valid assert(raw_path != nullptr); std::string path{}; if (raw_path[0] != gkfs::path::separator) { // path is relative if (dirfd == AT_FDCWD) { // path is relative to cwd path = gkfs::path::prepend_path(cwd_, raw_path); } else { if (!ofm_->exist(dirfd)) { return RelativizeStatus::fd_unknown; } // path is relative to fd auto dir = ofm_->get_dir(dirfd); if (dir == nullptr) { return RelativizeStatus::fd_not_a_dir; } path = mountdir_; path.append(dir->path()); path.push_back(gkfs::path::separator); path.append(raw_path); } } else { path = raw_path; } normalized_path = gkfs::path::normalize(path); return RelativizeStatus::ok; } RelativizeStatus PreloadContext::normalize_path(const char* raw_path, std::string& normalized_path) { // TODO when LEAF is available: return concated path and throw Status instead. // Relativize path should be called only after the library constructor has been executed assert(interception_enabled_); // If we run the constructor we also already setup the mountdir assert(!mountdir_.empty()); // We assume raw path is valid assert(raw_path != nullptr); std::string path; if (raw_path[0] != gkfs::path::separator) { /* Path is not absolute, we need to prepend CWD; * First reserve enough space to minimize memory copy */ path = gkfs::path::prepend_path(cwd_, raw_path); } else { path = raw_path; } normalized_path = gkfs::path::normalize(path); return RelativizeStatus::ok; } RelativizeStatus PreloadContext::relativize_fd_path(int dirfd, const char* raw_path, std::string& relative_path, Loading Loading
include/client/path.hpp +2 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ unsigned int match_components(const std::string& path, unsigned int& path_compon bool resolve(const std::string& path, std::string& resolved, bool resolve_last_link = true); std::string normalize(const std::string& path); std::string get_sys_cwd(); void set_sys_cwd(const std::string& path); Loading
include/client/preload_context.hpp +7 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ struct FsConfig { }; enum class RelativizeStatus { ok, internal, external, fd_unknown, Loading Loading @@ -123,6 +124,12 @@ public: void local_host_id(uint64_t id); bool is_gkfs_path(std::string& path); RelativizeStatus normalize_path(int dirfd, const char* raw_path, std::string& normalized_path); RelativizeStatus normalize_path(const char* raw_path, std::string& normalized_path); RelativizeStatus relativize_fd_path(int dirfd, const char* raw_path, std::string& relative_path, Loading
src/client/hooks.cpp +32 −10 Original line number Diff line number Diff line Loading @@ -43,28 +43,50 @@ namespace hook { int hook_openat(int dirfd, const char* cpath, int flags, mode_t mode) { LOG(DEBUG, "{}() called with fd: {}, path: \"{}\", flags: {}, mode: {}", LOG(INFO, "{}() called with fd: {}, path: \"{}\", flags: {}, mode: {}", __func__, dirfd, cpath, flags, mode); std::string resolved; auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved); switch (rstatus) { std::string normalized_path{}; auto status = CTX->normalize_path(dirfd, cpath, normalized_path); switch (status) { case gkfs::preload::RelativizeStatus::fd_unknown: return syscall_no_intercept(SYS_openat, dirfd, cpath, flags, mode); case gkfs::preload::RelativizeStatus::external: return syscall_no_intercept(SYS_openat, dirfd, resolved.c_str(), flags, mode); case gkfs::preload::RelativizeStatus::fd_not_a_dir: return -ENOTDIR; case gkfs::preload::RelativizeStatus::internal: return with_errno(gkfs::syscall::gkfs_open(resolved, mode, flags)); case gkfs::preload::RelativizeStatus::ok: if (CTX->is_gkfs_path(normalized_path)) return with_errno(gkfs::syscall::gkfs_open(normalized_path, mode, flags)); else return syscall_no_intercept(SYS_openat, dirfd, normalized_path.c_str(), flags, mode); default: LOG(ERROR, "{}() relativize status unknown: {}", __func__); return -EINVAL; } // // // // std::string resolved; // auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved); // switch (rstatus) { // case gkfs::preload::RelativizeStatus::fd_unknown: // return syscall_no_intercept(SYS_openat, dirfd, cpath, flags, mode); // // case gkfs::preload::RelativizeStatus::external: // return syscall_no_intercept(SYS_openat, dirfd, resolved.c_str(), flags, mode); // // case gkfs::preload::RelativizeStatus::fd_not_a_dir: // return -ENOTDIR; // // case gkfs::preload::RelativizeStatus::internal: // return with_errno(gkfs::syscall::gkfs_open(resolved, mode, flags)); // // default: // LOG(ERROR, "{}() relativize status unknown: {}", __func__); // return -EINVAL; // } } int hook_close(int fd) { Loading
src/client/path.cpp +55 −1 Original line number Diff line number Diff line Loading @@ -78,6 +78,60 @@ unsigned int match_components(const string& path, unsigned int& path_components, return matched; } /** * Normalize a given path with `.` and `..` components. This will not resolve symlinks * @param path * @return normalized path */ string normalize(const string& path) { string normalized{}; // final normalized path normalized.reserve(path.size()); string::size_type comp_size = 0; // size of current component string::size_type start = 0; // start index of curr component string::size_type end = 0; // end index of curr component (last processed Path Separator "separator") stack<string::size_type> slash_idx{}; slash_idx.push(0); // index of all slashes in resolved path (used for rollback due to `..`) while (++end < path.size()) { start = end; // Skip sequence of multiple path-separators. while (start < path.size() && path[start] == path::separator) { start++; } // Find next component end = path.find_first_of(path::separator, start); if (end == string::npos) { end = path.size(); } comp_size = end - start; // component is empty (this must be the last component) if (comp_size == 0) { break; } // component is '.', we skip it if (comp_size == 1 && path.at(start) == '.') { continue; } // component is '..' we need to rollback normalized path if (comp_size == 2 && path.at(start) == '.' && path.at(start + 1) == '.') { if (!normalized.empty()) { normalized.erase(slash_idx.top()); slash_idx.pop(); } continue; } // add `/<component>` to the normalized path normalized.push_back(path::separator); slash_idx.push(normalized.size() - 1); normalized.append(path, start, comp_size); } LOG(INFO, "path: '{}', normalized: '{}'", path, normalized); return normalized; } /** Resolve path to its canonical representation * * Populate `resolved` with the canonical representation of `path`. Loading Loading @@ -126,7 +180,7 @@ bool resolve(const string& path, string& resolved, bool resolve_last_link) { } // Find next component end = path.find(path::separator, start); end = path.find_first_of(path::separator, start); if (end == string::npos) { end = path.size(); } Loading
src/client/preload_context.cpp +66 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,72 @@ void PreloadContext::local_host_id(uint64_t id) { local_host_id_ = id; } bool PreloadContext::is_gkfs_path(std::string& path) { return path.rfind(mountdir_, 0) != std::string::npos; } RelativizeStatus PreloadContext::normalize_path(int dirfd, const char* raw_path, std::string& normalized_path) { // TODO when LEAF is available: return concated path and throw Status instead. // Relativize path should be called only after the library constructor has been executed assert(interception_enabled_); // If we run the constructor we also already setup the mountdir assert(!mountdir_.empty()); // We assume raw path is valid assert(raw_path != nullptr); std::string path{}; if (raw_path[0] != gkfs::path::separator) { // path is relative if (dirfd == AT_FDCWD) { // path is relative to cwd path = gkfs::path::prepend_path(cwd_, raw_path); } else { if (!ofm_->exist(dirfd)) { return RelativizeStatus::fd_unknown; } // path is relative to fd auto dir = ofm_->get_dir(dirfd); if (dir == nullptr) { return RelativizeStatus::fd_not_a_dir; } path = mountdir_; path.append(dir->path()); path.push_back(gkfs::path::separator); path.append(raw_path); } } else { path = raw_path; } normalized_path = gkfs::path::normalize(path); return RelativizeStatus::ok; } RelativizeStatus PreloadContext::normalize_path(const char* raw_path, std::string& normalized_path) { // TODO when LEAF is available: return concated path and throw Status instead. // Relativize path should be called only after the library constructor has been executed assert(interception_enabled_); // If we run the constructor we also already setup the mountdir assert(!mountdir_.empty()); // We assume raw path is valid assert(raw_path != nullptr); std::string path; if (raw_path[0] != gkfs::path::separator) { /* Path is not absolute, we need to prepend CWD; * First reserve enough space to minimize memory copy */ path = gkfs::path::prepend_path(cwd_, raw_path); } else { path = raw_path; } normalized_path = gkfs::path::normalize(path); return RelativizeStatus::ok; } RelativizeStatus PreloadContext::relativize_fd_path(int dirfd, const char* raw_path, std::string& relative_path, Loading