diff options
-rw-r--r-- | src/operations.cc | 68 | ||||
-rw-r--r-- | src/posix_extras.cc | 26 | ||||
-rw-r--r-- | src/posix_extras.h | 2 |
3 files changed, 93 insertions, 3 deletions
diff --git a/src/operations.cc b/src/operations.cc index 86cd880..a69b591 100644 --- a/src/operations.cc +++ b/src/operations.cc @@ -44,6 +44,10 @@ namespace { // Pointer to the directory underlying the mount point. File* root_; +File* FileInfoFile(fuse_file_info* const file_info) { + return reinterpret_cast<File*>(file_info->fh); +} + Directory* FileInfoDirectory(fuse_file_info* const file_info) { return reinterpret_cast<Directory*>(file_info->fh); } @@ -100,6 +104,65 @@ int Getattr(const char* const path, struct stat* output) noexcept { } } +int Open(const char* const path, fuse_file_info* const file_info) { + LOG(INFO) << "open(" << path << ")"; + + std::unique_ptr<File> file; + + try { + file.reset(new File( + strcmp(path, "/") == 0 + ? + // They're asking to open the mount point. + *root_ + : + // Trim the leading slash so OpenAt will treat it relative to root_. + root_->OpenAt(path + 1, file_info->flags))); + } catch (const std::bad_alloc&) { + return -ENOMEM; + } catch (const IoError& e) { + return -e.number(); + } + + static_assert(sizeof(file_info->fh) == sizeof(uintptr_t), + "FUSE file handles are a different size than pointers"); + file_info->fh = reinterpret_cast<uintptr_t>(file.release()); + return 0; +} + +int Create(const char* const path, const mode_t mode, + fuse_file_info* const file_info) { + LOG(INFO) << "create(" << path << ")"; + + if (strcmp(path, "/") == 0) { + // They're asking to create the mount point. Huh? + return -EEXIST; + } + + std::unique_ptr<File> file; + + try { + // Trim the leading slash so OpenAt will treat it relative to root_. + file.reset(new File(root_->OpenAt(path + 1, file_info->flags, mode))); + } catch (const std::bad_alloc&) { + return -ENOMEM; + } catch (const IoError& e) { + return -e.number(); + } + + static_assert(sizeof(file_info->fh) == sizeof(uintptr_t), + "FUSE file handles are a different size than pointers"); + file_info->fh = reinterpret_cast<uintptr_t>(file.release()); + return 0; +} + +int Release(const char*, fuse_file_info* const file_info) { + LOG(INFO) << "release"; + File* const file = FileInfoFile(file_info); + delete file; + return 0; +} + int Opendir(const char* const path, fuse_file_info* const file_info) { LOG(INFO) << "opendir(" << path << ")"; @@ -179,6 +242,11 @@ fuse_operations FuseOperations(File* const root) { result.destroy = &Destroy; result.getattr = &Getattr; + + result.open = &Open; + result.create = &Create; + result.release = &Release; + result.opendir = &Opendir; result.readdir = &Readdir; result.releasedir = &Releasedir; diff --git a/src/posix_extras.cc b/src/posix_extras.cc index 0acae13..07b459e 100644 --- a/src/posix_extras.cc +++ b/src/posix_extras.cc @@ -58,6 +58,14 @@ File::File(const char* const path, const int flags) : path_(path) { VLOG(1) << "opening file descriptor " << fd_; } +File::File(const char* const path, const int flags, const mode_t mode) + : path_(path) { + if ((fd_ = open(path, flags, mode)) == -1) { + throw IoError(); + } + VLOG(1) << "opening file descriptor " << fd_; +} + File::File(const File& other) : path_(other.path_), fd_(other.Duplicate()) { VLOG(1) << "opening file descriptor " << fd_; } @@ -103,6 +111,20 @@ File File::OpenAt(const char* const path, const int flags) const { return result; } +File File::OpenAt(const char* const path, const int flags, + const mode_t mode) const { + if (path[0] == '/') { + throw std::invalid_argument("absolute path"); + } + + File result; + if ((result.fd_ = openat(fd_, path, flags, mode)) == -1) { + throw IoError(); + } + result.path_ = path_ + "/" + path; + return result; +} + int File::Duplicate() const { int result; if ((result = dup(fd_)) == -1) { @@ -136,9 +158,7 @@ long Directory::offset() const { return result; } -void Directory::Seek(const long offset) noexcept { - seekdir(stream_, offset); -} +void Directory::Seek(const long offset) noexcept { seekdir(stream_, offset); } std::experimental::optional<dirent> Directory::ReadOne() { dirent* result; diff --git a/src/posix_extras.h b/src/posix_extras.h index 9498249..9aea47d 100644 --- a/src/posix_extras.h +++ b/src/posix_extras.h @@ -72,6 +72,7 @@ class Directory { class File { public: File(const char* path, int flags); + File(const char* path, int flags, mode_t mode); File(const File&); File(File&& other) = default; virtual ~File() noexcept; @@ -88,6 +89,7 @@ class File { // Calls openat(2) on the path relative to the file descriptor. The path must // indeed be relative (i.e., it must not start with '/'). File OpenAt(const char* path, int flags) const; + File OpenAt(const char* path, int flags, mode_t mode) const; private: File() {} |