aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/operations.cc68
-rw-r--r--src/posix_extras.cc26
-rw-r--r--src/posix_extras.h2
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() {}