aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Benjamin Barenblat <bbaren@mit.edu>2016-02-21 22:31:29 -0500
committerGravatar Benjamin Barenblat <bbaren@mit.edu>2016-02-21 22:48:53 -0500
commit604841c6c81608a7dfcfe05ab75fa0c7ede2a890 (patch)
treefb78d435722ca6fda1c9df3353b0b82e99e3b013
parent55e3bc99c51da7b4ec61fc6cf09177dc439cd541 (diff)
Implement symlink/readlink
-rw-r--r--src/operations.cc16
-rw-r--r--src/posix_extras.cc18
-rw-r--r--src/posix_extras.h10
3 files changed, 44 insertions, 0 deletions
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<std::uint8_t> File::Read(off_t offset, size_t bytes) const {
return result;
}
+std::string File::ReadLinkAt(const char* const path) const {
+ ValidatePath(path);
+ std::vector<char> result(64, '\0');
+ size_t bytes_read;
+
+ while ((bytes_read = static_cast<size_t>(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<std::uint8_t> 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;