From: Darrick J. Wong <djwong@xxxxxxxxxx> Allow creation of O_TMPFILE files now that we know how to use the unlinked list. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- misc/fuse4fs.c | 93 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 26 deletions(-) diff --git a/misc/fuse4fs.c b/misc/fuse4fs.c index 1d1797a483a139..3f88e98a20c203 100644 --- a/misc/fuse4fs.c +++ b/misc/fuse4fs.c @@ -897,22 +897,25 @@ static inline int fuse4fs_want_check_owner(struct fuse4fs *ff, /* Test for append permission */ #define A_OK 16 +/* Test for linked file */ +#define L_OK 32 static int fuse4fs_iflags_access(struct fuse4fs *ff, ext2_ino_t ino, const struct ext2_inode *inode, int mask) { - EXT2FS_BUILD_BUG_ON((A_OK & (R_OK | W_OK | X_OK | F_OK)) != 0); + EXT2FS_BUILD_BUG_ON(((A_OK | L_OK) & (R_OK | W_OK | X_OK | F_OK)) != 0); /* no writing or metadata changes to read-only or broken fs */ if ((mask & (W_OK | A_OK)) && !fuse4fs_is_writeable(ff)) return -EROFS; - dbg_printf(ff, "access ino=%d mask=e%s%s%s%s iflags=0x%x\n", + dbg_printf(ff, "access ino=%d mask=e%s%s%s%s%s iflags=0x%x\n", ino, (mask & R_OK ? "r" : ""), (mask & W_OK ? "w" : ""), (mask & X_OK ? "x" : ""), (mask & A_OK ? "a" : ""), + (mask & L_OK ? "l" : ""), inode->i_flags); /* is immutable? */ @@ -945,21 +948,31 @@ static int fuse4fs_inum_access(struct fuse4fs *ff, const struct fuse_ctx *ctxt, return translate_error(fs, ino, err); perms = inode.i_mode & 0777; - dbg_printf(ff, "access ino=%d mask=e%s%s%s%s perms=0%o iflags=0x%x " + dbg_printf(ff, "access ino=%d mask=e%s%s%s%s%s perms=0%o iflags=0x%x " "fuid=%d fgid=%d uid=%d gid=%d\n", ino, (mask & R_OK ? "r" : ""), (mask & W_OK ? "w" : ""), (mask & X_OK ? "x" : ""), (mask & A_OK ? "a" : ""), + (mask & L_OK ? "l" : ""), perms, inode.i_flags, inode_uid(inode), inode_gid(inode), ctxt->uid, ctxt->gid); - /* linked files cannot be on the unlinked list or deleted */ - if (inode.i_dtime != 0) { - dbg_printf(ff, "%s: unlinked ino=%d dtime=0x%x\n", - __func__, ino, inode.i_dtime); - return -ENOENT; + if (mask & L_OK) { + /* linked files cannot be on the unlinked list or deleted */ + if (inode.i_dtime != 0) { + dbg_printf(ff, "%s: unlinked ino=%d dtime=0x%x\n", + __func__, ino, inode.i_dtime); + return -ENOENT; + } + } else { + /* unlinked files cannot be deleted */ + if (inode.i_dtime >= fs->super->s_inodes_count) { + dbg_printf(ff, "%s: deleted ino=%d dtime=0x%x\n", + __func__, ino, inode.i_dtime); + return -ENOENT; + } } /* existence check */ @@ -3123,7 +3136,7 @@ static void detect_linux_executable_open(int kernel_flags, int *access_check, #endif /* __linux__ */ static int fuse4fs_open_file(struct fuse4fs *ff, const struct fuse_ctx *ctxt, - ext2_ino_t ino, + ext2_ino_t ino, bool linked, struct fuse_file_info *fp) { ext2_filsys fs = ff->fs; @@ -3153,6 +3166,9 @@ static int fuse4fs_open_file(struct fuse4fs *ff, const struct fuse_ctx *ctxt, break; } + if (linked) + check |= L_OK; + /* * If the caller wants to truncate the file, we need to ask for full * write access even if the caller claims to be appending. @@ -3219,7 +3235,7 @@ static void op_open(fuse_req_t req, fuse_ino_t fino, struct fuse_file_info *fp) dbg_printf(ff, "%s: ino=%d\n", __func__, ino); fuse4fs_start(ff); - ret = fuse4fs_open_file(ff, ctxt, ino, fp); + ret = fuse4fs_open_file(ff, ctxt, ino, true, fp); fuse4fs_finish(ff, ret); if (ret) @@ -4128,22 +4144,28 @@ static void op_create(fuse_req_t req, fuse_ino_t fino, const char *name, goto out2; } - dbg_printf(ff, "%s: creating dir=%d name='%s' child=%d\n", - __func__, parent, name, child); - err = ext2fs_link(fs, parent, name, child, - filetype | EXT2FS_LINK_EXPAND); - if (err) { - ret = translate_error(fs, parent, err); - goto out2; + if (name) { + dbg_printf(ff, "%s: creating dir=%d name='%s' child=%d\n", + __func__, parent, name, child); + + err = ext2fs_link(fs, parent, name, child, + filetype | EXT2FS_LINK_EXPAND); + if (err) { + ret = translate_error(fs, parent, err); + goto out2; + } + + ret = update_mtime(fs, parent, NULL); + if (ret) + goto out2; + } else { + dbg_printf(ff, "%s: creating dir=%d tempfile=%d\n", + __func__, parent, child); } - ret = update_mtime(fs, parent, NULL); - if (ret) - goto out2; - memset(&inode, 0, sizeof(inode)); inode.i_mode = mode; - inode.i_links_count = 1; + inode.i_links_count = name ? 1 : 0; fuse4fs_set_extra_isize(ff, child, &inode); fuse4fs_set_uid(&inode, ctxt->uid); fuse4fs_set_gid(&inode, gid); @@ -4161,6 +4183,12 @@ static void op_create(fuse_req_t req, fuse_ino_t fino, const char *name, ext2fs_extent_free(handle); } + if (!name) { + ret = fuse4fs_add_to_orphans(ff, child, &inode); + if (ret) + goto out2; + } + err = ext2fs_write_new_inode(fs, child, EXT2_INODE(&inode)); if (err) { ret = translate_error(fs, child, err); @@ -4182,13 +4210,15 @@ static void op_create(fuse_req_t req, fuse_ino_t fino, const char *name, goto out2; fp->flags &= ~O_TRUNC; - ret = fuse4fs_open_file(ff, ctxt, child, fp); + ret = fuse4fs_open_file(ff, ctxt, child, name != NULL, fp); if (ret) goto out2; - ret = fuse4fs_dirsync_flush(ff, parent, NULL); - if (ret) - goto out2; + if (name) { + ret = fuse4fs_dirsync_flush(ff, parent, NULL); + if (ret) + goto out2; + } ret = fuse4fs_stat_inode(ff, child, NULL, &fstat); if (ret) @@ -4203,6 +4233,14 @@ static void op_create(fuse_req_t req, fuse_ino_t fino, const char *name, fuse_reply_create(req, &fstat.entry, fp); } +#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 17) +static void op_tmpfile(fuse_req_t req, fuse_ino_t fino, mode_t mode, + struct fuse_file_info *fp) +{ + op_create(req, fino, NULL, mode, fp); +} +#endif + enum fuse4fs_time_action { TA_NOW, /* set to current time */ TA_OMIT, /* do not set timestamp */ @@ -5161,6 +5199,9 @@ static struct fuse_lowlevel_ops fs_ops = { .fsyncdir = op_fsync, .access = op_access, .create = op_create, +#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 17) + .tmpfile = op_tmpfile, +#endif .bmap = op_bmap, #ifdef SUPERFLUOUS .lock = op_lock,