[PATCH] NFSD: Add server support for NFSv3 ACLs.
[safe/jmp/linux-2.6] / fs / nfsd / vfs.c
index e3e9d21..ae3940d 100644 (file)
@@ -46,8 +46,9 @@
 #include <linux/nfsd/nfsfh.h>
 #include <linux/quotaops.h>
 #include <linux/dnotify.h>
-#ifdef CONFIG_NFSD_V4
+#include <linux/xattr_acl.h>
 #include <linux/posix_acl.h>
+#ifdef CONFIG_NFSD_V4
 #include <linux/posix_acl_xattr.h>
 #include <linux/xattr_acl.h>
 #include <linux/xattr.h>
@@ -1857,3 +1858,107 @@ nfsd_racache_init(int cache_size)
        nfsdstats.ra_size = cache_size;
        return 0;
 }
+
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+struct posix_acl *
+nfsd_get_posix_acl(struct svc_fh *fhp, int type)
+{
+       struct inode *inode = fhp->fh_dentry->d_inode;
+       char *name;
+       void *value = NULL;
+       ssize_t size;
+       struct posix_acl *acl;
+
+       if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr)
+               return ERR_PTR(-EOPNOTSUPP);
+       switch(type) {
+               case ACL_TYPE_ACCESS:
+                       name = XATTR_NAME_ACL_ACCESS;
+                       break;
+               case ACL_TYPE_DEFAULT:
+                       name = XATTR_NAME_ACL_DEFAULT;
+                       break;
+               default:
+                       return ERR_PTR(-EOPNOTSUPP);
+       }
+
+       size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0);
+
+       if (size < 0) {
+               acl = ERR_PTR(size);
+               goto getout;
+       } else if (size > 0) {
+               value = kmalloc(size, GFP_KERNEL);
+               if (!value) {
+                       acl = ERR_PTR(-ENOMEM);
+                       goto getout;
+               }
+               size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size);
+               if (size < 0) {
+                       acl = ERR_PTR(size);
+                       goto getout;
+               }
+       }
+       acl = posix_acl_from_xattr(value, size);
+
+getout:
+       kfree(value);
+       return acl;
+}
+
+int
+nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
+{
+       struct inode *inode = fhp->fh_dentry->d_inode;
+       char *name;
+       void *value = NULL;
+       size_t size;
+       int error;
+
+       if (!IS_POSIXACL(inode) || !inode->i_op ||
+           !inode->i_op->setxattr || !inode->i_op->removexattr)
+               return -EOPNOTSUPP;
+       switch(type) {
+               case ACL_TYPE_ACCESS:
+                       name = XATTR_NAME_ACL_ACCESS;
+                       break;
+               case ACL_TYPE_DEFAULT:
+                       name = XATTR_NAME_ACL_DEFAULT;
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+       }
+
+       if (acl && acl->a_count) {
+               size = xattr_acl_size(acl->a_count);
+               value = kmalloc(size, GFP_KERNEL);
+               if (!value)
+                       return -ENOMEM;
+               size = posix_acl_to_xattr(acl, value, size);
+               if (size < 0) {
+                       error = size;
+                       goto getout;
+               }
+       } else
+               size = 0;
+
+       if (!fhp->fh_locked)
+               fh_lock(fhp);  /* unlocking is done automatically */
+       if (size)
+               error = inode->i_op->setxattr(fhp->fh_dentry, name,
+                                             value, size, 0);
+       else {
+               if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
+                       error = 0;
+               else {
+                       error = inode->i_op->removexattr(fhp->fh_dentry, name);
+                       if (error == -ENODATA)
+                               error = 0;
+               }
+       }
+
+getout:
+       kfree(value);
+       return error;
+}
+#endif  /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */