add access operation
authorMiklos Szeredi <miklos@szeredi.hu>
Wed, 26 Oct 2005 12:53:25 +0000 (12:53 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Wed, 26 Oct 2005 12:53:25 +0000 (12:53 +0000)
14 files changed:
ChangeLog
configure.in
example/fusexmp.c
example/fusexmp_fh.c
include/fuse.h
include/fuse_common.h
include/fuse_lowlevel.h
kernel/configure.ac
kernel/dir.c
kernel/fuse_i.h
kernel/fuse_kernel.h
lib/Makefile.am
lib/fuse.c
lib/fuse_lowlevel.c

index b0192d776cd2dfa5c252e9d635f641a12376183d..e2e1b8c83775f638d8c09550baf5100b3d337bbd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2005-10-26  Miklos Szeredi <miklos@szeredi.hu>
+
+       * Add ACCESS operation.  This is called from the access() system
+       call if 'default_permissions' mount option is not given
+
 2005-10-18  Miklos Szeredi <miklos@szeredi.hu>
 
        * lib: optimize buffer reallocation in fill_dir.
index 8cc5c659e7d850cbb4708f361e4761eeab0f6aff..5a8c8b5d8a5f487761071b8cb168f88c6a6e072f 100644 (file)
@@ -1,4 +1,4 @@
-AC_INIT(fuse, 2.4.1)
+AC_INIT(fuse, 2.5.0-pre0)
 AM_INIT_AUTOMAKE
 AM_CONFIG_HEADER(include/config.h)
 
index 1ef0ac32b04c3895abd6adf9aa7d8c00c34dca28..173255679642348d1a1e56991c3ea575b0f1bea7 100644 (file)
@@ -36,6 +36,17 @@ static int xmp_getattr(const char *path, struct stat *stbuf)
     return 0;
 }
 
