From 604841c6c81608a7dfcfe05ab75fa0c7ede2a890 Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Sun, 21 Feb 2016 22:31:29 -0500 Subject: Implement symlink/readlink --- src/operations.cc | 16 ++++++++++++++++ src/posix_extras.cc | 18 ++++++++++++++++++ src/posix_extras.h | 10 ++++++++++ 3 files changed, 44 insertions(+) diff --git a/src/operations.cc b/src/operations.cc index e4e76b3..b1c568a 100644 --- a/src/operations.cc +++ b/src/operations.cc @@ -168,6 +168,19 @@ int Unlink(const char* c_path) { } } +int Symlink(const char* const target, const char* const source) { + root_->SymLinkAt(target, EncodePath(source).c_str()); + return 0; +} + +int Readlink(const char* const path, char* const output, + const size_t output_size) { + const std::string target = root_->ReadLinkAt(EncodePath(path).c_str()); + std::strncpy(output, target.c_str(), output_size); + output[output_size - 1] = '\0'; + return 0; +} + int Mkdir(const char* const c_path, const mode_t mode) { const std::string path(c_path); if (path == "/") { @@ -264,6 +277,9 @@ fuse_operations FuseOperations(File* const root) { result.release = CATCH_AND_RETURN_EXCEPTIONS(Release); result.unlink = CATCH_AND_RETURN_EXCEPTIONS(Unlink); + result.symlink = CATCH_AND_RETURN_EXCEPTIONS(Symlink); + result.readlink = CATCH_AND_RETURN_EXCEPTIONS(Readlink); + result.mkdir = CATCH_AND_RETURN_EXCEPTIONS(Mkdir); result.opendir = CATCH_AND_RETURN_EXCEPTIONS(Opendir); result.readdir = CATCH_AND_RETURN_EXCEPTIONS(Readdir); diff --git a/src/posix_extras.cc b/src/posix_extras.cc index e7705a7..11db247 100644 --- a/src/posix_extras.cc +++ b/src/posix_extras.cc @@ -125,6 +125,19 @@ std::vector File::Read(off_t offset, size_t bytes) const { return result; } +std::string File::ReadLinkAt(const char* const path) const { + ValidatePath(path); + std::vector result(64, '\0'); + size_t bytes_read; + + while ((bytes_read = static_cast(CheckSyscall(readlinkat( + fd_, path, result.data(), result.size())))) == result.size()) { + // We filled the entire buffer. There may be more data we missed. + result.resize(result.size() * 2); + } + return std::string(result.data(), result.data() + bytes_read); +} + void File::RenameAt(const char* old_path, const char* new_path) const { ValidatePath(old_path); ValidatePath(new_path); @@ -136,6 +149,11 @@ void File::RmDirAt(const char* const path) const { CheckSyscall(unlinkat(fd_, path, AT_REMOVEDIR)); } +void File::SymLinkAt(const char* const target, const char* const source) const { + ValidatePath(source); + CheckSyscall(symlinkat(target, fd_, source)); +} + void File::UnlinkAt(const char* const path) const { ValidatePath(path); CheckSyscall(unlinkat(fd_, path, 0)); diff --git a/src/posix_extras.h b/src/posix_extras.h index 2976016..889175e 100644 --- a/src/posix_extras.h +++ b/src/posix_extras.h @@ -93,6 +93,11 @@ class File { // fewer bytes are returned. std::vector Read(off_t, size_t) const; + // Reads the contents of a symbolic link. The path to the symbolic link is + // interpreted relative to the file descriptor and must indeed be relative + // (i.e., it must not start with '/'). + std::string ReadLinkAt(const char* path) const; + // Renames a file from old_path to new_path. Both paths are interpreted // relative to the file descriptor, and both must indeed be relative (i.e., // they must not start with '/'). @@ -102,6 +107,11 @@ class File { // path must indeed be relative (i.e., it must not start with '/'). void RmDirAt(const char* path) const; + // Creates a symlink at source pointing to target. target is unvalidated. + // source is interpreted as a path relative to the file descriptor and must + // indeed be relative (i.e., it must not start with '/'). + void SymLinkAt(const char* target, const char* source) const; + // Removes the file at the path relative to the file descriptor. The path // must indeed be relative (i.e., it must not start with '/'). void UnlinkAt(const char* path) const; -- cgit v1.2.3