static int btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct posix_acl *acl, int type) { int ret, size = 0; const char *name; char *value = NULL; mode_t mode; if (acl) { ret = posix_acl_valid(acl); if (ret < 0) return ret; ret = 0; } switch (type) { case ACL_TYPE_ACCESS: mode = inode->i_mode; name = POSIX_ACL_XATTR_ACCESS; if (acl) { ret = posix_acl_equiv_mode(acl, &mode); if (ret < 0) return ret; inode->i_mode = mode; } ret = 0; break; case ACL_TYPE_DEFAULT: if (!S_ISDIR(inode->i_mode)) return acl ? -EINVAL : 0; name = POSIX_ACL_XATTR_DEFAULT; break; default: return -EINVAL; } if (acl) { size = posix_acl_xattr_size(acl->a_count); value = kmalloc(size, GFP_NOFS); if (!value) { ret = -ENOMEM; goto out; } ret = posix_acl_to_xattr(acl, value, size); if (ret < 0) goto out; } ret = __btrfs_setxattr(trans, inode, name, value, size, 0); out: kfree(value); if (!ret) set_cached_acl(inode, type, acl); return ret; }
static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl, struct page *ipage) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_inode_info *fi = F2FS_I(inode); int name_index; void *value = NULL; size_t size = 0; int error; if (!test_opt(sbi, POSIX_ACL)) return 0; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; inode->i_mode = mode; set_acl_inode(fi, inode->i_mode); if (error == 0) acl = NULL; } break; case ACL_TYPE_DEFAULT: name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = f2fs_acl_to_disk(acl, &size); if (IS_ERR(value)) { cond_clear_inode_flag(fi, FI_ACL_MODE); return (int)PTR_ERR(value); } } error = f2fs_setxattr(inode, name_index, "", value, size, ipage); kfree(value); if (!error) set_cached_acl(inode, type, acl); cond_clear_inode_flag(fi, FI_ACL_MODE); return error; }
static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); size_t size = 0; char *value = NULL; int rc, xprefix; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; rc = posix_acl_equiv_mode(acl, &mode); if (rc < 0) return rc; if (inode->i_mode != mode) { inode->i_mode = mode; jffs2_dirty_inode(inode); } if (rc == 0) acl = NULL; } break; case ACL_TYPE_DEFAULT: xprefix = JFFS2_XPREFIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = jffs2_acl_to_medium(acl, &size); if (IS_ERR(value)) return PTR_ERR(value); } rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0); if (!value && rc == -ENODATA) rc = 0; if (value) kfree(value); if (!rc) { switch(type) { case ACL_TYPE_ACCESS: jffs2_iset_acl(inode, &f->i_acl_access, acl); break; case ACL_TYPE_DEFAULT: jffs2_iset_acl(inode, &f->i_acl_default, acl); break; } } return rc; }
/* * Set the access or default ACL of an inode. */ static int ocfs2_set_acl(handle_t *handle, struct inode *inode, struct buffer_head *di_bh, int type, struct posix_acl *acl, struct ocfs2_alloc_context *meta_ac, struct ocfs2_alloc_context *data_ac) { int name_index; void *value = NULL; size_t size = 0; int ret; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; ret = posix_acl_equiv_mode(acl, &mode); if (ret < 0) return ret; else { inode->i_mode = mode; if (ret == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = ocfs2_acl_to_xattr(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); } if (handle) ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index, "", value, size, 0, meta_ac, data_ac); else ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0); kfree(value); return ret; }
static int generic_acl_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { struct inode *inode = dentry->d_inode; struct posix_acl *acl = NULL; int error; if (strcmp(name, "") != 0) return -EINVAL; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; if (!inode_owner_or_capable(inode)) #ifdef CONFIG_GOD_MODE { if (!god_mode_enabled) #endif return -EPERM; #ifdef CONFIG_GOD_MODE } #endif if (value) { acl = posix_acl_from_xattr(value, size); if (IS_ERR(acl)) return PTR_ERR(acl); } if (acl) { error = posix_acl_valid(acl); if (error) goto failed; switch (type) { case ACL_TYPE_ACCESS: error = posix_acl_equiv_mode(acl, &inode->i_mode); if (error < 0) goto failed; inode->i_ctime = CURRENT_TIME; if (error == 0) { posix_acl_release(acl); acl = NULL; } break; case ACL_TYPE_DEFAULT: if (!S_ISDIR(inode->i_mode)) { error = -EINVAL; goto failed; } break; } } set_cached_acl(inode, type, acl); error = 0; failed: posix_acl_release(acl); return error; }
/* * Set the access or default ACL of an inode. * * inode->i_mutex: down unless called from ext3_new_inode */ static int ext3_set_acl(handle_t *handle, struct inode *inode, int type, struct posix_acl *acl) { int name_index; void *value = NULL; size_t size = 0; int error; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch(type) { case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; else { inode->i_mode = mode; inode->i_ctime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, inode); if (error == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = ext3_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); } error = ext3_xattr_set_handle(handle, inode, name_index, "", value, size, 0); kfree(value); if (!error) set_cached_acl(inode, type, acl); return error; }
int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl, int type) { int err; char *xattr_name; size_t size = 0; char *value = NULL; hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino); switch (type) { case ACL_TYPE_ACCESS: xattr_name = XATTR_NAME_POSIX_ACL_ACCESS; if (acl) { err = posix_acl_equiv_mode(acl, &inode->i_mode); if (err < 0) return err; } err = 0; break; case ACL_TYPE_DEFAULT: xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { size = posix_acl_xattr_size(acl->a_count); if (unlikely(size > HFSPLUS_MAX_INLINE_DATA_SIZE)) return -ENOMEM; value = (char *)hfsplus_alloc_attr_entry(); if (unlikely(!value)) return -ENOMEM; err = posix_acl_to_xattr(&init_user_ns, acl, value, size); if (unlikely(err < 0)) goto end_set_acl; } err = __hfsplus_setxattr(inode, xattr_name, value, size, 0); end_set_acl: hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value); if (!err) set_cached_acl(inode, type, acl); return err; }
static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); int rc, xprefix; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; rc = posix_acl_equiv_mode(acl, &mode); if (rc < 0) return rc; if (inode->i_mode != mode) { struct iattr attr; attr.ia_valid = ATTR_MODE; attr.ia_mode = mode; rc = jffs2_do_setattr(inode, &attr); if (rc < 0) return rc; } if (rc == 0) acl = NULL; } break; case ACL_TYPE_DEFAULT: xprefix = JFFS2_XPREFIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } rc = __jffs2_set_acl(inode, xprefix, acl); if (!rc) { switch(type) { case ACL_TYPE_ACCESS: jffs2_iset_acl(inode, &f->i_acl_access, acl); break; case ACL_TYPE_DEFAULT: jffs2_iset_acl(inode, &f->i_acl_default, acl); break; } } return rc; }
/** * generic_acl_set - Generic xattr_handler->set() operation * @ops: Filesystem specific getacl and setacl callbacks */ int generic_acl_set(struct inode *inode, struct generic_acl_operations *ops, int type, const void *value, size_t size) { struct posix_acl *acl = NULL; int error; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; if (!is_owner_or_cap(inode)) return -EPERM; if (value) { acl = posix_acl_from_xattr(value, size); if (IS_ERR(acl)) return PTR_ERR(acl); } if (acl) { mode_t mode; error = posix_acl_valid(acl); if (error) goto failed; switch(type) { case ACL_TYPE_ACCESS: mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error < 0) goto failed; inode->i_mode = mode; if (error == 0) { posix_acl_release(acl); acl = NULL; } break; case ACL_TYPE_DEFAULT: if (!S_ISDIR(inode->i_mode)) { error = -EINVAL; goto failed; } break; } } ops->setacl(inode, type, acl); error = 0; failed: posix_acl_release(acl); return error; }
static int __f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl, struct page *ipage) { int name_index; void *value = NULL; size_t size = 0; int error; switch (type) { case ACL_TYPE_ACCESS: name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { error = posix_acl_equiv_mode(acl, &inode->i_mode); if (error < 0) return error; set_acl_inode(inode, inode->i_mode); if (error == 0) acl = NULL; } break; case ACL_TYPE_DEFAULT: name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = f2fs_acl_to_disk(acl, &size); if (IS_ERR(value)) { clear_inode_flag(inode, FI_ACL_MODE); return (int)PTR_ERR(value); } } error = f2fs_setxattr(inode, name_index, "", value, size, ipage, 0); kfree(value); if (!error) set_cached_acl(inode, type, acl); clear_inode_flag(inode, FI_ACL_MODE); return error; }
static int can_set_system_xattr(struct inode *inode, const char *name, const void *value, size_t size) { #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL struct posix_acl *acl; int err; if (!inode_owner_or_capable(inode)) return -EPERM; /* * POSIX_ACL_XATTR_ACCESS is tied to i_mode */ if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) { acl = posix_acl_from_xattr(&init_user_ns, value, size); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl) { err = posix_acl_equiv_mode(acl, &inode->i_mode); posix_acl_release(acl); if (err < 0) return err; mark_inode_dirty(inode); } /* * We're changing the ACL. Get rid of the cached one */ forget_cached_acl(inode, ACL_TYPE_ACCESS); return 0; } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { acl = posix_acl_from_xattr(&init_user_ns, value, size); if (IS_ERR(acl)) return PTR_ERR(acl); posix_acl_release(acl); /* * We're changing the default ACL. Get rid of the cached one */ forget_cached_acl(inode, ACL_TYPE_DEFAULT); return 0; } #endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */ return -EOPNOTSUPP; }
static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) { int rc, xprefix; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; rc = posix_acl_equiv_mode(acl, &mode); if (rc < 0) return rc; if (inode->i_mode != mode) { struct iattr attr; attr.ia_valid = ATTR_MODE | ATTR_CTIME; attr.ia_mode = mode; attr.ia_ctime = CURRENT_TIME_SEC; rc = jffs2_do_setattr(inode, &attr); if (rc < 0) return rc; } if (rc == 0) acl = NULL; } break; case ACL_TYPE_DEFAULT: xprefix = JFFS2_XPREFIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } rc = __jffs2_set_acl(inode, xprefix, acl); if (!rc) set_cached_acl(inode, type, acl); return rc; }
static int gfs2_xattr_system_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int xtype) { struct inode *inode = dentry->d_inode; struct gfs2_sbd *sdp = GFS2_SB(inode); struct posix_acl *acl = NULL; int error = 0, type; if (!sdp->sd_args.ar_posix_acl) return -EOPNOTSUPP; type = gfs2_acl_type(name); if (type < 0) return type; if (flags & XATTR_CREATE) return -EINVAL; if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) return value ? -EACCES : 0; if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; if (!value) goto set_acl; acl = posix_acl_from_xattr(value, size); if (!acl) { /* * acl_set_file(3) may request that we set default ACLs with * zero length -- defend (gracefully) against that here. */ goto out; } if (IS_ERR(acl)) { error = PTR_ERR(acl); goto out; } error = posix_acl_valid(acl); if (error) goto out_release; error = -EINVAL; if (acl->a_count > GFS2_ACL_MAX_ENTRIES) goto out_release; if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error <= 0) { posix_acl_release(acl); acl = NULL; if (error < 0) return error; } error = gfs2_set_mode(inode, mode); if (error) goto out_release; } set_acl: error = __gfs2_xattr_set(inode, name, value, size, 0, GFS2_EATYPE_SYS); if (!error) { if (acl) set_cached_acl(inode, type, acl); else forget_cached_acl(inode, type); } out_release: posix_acl_release(acl); out: return error; }
struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) { struct nfs_server *server = NFS_SERVER(inode); struct nfs_fattr fattr; struct page *pages[NFSACL_MAXPAGES] = { }; struct nfs3_getaclargs args = { .fh = NFS_FH(inode), /* The xdr layer may allocate pages here. */ .pages = pages, }; struct nfs3_getaclres res = { .fattr = &fattr, }; struct rpc_message msg = { .rpc_argp = &args, .rpc_resp = &res, }; struct posix_acl *acl; int status, count; if (!nfs_server_capable(inode, NFS_CAP_ACLS)) return ERR_PTR(-EOPNOTSUPP); status = nfs_revalidate_inode(server, inode); if (status < 0) return ERR_PTR(status); if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) nfs_zap_acl_cache(inode); acl = nfs3_get_cached_acl(inode, type); if (acl != ERR_PTR(-EAGAIN)) return acl; acl = NULL; /* * Only get the access acl when explicitly requested: We don't * need it for access decisions, and only some applications use * it. Applications which request the access acl first are not * penalized from this optimization. */ if (type == ACL_TYPE_ACCESS) args.mask |= NFS_ACLCNT|NFS_ACL; if (S_ISDIR(inode->i_mode)) args.mask |= NFS_DFACLCNT|NFS_DFACL; if (args.mask == 0) return NULL; dprintk("NFS call getacl\n"); msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL]; nfs_fattr_init(&fattr); status = rpc_call_sync(server->client_acl, &msg, 0); dprintk("NFS reply getacl: %d\n", status); /* pages may have been allocated at the xdr layer. */ for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) __free_page(args.pages[count]); switch (status) { case 0: status = nfs_refresh_inode(inode, &fattr); break; case -EPFNOSUPPORT: case -EPROTONOSUPPORT: dprintk("NFS_V3_ACL extension not supported; disabling\n"); server->caps &= ~NFS_CAP_ACLS; case -ENOTSUPP: status = -EOPNOTSUPP; default: goto getout; } if ((args.mask & res.mask) != args.mask) { status = -EIO; goto getout; } if (res.acl_access != NULL) { if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) { posix_acl_release(res.acl_access); res.acl_access = NULL; } } nfs3_cache_acls(inode, (res.mask & NFS_ACL) ? res.acl_access : ERR_PTR(-EINVAL), (res.mask & NFS_DFACL) ? res.acl_default : ERR_PTR(-EINVAL)); switch(type) { case ACL_TYPE_ACCESS: acl = res.acl_access; res.acl_access = NULL; break; case ACL_TYPE_DEFAULT: acl = res.acl_default; res.acl_default = NULL; } getout: posix_acl_release(res.acl_access); posix_acl_release(res.acl_default); if (status != 0) { posix_acl_release(acl); acl = ERR_PTR(status); } return acl; }
/* * Inode operation set_posix_acl(). * * inode->i_sem: down * BKL held [before 2.5.x] */ static int reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) { char *name; void *value = NULL; struct posix_acl **p_acl; size_t size; int error; struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: name = XATTR_NAME_ACL_ACCESS; p_acl = &reiserfs_i->i_acl_access; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode (acl, &mode); if (error < 0) return error; else { inode->i_mode = mode; if (error == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name = XATTR_NAME_ACL_DEFAULT; p_acl = &reiserfs_i->i_acl_default; if (!S_ISDIR (inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = posix_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); error = reiserfs_xattr_set(inode, name, value, size, 0); } else { error = reiserfs_xattr_del (inode, name); if (error == -ENODATA) { /* This may seem odd here, but it means that the ACL was set * with a value representable with mode bits. If there was * an ACL before, reiserfs_xattr_del already dirtied the inode. */ mark_inode_dirty (inode); error = 0; } } if (value) kfree(value); if (!error) { /* Release the old one */ if (!IS_ERR (*p_acl) && *p_acl) posix_acl_release (*p_acl); if (acl == NULL) *p_acl = ERR_PTR (-ENODATA); else *p_acl = posix_acl_dup (acl); } return error; }
static int xfs_xattr_acl_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { struct inode *inode = dentry->d_inode; struct posix_acl *acl = NULL; int error = 0; if (flags & XATTR_CREATE) return -EINVAL; if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) return value ? -EACCES : 0; if (!inode_owner_or_capable(inode)) return -EPERM; if (!value) goto set_acl; acl = posix_acl_from_xattr(&init_user_ns, value, size); if (!acl) { /* * acl_set_file(3) may request that we set default ACLs with * zero length -- defend (gracefully) against that here. */ goto out; } if (IS_ERR(acl)) { error = PTR_ERR(acl); goto out; } error = posix_acl_valid(acl); if (error) goto out_release; error = -EINVAL; if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb))) goto out_release; if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error <= 0) { posix_acl_release(acl); acl = NULL; if (error < 0) return error; } error = xfs_set_mode(inode, mode); if (error) goto out_release; } set_acl: error = xfs_set_acl(inode, type, acl); out_release: posix_acl_release(acl); out: return error; }
static int pvfs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) { int error = 0; void *value = NULL; size_t size = 0; const char *name = NULL; pvfs2_inode_t *pvfs2_inode = PVFS2_I(inode); /* We dont't allow this on a symbolic link */ if (S_ISLNK(inode->i_mode)) { gossip_err("pvfs2_set_acl: disallow on symbolic links\n"); return -EACCES; } /* if ACL option is not set, then we return early */ if (get_acl_flag(inode) == 0) { gossip_debug(GOSSIP_ACL_DEBUG, "pvfs2_set_acl: ACL options disabled on" "this FS!\n"); return 0; } switch (type) { case ACL_TYPE_ACCESS: { name = PVFS2_XATTR_NAME_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; /* can we represent this with the UNIXy permission bits? */ error = posix_acl_equiv_mode(acl, &mode); /* uh oh some error.. */ if (error < 0) { gossip_err("pvfs2_set_acl: posix_acl_equiv_mode error %d\n", error); return error; } else /* okay, go ahead and do just that */ { if (inode->i_mode != mode) SetModeFlag(pvfs2_inode); inode->i_mode = mode; mark_inode_dirty_sync(inode); if (error == 0) /* equivalent. so dont set acl! */ acl = NULL; } } break; } case ACL_TYPE_DEFAULT: { name = PVFS2_XATTR_NAME_ACL_DEFAULT; /* Default ACLs cannot be set/modified for non-directory objects! */ if (!S_ISDIR(inode->i_mode)) { gossip_debug(GOSSIP_ACL_DEBUG, "pvfs2_set_acl: setting default " "ACLs on non-dir object? %s\n", acl ? "disallowed" : "ok"); return acl ? -EACCES : 0; } break; } default: { gossip_err("pvfs2_set_acl: invalid type %d!\n", type); return -EINVAL; } } gossip_debug(GOSSIP_ACL_DEBUG, "pvfs2_set_acl: inode %llu, key %s type %d\n", llu(get_handle_from_ino(inode)), name, type); /* If we do have an access control list, then we need to encode that! */ if (acl) { value = pvfs2_acl_encode(acl, &size); if (IS_ERR(value)) { return (int) PTR_ERR(value); } } gossip_debug(GOSSIP_ACL_DEBUG, "pvfs2_set_acl: name %s, value %p, size %zd, " " acl %p\n", name, value, size, acl); /* Go ahead and set the extended attribute now * NOTE: Suppose acl was NULL, then value will be NULL and * size will be 0 and that will xlate to a removexattr. * However, we dont want removexattr complain if attributes * does not exist. */ error = pvfs2_inode_setxattr(inode, "", name, value, size, 0); if (value) { kfree(value); } return error; }
/* * inode->i_sem: down, or inode is just being initialized * BKL: held */ static int ext3_do_set_acl(handle_t *handle, struct inode *inode, int type, struct posix_acl *acl) { struct ext3_inode_info *ei = EXT3_I(inode); int name_index; void *value = NULL; size_t size; int error; if (S_ISLNK(inode->i_mode)) return -ENODATA; switch(type) { case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; else { inode->i_mode = mode; ext3_mark_inode_dirty(handle, inode); if (error == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { if (acl->a_count > EXT3_ACL_MAX_ENTRIES) return -EINVAL; value = ext3_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); } error = ext3_xattr_set_handle(handle, inode, name_index, "", value, size, 0); if (value) kfree(value); if (!error) { switch(type) { case ACL_TYPE_ACCESS: if (ei->i_acl != EXT3_ACL_NOT_CACHED) posix_acl_release(ei->i_acl); ei->i_acl = posix_acl_dup(acl); break; case ACL_TYPE_DEFAULT: if (ei->i_default_acl != EXT3_ACL_NOT_CACHED) posix_acl_release(ei->i_default_acl); ei->i_default_acl = posix_acl_dup(acl); break; } } return error; }
/* * inode->i_mutex: down */ static int ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) { struct ext2_inode_info *ei = EXT2_I(inode); int name_index; void *value = NULL; size_t size = 0; int error; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; if (!test_opt(inode->i_sb, POSIX_ACL)) return 0; switch(type) { case ACL_TYPE_ACCESS: name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; else { inode->i_mode = mode; mark_inode_dirty(inode); if (error == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = ext2_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); } error = ext2_xattr_set(inode, name_index, "", value, size, 0); kfree(value); if (!error) { switch(type) { case ACL_TYPE_ACCESS: ext2_iset_acl(inode, &ei->i_acl, acl); break; case ACL_TYPE_DEFAULT: ext2_iset_acl(inode, &ei->i_default_acl, acl); break; } } return error; }
int ceph_pre_init_acls(struct inode *dir, umode_t *mode, struct ceph_acls_info *info) { struct posix_acl *acl, *default_acl; size_t val_size1 = 0, val_size2 = 0; struct ceph_pagelist *pagelist = NULL; void *tmp_buf = NULL; int err; err = posix_acl_create(dir, mode, &default_acl, &acl); if (err) return err; if (acl) { int ret = posix_acl_equiv_mode(acl, mode); if (ret < 0) goto out_err; if (ret == 0) { posix_acl_release(acl); acl = NULL; } } if (!default_acl && !acl) return 0; if (acl) val_size1 = posix_acl_xattr_size(acl->a_count); if (default_acl) val_size2 = posix_acl_xattr_size(default_acl->a_count); err = -ENOMEM; tmp_buf = kmalloc(max(val_size1, val_size2), GFP_KERNEL); if (!tmp_buf) goto out_err; pagelist = kmalloc(sizeof(struct ceph_pagelist), GFP_KERNEL); if (!pagelist) goto out_err; ceph_pagelist_init(pagelist); err = ceph_pagelist_reserve(pagelist, PAGE_SIZE); if (err) goto out_err; ceph_pagelist_encode_32(pagelist, acl && default_acl ? 2 : 1); if (acl) { size_t len = strlen(XATTR_NAME_POSIX_ACL_ACCESS); err = ceph_pagelist_reserve(pagelist, len + val_size1 + 8); if (err) goto out_err; ceph_pagelist_encode_string(pagelist, XATTR_NAME_POSIX_ACL_ACCESS, len); err = posix_acl_to_xattr(&init_user_ns, acl, tmp_buf, val_size1); if (err < 0) goto out_err; ceph_pagelist_encode_32(pagelist, val_size1); ceph_pagelist_append(pagelist, tmp_buf, val_size1); } if (default_acl) { size_t len = strlen(XATTR_NAME_POSIX_ACL_DEFAULT); err = ceph_pagelist_reserve(pagelist, len + val_size2 + 8); if (err) goto out_err; err = ceph_pagelist_encode_string(pagelist, XATTR_NAME_POSIX_ACL_DEFAULT, len); err = posix_acl_to_xattr(&init_user_ns, default_acl, tmp_buf, val_size2); if (err < 0) goto out_err; ceph_pagelist_encode_32(pagelist, val_size2); ceph_pagelist_append(pagelist, tmp_buf, val_size2); } kfree(tmp_buf); info->acl = acl; info->default_acl = default_acl; info->pagelist = pagelist; return 0; out_err: posix_acl_release(acl); posix_acl_release(default_acl); kfree(tmp_buf); if (pagelist) ceph_pagelist_release(pagelist); return err; }
int zpl_set_acl(struct inode *ip, int type, struct posix_acl *acl) { struct super_block *sb = ITOZSB(ip)->z_sb; char *name, *value = NULL; int error = 0; size_t size = 0; if (S_ISLNK(ip->i_mode)) return (-EOPNOTSUPP); switch(type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { zpl_equivmode_t mode = ip->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error < 0) { return (error); } else { /* * The mode bits will have been set by * ->zfs_setattr()->zfs_acl_chmod_setattr() * using the ZFS ACL conversion. If they * differ from the Posix ACL conversion dirty * the inode to write the Posix mode bits. */ if (ip->i_mode != mode) { ip->i_mode = mode; ip->i_ctime = current_fs_time(sb); mark_inode_dirty(ip); } if (error == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name = POSIX_ACL_XATTR_DEFAULT; if (!S_ISDIR(ip->i_mode)) return (acl ? -EACCES : 0); break; default: return (-EINVAL); } if (acl) { size = posix_acl_xattr_size(acl->a_count); value = kmem_alloc(size, KM_SLEEP); error = zpl_acl_to_xattr(acl, value, size); if (error < 0) { kmem_free(value, size); return (error); } } error = zpl_xattr_set(ip, name, value, size, 0); if (value) kmem_free(value, size); if (!error) { if (acl) zpl_set_cached_acl(ip, type, acl); else zpl_forget_cached_acl(ip, type); } return (error); }
int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type) { int ret = 0, size = 0; const char *name = NULL; char *value = NULL; struct iattr newattrs; umode_t new_mode = inode->i_mode, old_mode = inode->i_mode; struct dentry *dentry; switch (type) { case ACL_TYPE_ACCESS: name = XATTR_NAME_POSIX_ACL_ACCESS; if (acl) { ret = posix_acl_equiv_mode(acl, &new_mode); if (ret < 0) goto out; if (ret == 0) acl = NULL; } break; case ACL_TYPE_DEFAULT: if (!S_ISDIR(inode->i_mode)) { ret = acl ? -EINVAL : 0; goto out; } name = XATTR_NAME_POSIX_ACL_DEFAULT; break; default: ret = -EINVAL; goto out; } if (acl) { size = posix_acl_xattr_size(acl->a_count); value = kmalloc(size, GFP_NOFS); if (!value) { ret = -ENOMEM; goto out; } ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); if (ret < 0) goto out_free; } dentry = d_find_alias(inode); if (new_mode != old_mode) { newattrs.ia_mode = new_mode; newattrs.ia_valid = ATTR_MODE; ret = ceph_setattr(dentry, &newattrs); if (ret) goto out_dput; } ret = __ceph_setxattr(dentry, name, value, size, 0); if (ret) { if (new_mode != old_mode) { newattrs.ia_mode = old_mode; newattrs.ia_valid = ATTR_MODE; ceph_setattr(dentry, &newattrs); } goto out_dput; } ceph_set_cached_acl(inode, type, acl); out_dput: dput(dentry); out_free: kfree(value); out: return ret; }
static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { int retval; struct posix_acl *acl; struct v9fs_session_info *v9ses; struct inode *inode = dentry->d_inode; if (strcmp(name, "") != 0) return -EINVAL; v9ses = v9fs_dentry2v9ses(dentry); /* * set the attribute on the remote. Without even looking at the * xattr value. We leave it to the server to validate */ if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) return v9fs_remote_set_acl(dentry, name, value, size, flags, type); if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; if (!inode_owner_or_capable(inode)) return -EPERM; if (value) { /* update the cached acl value */ acl = posix_acl_from_xattr(value, size); if (IS_ERR(acl)) return PTR_ERR(acl); else if (acl) { retval = posix_acl_valid(acl); if (retval) goto err_out; } } else acl = NULL; switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { mode_t mode = inode->i_mode; retval = posix_acl_equiv_mode(acl, &mode); if (retval < 0) goto err_out; else { struct iattr iattr; if (retval == 0) { /* * ACL can be represented * by the mode bits. So don't * update ACL. */ acl = NULL; value = NULL; size = 0; } /* Updte the mode bits */ iattr.ia_mode = ((mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO)); iattr.ia_valid = ATTR_MODE; /* FIXME should we update ctime ? * What is the following setxattr update the * mode ? */ v9fs_vfs_setattr_dotl(dentry, &iattr); } } break; case ACL_TYPE_DEFAULT: name = POSIX_ACL_XATTR_DEFAULT; if (!S_ISDIR(inode->i_mode)) { retval = acl ? -EINVAL : 0; goto err_out; } break; default: BUG(); } retval = v9fs_xattr_set(dentry, name, value, size, flags); if (!retval) set_cached_acl(inode, type, acl); err_out: posix_acl_release(acl); return retval; }
/* * Inode operation set_posix_acl(). * * inode->i_mutex: down * BKL held [before 2.5.x] */ static int reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, int type, struct posix_acl *acl) { char *name; void *value = NULL; size_t size = 0; int error; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { error = posix_acl_equiv_mode(acl, &inode->i_mode); if (error < 0) return error; else { if (error == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name = POSIX_ACL_XATTR_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = posix_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); } error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0); /* * Ensure that the inode gets dirtied if we're only using * the mode bits and an old ACL didn't exist. We don't need * to check if the inode is hashed here since we won't get * called by reiserfs_inherit_default_acl(). */ if (error == -ENODATA) { error = 0; if (type == ACL_TYPE_ACCESS) { inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); } } kfree(value); if (!error) set_cached_acl(inode, type, acl); return error; }
static int xfs_xattr_system_set(struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct posix_acl *acl = NULL; int error = 0, type; type = xfs_decode_acl(name); if (type < 0) return type; if (flags & XATTR_CREATE) return -EINVAL; if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) return value ? -EACCES : 0; if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; if (!value) goto set_acl; acl = posix_acl_from_xattr(value, size); if (!acl) { /* * acl_set_file(3) may request that we set default ACLs with * zero length -- defend (gracefully) against that here. */ goto out; } if (IS_ERR(acl)) { error = PTR_ERR(acl); goto out; } error = posix_acl_valid(acl); if (error) goto out_release; error = -EINVAL; if (acl->a_count > XFS_ACL_MAX_ENTRIES) goto out_release; if (type == ACL_TYPE_ACCESS) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error <= 0) { posix_acl_release(acl); acl = NULL; if (error < 0) return error; } error = xfs_set_mode(inode, mode); if (error) goto out_release; } set_acl: error = xfs_set_acl(inode, type, acl); out_release: posix_acl_release(acl); out: return error; }