+static int xmp_access(const char *path, int mask)
+{
+    int res;
+
+    res = access(path, mask);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
 static int xmp_readlink(const char *path, char *buf, size_t size)
 {
     int res;
@@ -319,6 +330,7 @@ static int xmp_removexattr(const char *path, const char *name)
 
 static struct fuse_operations xmp_oper = {
     .getattr   = xmp_getattr,
+    .access    = xmp_access,
     .readlink  = xmp_readlink,
     .readdir   = xmp_readdir,
     .mknod     = xmp_mknod,
index f1c08f88c4dd6f6598f3dba6c2b392cf4384db12..d17699e07c094bf2c5aaf55cf772694e7d5aa2b9 100644 (file)
@@ -33,6 +33,17 @@ static int xmp_getattr(const char *path, struct stat *stbuf)
     return 0;
 }
 
+static int xmp_access(const char *path, int mask)
+{
+    int res;
+
+    res = access(path, mask);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
 static int xmp_readlink(const char *path, char *buf, size_t size)
 {
     int res;
@@ -317,6 +328,7 @@ static int xmp_removexattr(const char *path, const char *name)
 
 static struct fuse_operations xmp_oper = {
     .getattr   = xmp_getattr,
+    .access    = xmp_access,
     .readlink  = xmp_readlink,
     .opendir   = xmp_opendir,
     .readdir   = xmp_readdir,
index 9739f2636f87bae50e555e2b3ef7ff2878cbafbd..4a099bc9eb907f9324fae7cd5241cb825f3e7a75 100644 (file)
@@ -63,8 +63,9 @@ typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type,
  *
  * All methods are optional, but some are essential for a useful
  * filesystem (e.g. getattr).  Open, flush, release, fsync, opendir,
- * releasedir, fsyncdir, init and destroy are special purpose methods,
- * without which a full featured filesystem can still be implemented.
+ * releasedir, fsyncdir, access, init and destroy are special purpose
+ * methods, without which a full featured filesystem can still be
+ * implemented.
  */
 struct fuse_operations {
     /** Get file attributes.
@@ -296,6 +297,17 @@ struct fuse_operations {
      * Introduced in version 2.3
      */
     void (*destroy) (void *);
+
+    /**
+     * Check file access permissions
+     *
+     * Need not be implemented.  This will be called for the access()
+     * system call.  If the 'default_permissions' mount option is
+     * given, this method is not called.
+     *
+     * Introduced in version 2.5
+     */
+    int (*access) (const char *, int);
 };
 
 /** Extra context that may be needed by some filesystems
index ef7e85a7f9e0b10eed862e82daebea3a08e362e1..a59aea68c58fdd561908438cf99373a8740b787e 100644 (file)
@@ -21,7 +21,7 @@
 #define FUSE_MAJOR_VERSION 2
 
 /** Minor version of FUSE library interface */
-#define FUSE_MINOR_VERSION 4
+#define FUSE_MINOR_VERSION 5
 
 #define FUSE_MAKE_VERSION(maj, min)  ((maj) * 10 + (min))
 #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
index dee43250691b3c610c6c0de29ab462297b4295c2..73f57f0ae551e36688915cafca80812a0465a47d 100644 (file)
@@ -642,6 +642,8 @@ struct fuse_lowlevel_ops {
      * @param name of the extended attribute
      */
     void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
+
+    void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
 };
 
 /**
index 5f31daa7a2e2b2be1026d0648b5b4ffad8955613..04483e36ce29f33fd2a42a40b0e52dbbcd7dfff6 100644 (file)
@@ -1,4 +1,4 @@
-AC_INIT(fuse-kernel, 2.4.1)
+AC_INIT(fuse-kernel, 2.5.0-pre0)
 AC_CONFIG_HEADERS([config.h])
 
 AC_PROG_INSTALL
index 6753636db5f9d6e2b5557e23e03350ee0a1b57c3..20a6aae80e8b8730d5f90cc3f8fcfdb53c0e01b3 100644 (file)
@@ -482,6 +482,40 @@ static int fuse_revalidate(struct dentry *entry)
        return fuse_do_getattr(inode);
 }
 
+#ifdef KERNEL_2_6
+static int fuse_access(struct inode *inode, int mask)
+{
+       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_req *req;
+       struct fuse_access_in inarg;
+       int err;
+
+       if (fc->no_access)
+               return 0;
+
+       req = fuse_get_request(fc);
+       if (!req)
+               return -EINTR;
+
+       memset(&inarg, 0, sizeof(inarg));
+       inarg.mask = mask;
+       req->in.h.opcode = FUSE_ACCESS;
+       req->in.h.nodeid = get_node_id(inode);
+       req->inode = inode;
+       req->in.numargs = 1;
+       req->in.args[0].size = sizeof(inarg);
+       req->in.args[0].value = &inarg;
+       request_send(fc, req);
+       err = req->out.h.error;
+       fuse_put_request(fc, req);
+       if (err == -ENOSYS) {
+               fc->no_access = 1;
+               err = 0;
+       }
+       return err;
+}
+#endif
+
 static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
@@ -525,6 +559,11 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
                         return -EROFS;
                if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
                        return -EACCES;
+
+#ifdef KERNEL_2_6
+               if (nd && (nd->flags & LOOKUP_ACCESS))
+                       return fuse_access(inode, mask);
+#endif
                return 0;
        }
 }
index b8270ce05ef3b051b217ac498c8070af60d85e3b..af9457d146689954ed5088ecfdcec8c12c18d4a0 100644 (file)
@@ -340,6 +340,9 @@ struct fuse_conn {
        /** Is removexattr not implemented by fs? */
        unsigned no_removexattr : 1;
 
+       /** Is access not implemented by fs? */
+       unsigned no_access : 1;
+
 #ifdef KERNEL_2_6
        /** Backing dev info */
        struct backing_dev_info bdi;
index 1dc9e0633e29ff89fa2aa4d4e74709a8745290c0..771020168d1a90454b7574277e4ea36018e82b81 100644 (file)
@@ -127,7 +127,8 @@ enum fuse_opcode {
        FUSE_OPENDIR       = 27,
        FUSE_READDIR       = 28,
        FUSE_RELEASEDIR    = 29,
-       FUSE_FSYNCDIR      = 30
+       FUSE_FSYNCDIR      = 30,
+       FUSE_ACCESS        = 34
 };
 
 /* Conservative buffer size for the client */
@@ -250,6 +251,11 @@ struct fuse_getxattr_out {
        __u32   padding;
 };
 
+struct fuse_access_in {
+       __u32   mask;
+       __u32   padding;
+};
+
 struct fuse_init_in_out {
        __u32   major;
        __u32   minor;
index 2d81fb00a894ed1235174fd37c1d4f08daeee2c9..8d340f9992367966bc7d22c1626c809998eb7adf 100644 (file)
@@ -14,7 +14,7 @@ libfuse_la_SOURCES =          \
        helper.c                \
        mount.c
 
-libfuse_la_LDFLAGS = -lpthread -version-number 2:4:1 \
+libfuse_la_LDFLAGS = -lpthread -version-number 2:5:0 \
        -Wl,--version-script,fuse_versionscript
 
 EXTRA_DIST = fuse_versionscript
index b0cf5530ad360c8ee3f69f0b6befaf3c8156bad4..6b3b6ae56f6efc7c9d8a6ad2b0acaeeb4090be3b 100644 (file)
@@ -736,6 +736,29 @@ static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
         reply_err(req, err);
 }
 
+static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
+{
+    struct fuse *f = req_fuse_prepare(req);
+    char *path;
+    int err;
+
+    err = -ENOENT;
+    pthread_rwlock_rdlock(&f->tree_lock);
+    path = get_path(f, ino);
+    if (path != NULL) {
+        if (f->flags & FUSE_DEBUG) {
+            printf("ACCESS %s 0%o\n", path, mask);
+            fflush(stdout);
+        }
+        err = -ENOSYS;
+        if (f->op.access)
+            err = f->op.access(path, mask);
+        free(path);
+    }
+    pthread_rwlock_unlock(&f->tree_lock);
+    reply_err(req, err);
+}
+
 static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
 {
     struct fuse *f = req_fuse_prepare(req);
@@ -1622,6 +1645,7 @@ static struct fuse_lowlevel_ops fuse_path_ops = {
     .forget = fuse_forget,
     .getattr = fuse_getattr,
     .setattr = fuse_setattr,
+    .access = fuse_access,
     .readlink = fuse_readlink,
     .mknod = fuse_mknod,
     .mkdir = fuse_mkdir,
index 95882ed7661d6636711f12e9bdcbcf5b6ac43b32..22dc41d9e3fa261532ef2a2fdd445fcb4fdd9dd1 100644 (file)
@@ -69,6 +69,7 @@ static const char *opname(enum fuse_opcode opcode)
     case FUSE_READDIR:         return "READDIR";
     case FUSE_RELEASEDIR:      return "RELEASEDIR";
     case FUSE_FSYNCDIR:                return "FSYNCDIR";
+    case FUSE_ACCESS:          return "ACCESS";
     default:                   return "???";
     }
 }
@@ -361,6 +362,15 @@ static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
         fuse_reply_err(req, ENOSYS);
 }
 
+static void do_access(fuse_req_t req, fuse_ino_t nodeid,
+                      struct fuse_access_in *arg)
+{
+    if (req->f->op.access)
+        req->f->op.access(req, nodeid, arg->mask);
+    else
+        fuse_reply_err(req, ENOSYS);
+}
+
 static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
 {
     if (req->f->op.readlink)
@@ -811,6 +821,10 @@ static void fuse_ll_process(void *data, const char *buf, size_t len,
         do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
         break;
 
+    case FUSE_ACCESS:
+        do_access(req, in->nodeid, (struct fuse_access_in *) inarg);
+        break;
+
     default:
         fuse_reply_err(req, ENOSYS);
     }