From d5f16dbf317dd8287d2f7536d3b1c376113c040a Mon Sep 17 00:00:00 2001 From: Pavel Siska Date: Mon, 7 Oct 2024 02:01:24 +0200 Subject: [PATCH] appfs - Add symlink support in FUSE implementation - Updated `fuseGetAttr` to handle symlink attributes. - Added `readlinkCallback` to retrieve target of symbolic links. --- src/appFs/appFs.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/appFs/appFs.cpp b/src/appFs/appFs.cpp index 740cc9c..d6d7b77 100644 --- a/src/appFs/appFs.cpp +++ b/src/appFs/appFs.cpp @@ -41,6 +41,15 @@ static off_t getMaxFileSize(const std::shared_ptr& file) return static_cast(blockSizeMultiplier * blockSize); } +static void setSymlinkAttr(struct stat* stbuf) +{ + const mode_t symlinkMode = 0777; + stbuf->st_mode = S_IFLNK | symlinkMode; + stbuf->st_nlink = 1; + stbuf->st_size = BUFSIZ; + stbuf->st_mtime = time(nullptr); +} + static void setFileAttr(const std::shared_ptr& file, struct stat* stbuf) { stbuf->st_mode = S_IFREG; @@ -82,6 +91,11 @@ static int fuseGetAttr(const char* path, struct stat* stbuf, struct fuse_file_in const std::shared_ptr rootDirectory = getRootDirectory(); auto node = utils::getNodeFromPath(rootDirectory, path); + if (utils::isSymlink(node)) { + setSymlinkAttr(stbuf); + return 0; + } + if (utils::isFile(node)) { setFileAttr(std::dynamic_pointer_cast(node), stbuf); return 0; @@ -306,6 +320,34 @@ static int writeCallback( } } +static int readlinkCallback(const char* path, char* buffer, size_t size) +{ + auto node = utils::getNodeFromPath(getRootDirectory(), path); + + if (!utils::isSymlink(node)) { + return -ENOENT; + } + + const auto targetNode = std::dynamic_pointer_cast(node)->getTarget(); + if (targetNode == nullptr) { + return -ENOENT; + } + + const std::filesystem::path targetPath = targetNode->getFullPath(); + + const std::string relativeTargetPath + = std::filesystem::relative(targetPath, std::filesystem::path(path).parent_path()).string(); + + if (size < relativeTargetPath.size() + 1) { + return -ENAMETOOLONG; + } + + std::memcpy(buffer, relativeTargetPath.c_str(), relativeTargetPath.size()); + buffer[relativeTargetPath.size()] = '\0'; + + return 0; +} + static void setFuseOperations(struct fuse_operations* fuseOps) { fuseOps->getattr = getAttrCallback; @@ -314,6 +356,7 @@ static void setFuseOperations(struct fuse_operations* fuseOps) fuseOps->read = readCallback; fuseOps->write = writeCallback; fuseOps->release = releaseCallback; + fuseOps->readlink = readlinkCallback; } static void runFuseLoop(struct fuse* fuse)