aboutsummaryrefslogtreecommitdiffstats
path: root/example/passthrough_hp.cc
diff options
context:
space:
mode:
authorHorst Birthelmer <hbirthelmer@ddn.com>2024-11-20 16:14:43 +0100
committerBernd Schubert <bernd.schubert@fastmail.fm>2024-11-27 13:38:56 +0100
commit4ec109d1c447bbf5be05854e32d8683bb1df5a80 (patch)
tree4283922b8aee6846ea111499285174232ed062b8 /example/passthrough_hp.cc
parent8b34ed03682bb7806a6083b05187c4fc5475a135 (diff)
downloadlibfuse-4ec109d1c447bbf5be05854e32d8683bb1df5a80.tar.gz
support FUSE_TMPFILE in the low level API
Note that name hashes and using paths as parameters makes it very hard to support anonymous files in the high level API. Known Issues: - tests have to bail out when O_TMPFILE is not supported. This will always be the case with high level passthrough implementations. - test_create_and_link_tmpfile has to be skipped due to unidentified problems with github runner
Diffstat (limited to 'example/passthrough_hp.cc')
-rw-r--r--example/passthrough_hp.cc81
1 files changed, 81 insertions, 0 deletions
diff --git a/example/passthrough_hp.cc b/example/passthrough_hp.cc
index c393f04..41904e5 100644
--- a/example/passthrough_hp.cc
+++ b/example/passthrough_hp.cc
@@ -914,6 +914,86 @@ static void sfs_create(fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_reply_create(req, &e, fi);
}
+static Inode *create_new_inode(int fd, fuse_entry_param *e)
+{
+ memset(e, 0, sizeof(*e));
+ e->attr_timeout = fs.timeout;
+ e->entry_timeout = fs.timeout;
+
+ auto res = fstatat(fd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+ if (res == -1) {
+ if (fs.debug)
+ cerr << "DEBUG: lookup(): fstatat failed" << endl;
+ return NULL;
+ }
+
+ SrcId id {e->attr.st_ino, e->attr.st_dev};
+ unique_lock<mutex> fs_lock {fs.mutex};
+ Inode* p_inode;
+ try {
+ p_inode = &fs.inodes[id];
+ } catch (std::bad_alloc&) {
+ return NULL;
+ }
+
+ e->ino = reinterpret_cast<fuse_ino_t>(p_inode);
+ e->generation = p_inode->generation;
+
+ lock_guard<mutex> g {p_inode->m};
+ p_inode->src_ino = e->attr.st_ino;
+ p_inode->src_dev = e->attr.st_dev;
+
+ p_inode->nlookup++;
+ if (fs.debug)
+ cerr << "DEBUG:" << __func__ << ":" << __LINE__ << " "
+ << "inode " << p_inode->src_ino
+ << " count " << p_inode->nlookup << endl;
+
+ p_inode->fd = fd;
+ fs_lock.unlock();
+
+ if (fs.debug)
+ cerr << "DEBUG: lookup(): created userspace inode " << e->attr.st_ino
+ << "; fd = " << p_inode->fd << endl;
+ return p_inode;
+}
+
+static void sfs_tmpfile(fuse_req_t req, fuse_ino_t parent,
+ mode_t mode, fuse_file_info *fi) {
+ Inode& parent_inode = get_inode(parent);
+
+ auto fd = openat(parent_inode.fd, ".",
+ (fi->flags | O_TMPFILE) & ~O_NOFOLLOW, mode);
+ if (fd == -1) {
+ auto err = errno;
+ if (err == ENFILE || err == EMFILE)
+ cerr << "ERROR: Reached maximum number of file descriptors." << endl;
+ fuse_reply_err(req, err);
+ return;
+ }
+
+ fi->fh = fd;
+ fuse_entry_param e;
+
+ Inode *inode = create_new_inode(dup(fd), &e);
+ if (inode == NULL) {
+ auto err = errno;
+ cerr << "ERROR: could not create new inode." << endl;
+ close(fd);
+ fuse_reply_err(req, err);
+ return;
+ }
+
+ lock_guard<mutex> g {inode->m};
+
+ sfs_create_open_flags(fi);
+
+ if (fs.passthrough)
+ do_passthrough_open(req, e.ino, fd, fi);
+
+ fuse_reply_create(req, &e, fi);
+}
+
static void sfs_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
fuse_file_info *fi) {
@@ -1237,6 +1317,7 @@ static void assign_operations(fuse_lowlevel_ops &sfs_oper) {
sfs_oper.releasedir = sfs_releasedir;
sfs_oper.fsyncdir = sfs_fsyncdir;
sfs_oper.create = sfs_create;
+ sfs_oper.tmpfile = sfs_tmpfile;
sfs_oper.open = sfs_open;
sfs_oper.release = sfs_release;
sfs_oper.flush = sfs_flush;