fix
authorMiklos Szeredi <miklos@szeredi.hu>
Mon, 1 Aug 2005 12:48:30 +0000 (12:48 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Mon, 1 Aug 2005 12:48:30 +0000 (12:48 +0000)
ChangeLog
include/fuse.h
include/fuse_common.h
include/fuse_lowlevel.h
kernel/dir.c
kernel/fuse_i.h
kernel/fuse_kernel.h
lib/fuse.c
lib/fuse_lowlevel.c

index 37b13d8c22906621b52a1bb65899eef412f07555..aa6d1fd813186619d082b630c43f42b5ee8a1eee 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,9 @@
        userspace.  For both mount options, if the option is given, then
        the respective open flag is set, otherwise the open flag is left
        unmodified (so the filesystem can set it).
+
+       * Add ACCESS operation.  This is called from the access() system
+       call if 'default_permissions' mount option is not given
  
 2005-07-28  Miklos Szeredi <miklos@szeredi.hu>
 
index e285c07191c63cd07752fa242b2a3b7ed2f7c53d..b7b7ef326b596774f6fea3f5ed7c6a883a0ae5c8 100644 (file)
@@ -306,6 +306,17 @@ struct fuse_operations {
      * Introduced in version 2.3
      */
     void (*destroy) (void *);
+
+    /**
+     * Check file access permissions
+     * 
+     * Need not be implemented.  Will only be called for the access()
+     * system call, and only if 'default_permissions' mount option is
+     * not given.
+     *
+     * Introduced in version 2.4
+     */
+    int (*access) (const char *, int);
 };
 
 /** Extra context that may be needed by some filesystems
index 21109461eb2a37a8d1d4c994733035cd6633e930..bb120d2fdcbf976cfa05975c77c8ab45bb9318c3 100644 (file)
@@ -26,11 +26,12 @@ struct fuse_file_info {
         writepage */
     int writepage;
 
-    /** Can be filled in by open, to use direct I/O on this file */
+    /** Can be filled in by open, to use direct I/O on this file.
+        Introduced in version 2.4 */
     unsigned int direct_io : 1;
 
     /** Can be filled in by open, to indicate, that cached file data
-        need not be invalidated */    
+        need not be invalidated.  Introduced in version 2.4 */
     unsigned int keep_cache : 1;
 };
 
index ddead682781773ed98c98fee80a25157f4f4e0a7..16257a94476d083b462086cbfa6beffa38eb428e 100644 (file)
@@ -78,6 +78,7 @@ struct fuse_ll_operations {
     void (*getattr)(fuse_req_t req, fuse_ino_t ino);
     void (*setattr)(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
                      int to_set);
+    void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
     void (*readlink)(fuse_req_t req, fuse_ino_t ino);
     void (*mknod)  (fuse_req_t req, fuse_ino_t parent, const char *name,
                     mode_t mode, dev_t rdev);
index 2aa16e9f26aae9af8d5f1f04305c1722766590a8..26d2dfcfb61d592ee6449ff94a806a4f16f2899f 100644 (file)
@@ -476,17 +476,50 @@ static int fuse_revalidate(struct dentry *entry)
        return fuse_do_getattr(inode);
 }
 
+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;
+}
+
 static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
+       int err;
 
        if (!fuse_allow_task(fc, current))
                return -EACCES;
        else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
 #ifdef KERNEL_2_6_10_PLUS
-               int err = generic_permission(inode, mask, NULL);
+               err = generic_permission(inode, mask, NULL);
 #else
-               int err = vfs_permission(inode, mask);
+               err = vfs_permission(inode, mask);
 #endif
 
                /* If permission is denied, try to refresh file
@@ -510,8 +543,6 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
                   This is actually not so grave, since the user can
                   simply keep access to the file/directory anyway by
                   keeping it open... */
-
-               return err;
        } else {
                int mode = inode->i_mode;
                if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
@@ -519,8 +550,12 @@ 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;
-               return 0;
+
+               err = 0;
+               if (nd->flags & LOOKUP_ACCESS)
+                       err = fuse_access(inode, mask);
        }
+       return err;
 }
 
 static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
index 4faaff7ae25bf7ffba81eb77f0b56b08dafd810c..cf990fbd340309d476953d008c8af1f59210bb2e 100644 (file)
@@ -334,9 +334,12 @@ struct fuse_conn {
        /** Is removexattr not implemented by fs? */
        unsigned no_removexattr : 1;
 
-       /** Are file locking primitives implemented by fs? */
+       /** Are file locking primitives not implemented by fs? */
        unsigned no_lk : 1;
 
+       /** Is access not implemented by fs */
+       unsigned no_access : 1;
+
 #ifdef KERNEL_2_6
        /** Backing dev info */
        struct backing_dev_info bdi;
index fc99b7d67214b2d78b6d42b7066074eabae14474..2c2903e5a7a03f6ae4049591d464047cb0176ed4 100644 (file)
@@ -105,7 +105,8 @@ enum fuse_opcode {
        FUSE_FSYNCDIR      = 30,
        FUSE_GETLK         = 31,
        FUSE_SETLK         = 32,
-       FUSE_SETLKW        = 33
+       FUSE_SETLKW        = 33,
+       FUSE_ACCESS        = 34
 };
 
 /* Conservative buffer size for the client */
@@ -232,6 +233,11 @@ struct fuse_lk_in_out {
        struct fuse_file_lock lk;
 };
 
+struct fuse_access_in {
+       __u32   mask;
+       __u32   padding;
+};
+
 struct fuse_init_in_out {
        __u32   major;
        __u32   minor;
index 91a1e525144f2fc04c3ddfb3ed00e9a89aaa682f..a84964833b905e06c85ac32862d4cf4e9c699cd4 100644 (file)
@@ -724,6 +724,25 @@ 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) {
+        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);
@@ -1589,6 +1608,7 @@ static struct fuse_ll_operations 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 98ce673aa210b274a652d9465f479aabaa05a744..9df0e098f645c7fae2f51603be321895a18e2ab1 100644 (file)
@@ -81,6 +81,7 @@ static const char *opname(enum fuse_opcode opcode)
     case FUSE_GETLK:           return "GETLK";
     case FUSE_SETLK:           return "SETLK";
     case FUSE_SETLKW:          return "SETLKW";
+    case FUSE_ACCESS:          return "ACCESS";
     default:                   return "???";
     }
 }
@@ -430,6 +431,14 @@ 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)
@@ -927,6 +936,10 @@ void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
     case FUSE_SETLKW:
         do_setlk(req, in->nodeid, 1, (struct fuse_lk_in_out *) inarg);
         break;
+        
+    case FUSE_ACCESS:
+        do_access(req, in->nodeid, (struct fuse_access_in *) inarg);
+        break;
 
     default:
         fuse_reply_err(req, ENOSYS);