summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2009-06-19 10:27:38 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2009-06-19 10:27:38 +0000
commitecd073bd7054c9e13516041e3ef930e39270c8df (patch)
treebb36abf9662bec5c5027363f6d0d902d00f40815
parent17d1cf6956d08de9aa79b4a7691fb50a2446fa18 (diff)
downloadfuse-ecd073bd7054c9e13516041e3ef930e39270c8df.tar.gz
Add fuse_getgroups (high level lib) and fuse_req_getgroups (low
level lib) functions to query the supplementary group IDs for the current request. Currently this is implemented on Linux by reading from the /proc filesystem.
-rw-r--r--ChangeLog7
-rw-r--r--README.NFS29
-rw-r--r--include/fuse.h20
-rw-r--r--include/fuse_lowlevel.h21
-rw-r--r--lib/fuse.c6
-rw-r--r--lib/fuse_lowlevel.c68
-rw-r--r--lib/fuse_versionscript2
7 files changed, 153 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index a32dd66..313a049 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2009-06-19 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Add fuse_getgroups (high level lib) and fuse_req_getgroups (low
+ level lib) functions to query the supplementary group IDs for the
+ current request. Currently this is implemented on Linux by
+ reading from the /proc filesystem.
+
2009-06-18 Miklos Szeredi <miklos@szeredi.hu>
* Add "noforget" option to high level lib to prevent ESTALE errors
diff --git a/README.NFS b/README.NFS
index b805f39..f3348d5 100644
--- a/README.NFS
+++ b/README.NFS
@@ -2,3 +2,32 @@ NFS exporting is supported in Linux kernels 2.6.27 or later.
You need to add an fsid=NNN option to /etc/exports to make exporting a
FUSE directory work.
+
+Filesystem support
+------------------
+
+NFS exporting works to some extent on all fuse filesystems, but not
+perfectly. This is due to the stateless nature of the protocol, the
+server has no way of knowing whether the client is keeping a reference
+to a file or not, and hence that file may be removed from the server's
+cache. In that case there has to be a way to look up that object
+using the inode number, otherwise an ESTALE error will be returned.
+
+1) low-level interface
+
+Filesystems need to implement special lookups for the names "." and
+"..". The former may be requested on any inode, including
+non-directories, while the latter is only requested for directories.
+Otherwise these special lookups should behave identically to ordinary
+lookups.
+
+2) high-level interface
+
+Because the high-level interface is path based, it is not possible to
+delegate looking up by inode to the filesystem.
+
+To work around this, currently a "noforget" option is provided, which
+makes the library remember nodes forever. This will make the NFS
+server happy, but also results in an ever growing memory footprint for
+the filesystem. For this reason if the filesystem is large (or the
+memory is small), then this option is not recommended.
diff --git a/include/fuse.h b/include/fuse.h
index 6ded4f5..a58cd9f 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -624,6 +624,26 @@ int fuse_loop_mt(struct fuse *f);
struct fuse_context *fuse_get_context(void);
/**
+ * Get the current supplementary group IDs for the current request
+ *
+ * Similar to the getgroups(2) system call, except the return value is
+ * always the total number of group IDs, even if it is larger than the
+ * specified size.
+ *
+ * The current fuse kernel module in linux (as of 2.6.30) doesn't pass
+ * the group list to userspace, hence this function needs to parse
+ * "/proc/$TID/task/$TID/status" to get the group IDs.
+ *
+ * This feature may not be supported on all operating systems. In
+ * such a case this function will return -ENOSYS.
+ *
+ * @param size size of given array
+ * @param list array of group IDs to be filled in
+ * @return the total number of supplementary group IDs or -errno on failure
+ */
+int fuse_getgroups(int size, gid_t list[]);
+
+/**
* Check if the current request has already been interrupted
*
* @return 1 if the request has been interrupted, 0 otherwise
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index 5ab2422..a495e15 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -1175,6 +1175,27 @@ void *fuse_req_userdata(fuse_req_t req);
const struct fuse_ctx *fuse_req_ctx(fuse_req_t req);
/**
+ * Get the current supplementary group IDs for the specified request
+ *
+ * Similar to the getgroups(2) system call, except the return value is
+ * always the total number of group IDs, even if it is larger than the
+ * specified size.
+ *
+ * The current fuse kernel module in linux (as of 2.6.30) doesn't pass
+ * the group list to userspace, hence this function needs to parse
+ * "/proc/$TID/task/$TID/status" to get the group IDs.
+ *
+ * This feature may not be supported on all operating systems. In
+ * such a case this function will return -ENOSYS.
+ *
+ * @param req request handle
+ * @param size size of given array
+ * @param list array of group IDs to be filled in
+ * @return the total number of supplementary group IDs or -errno on failure
+ */
+int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]);
+
+/**
* Callback function for an interrupt
*
* @param req interrupted request
diff --git a/lib/fuse.c b/lib/fuse.c
index 9267ca6..dad9a71 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -3450,6 +3450,12 @@ struct fuse_context *fuse_get_context(void)
return &fuse_get_context_internal()->ctx;
}
+int fuse_getgroups(int size, gid_t list[])
+{
+ fuse_req_t req = fuse_get_context_internal()->req;
+ return fuse_req_getgroups(req, size, list);
+}
+
int fuse_interrupted(void)
{
return fuse_req_interrupted(fuse_get_context_internal()->req);
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index a60c5b8..89e8f2f 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -1575,6 +1575,74 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
return fuse_lowlevel_new_common(args, op, op_size, userdata);
}
+#ifdef linux
+int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
+{
+ char *buf;
+ size_t bufsize = 1024;
+ char path[128];
+ int ret;
+ int fd;
+ unsigned long pid = req->ctx.pid;
+ char *s;
+
+ sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
+
+retry:
+ buf = malloc(bufsize);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ ret = -EIO;
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ goto out_free;
+
+ ret = read(fd, buf, bufsize);
+ close(fd);
+ if (ret == -1) {
+ ret = -EIO;
+ goto out_free;
+ }
+
+ if (ret == bufsize) {
+ free(buf);
+ bufsize *= 4;
+ goto retry;
+ }
+
+ ret = -EIO;
+ s = strstr(buf, "\nGroups:");
+ if (s == NULL)
+ goto out_free;
+
+ s += 8;
+ ret = 0;
+ while (1) {
+ char *end;
+ unsigned long val = strtoul(s, &end, 0);
+ if (end == s)
+ break;
+
+ s = end;
+ if (ret < size)
+ list[ret] = val;
+ ret++;
+ }
+
+out_free:
+ free(buf);
+ return ret;
+}
+#else /* linux */
+/*
+ * This is currently not implemented on other than Linux...
+ */
+int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]);
+{
+ return -ENOSYS;
+}
+#endif
#ifndef __FreeBSD__
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index 4cd09aa..463c74f 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -174,6 +174,8 @@ FUSE_2.8 {
fuse_reply_ioctl_iov;
fuse_reply_ioctl_retry;
fuse_reply_poll;
+ fuse_req_getgroups;
+ fuse_getgroups;
local:
*;