From 24b35c3d97ffdbf0a1f8e8b4e94ed892343603a6 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 2 Jul 2009 12:26:36 +0000 Subject: * The context is extended with a 'umask' field. The umask is sent for mknod, mkdir and create requests by linux kernel version 2.6.31 or later, otherwise the umask is set to zero. Also introduce a new feature flag: FUSE_CAP_DONT_MASK. If the kernel supports this feature, then this flag will be set in conn->capable in the ->init() method. If the filesystem sets this flag in in conn->want, then the create modes will not be masked. * Add low level interfaces for lookup cache and attribute invalidation. This feature is available in linux kernels 2.6.31 or later. Patch by John Muir * Kernel interface version is now 7.12 --- lib/fuse.c | 15 ++++++--- lib/fuse_lowlevel.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++-- lib/fuse_session.c | 5 +++ lib/fuse_versionscript | 6 ++-- 4 files changed, 104 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/fuse.c b/lib/fuse.c index dad9a71..68cb603 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -1422,8 +1422,10 @@ int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, int err; if (fs->debug) - fprintf(stderr, "create flags: 0x%x %s\n", fi->flags, - path); + fprintf(stderr, + "create flags: 0x%x %s 0%o umask=0%03o\n", + fi->flags, path, mode, + fuse_get_context()->umask); err = fs->op.create(path, mode, fi); @@ -1572,8 +1574,9 @@ int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, fuse_get_context()->private_data = fs->user_data; if (fs->op.mknod) { if (fs->debug) - fprintf(stderr, "mknod %s 0%o 0x%llx\n", path, - mode, (unsigned long long) rdev); + fprintf(stderr, "mknod %s 0%o 0x%llx umask=0%03o\n", + path, mode, (unsigned long long) rdev, + fuse_get_context()->umask); return fs->op.mknod(path, mode, rdev); } else { @@ -1586,7 +1589,8 @@ int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode) fuse_get_context()->private_data = fs->user_data; if (fs->op.mkdir) { if (fs->debug) - fprintf(stderr, "mkdir %s 0%o\n", path, mode); + fprintf(stderr, "mkdir %s 0%o umask=0%03o\n", + path, mode, fuse_get_context()->umask); return fs->op.mkdir(path, mode); } else { @@ -1909,6 +1913,7 @@ static struct fuse *req_fuse_prepare(fuse_req_t req) c->ctx.uid = ctx->uid; c->ctx.gid = ctx->gid; c->ctx.pid = ctx->pid; + c->ctx.umask = ctx->umask; return c->ctx.fuse; } diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 89e8f2f..32b9db3 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -606,9 +606,15 @@ static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg; + char *name = PARAM(arg); + + if (req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; + else + name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE; if (req->f->op.mknod) - req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev); + req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev); else fuse_reply_err(req, ENOSYS); } @@ -617,6 +623,9 @@ static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg; + if (req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; + if (req->f->op.mkdir) req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); else @@ -678,15 +687,21 @@ static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_open_in *arg = (struct fuse_open_in *) inarg; + struct fuse_create_in *arg = (struct fuse_create_in *) inarg; if (req->f->op.create) { struct fuse_file_info fi; + char *name = PARAM(arg); memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; - req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi); + if (req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; + else + name = (char *) inarg + sizeof(struct fuse_open_in); + + req->f->op.create(req, nodeid, name, arg->mode, &fi); } else fuse_reply_err(req, ENOSYS); } @@ -1168,6 +1183,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT; if (arg->flags & FUSE_BIG_WRITES) f->conn.capable |= FUSE_CAP_BIG_WRITES; + if (arg->flags & FUSE_DONT_MASK) + f->conn.capable |= FUSE_CAP_DONT_MASK; } else { f->conn.async_read = 0; f->conn.max_readahead = 0; @@ -1207,6 +1224,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) outarg.flags |= FUSE_EXPORT_SUPPORT; if (f->conn.want & FUSE_CAP_BIG_WRITES) outarg.flags |= FUSE_BIG_WRITES; + if (f->conn.want & FUSE_CAP_DONT_MASK) + outarg.flags |= FUSE_DONT_MASK; outarg.max_readahead = f->conn.max_readahead; outarg.max_write = f->conn.max_write; @@ -1270,6 +1289,56 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph) } } +int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, + off_t off, off_t len) +{ + struct fuse_notify_inval_inode_out outarg; + struct fuse_ll *f; + struct iovec iov[2]; + + if (!ch) + return -EINVAL; + + f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + if (!f) + return -ENODEV; + + outarg.ino = ino; + outarg.off = off; + outarg.len = len; + + iov[1].iov_base = &outarg; + iov[1].iov_len = sizeof(outarg); + + return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_INODE, iov, 2); +} + +int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, + const char *name, size_t namelen) +{ + struct fuse_notify_inval_entry_out outarg; + struct fuse_ll *f; + struct iovec iov[3]; + + if (!ch) + return -EINVAL; + + f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + if (!f) + return -ENODEV; + + outarg.parent = parent; + outarg.namelen = namelen; + outarg.padding = 0; + + iov[1].iov_base = &outarg; + iov[1].iov_len = sizeof(outarg); + iov[2].iov_base = (void *)name; + iov[2].iov_len = namelen + 1; + + return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3); +} + void *fuse_req_userdata(fuse_req_t req) { return req->f->userdata; @@ -1280,6 +1349,19 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) return &req->ctx; } +/* + * The size of fuse_ctx got extended, so need to be careful about + * incompatibility (i.e. a new binary cannot work with an old + * library). + */ +const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req); +const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req) +{ + return fuse_req_ctx(req); +} +FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4"); + + void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data) { diff --git a/lib/fuse_session.c b/lib/fuse_session.c index 7df4795..3758627 100644 --- a/lib/fuse_session.c +++ b/lib/fuse_session.c @@ -111,6 +111,11 @@ int fuse_session_exited(struct fuse_session *se) return se->exited; } +void *fuse_session_data(struct fuse_session *se) +{ + return se->data; +} + static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, size_t bufsize, void *data, int compat) diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index 463c74f..4ab0291 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -3,7 +3,6 @@ FUSE_2.2 { fuse_destroy; fuse_exit; fuse_exited; - fuse_get_context; fuse_invalidate; fuse_is_lib_option; fuse_loop; @@ -43,7 +42,6 @@ FUSE_2.4 { fuse_reply_readlink; fuse_reply_write; fuse_reply_xattr; - fuse_req_ctx; fuse_req_userdata; fuse_session_add_chan; fuse_session_destroy; @@ -176,6 +174,10 @@ FUSE_2.8 { fuse_reply_poll; fuse_req_getgroups; fuse_getgroups; + fuse_req_ctx; + fuse_get_context; + fuse_lowlevel_notify_inval_inode; + fuse_lowlevel_notify_inval_entry; local: *; -- cgit v1.2.3