STATIC int linvfs_removexattr( struct dentry *dentry, const char *name) { int error; int xflags = 0; char *p = (char *)name; struct inode *inode = dentry->d_inode; vnode_t *vp = LINVFS_GET_VP(inode); if (strncmp(name, xfs_namespaces[SYSTEM_NAMES].name, xfs_namespaces[SYSTEM_NAMES].namelen) == 0) { error = -ENOATTR; p += xfs_namespaces[SYSTEM_NAMES].namelen; if (strcmp(p, POSIXACL_ACCESS) == 0) error = xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); else if (strcmp(p, POSIXACL_DEFAULT) == 0) error = xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT); else if (strcmp(p, POSIXCAP) == 0) error = xfs_cap_vremove(vp); return error; } if (strncmp(name, xfs_namespaces[ROOT_NAMES].name, xfs_namespaces[ROOT_NAMES].namelen) == 0) { if (!capable(CAP_SYS_ADMIN)) return -EPERM; xflags |= ATTR_ROOT; p += xfs_namespaces[ROOT_NAMES].namelen; VOP_ATTR_REMOVE(vp, p, xflags, NULL, error); return -error; } if (strncmp(name, xfs_namespaces[USER_NAMES].name, xfs_namespaces[USER_NAMES].namelen) == 0) { p += xfs_namespaces[USER_NAMES].namelen; if (!capable_user_xattr(inode)) return -EPERM; VOP_ATTR_REMOVE(vp, p, xflags, NULL, error); return -error; } return -ENOATTR; }
int xfs_cap_vremove( vnode_t *vp) { int error; VN_HOLD(vp); error = xfs_cap_allow_set(vp); if (!error) { VOP_ATTR_REMOVE(vp, SGI_CAP_LINUX, ATTR_ROOT, sys_cred, error); if (error == ENOATTR) error = 0; /* 'scool */ } VN_RELE(vp); return -error; }
STATIC int xfs_attrmulti_attr_remove( struct vnode *vp, char *name, __uint32_t flags) { int error; if (IS_RDONLY(&vp->v_inode)) return -EROFS; if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode)) return EPERM; VOP_ATTR_REMOVE(vp, name, flags, NULL, error); return error; }
int xfs_acl_vremove( vnode_t *vp, int kind) { int error; VN_HOLD(vp); error = xfs_acl_allow_set(vp, kind); if (!error) { VOP_ATTR_REMOVE(vp, kind == _ACL_TYPE_DEFAULT? SGI_ACL_DEFAULT: SGI_ACL_FILE, ATTR_ROOT, sys_cred, error); if (error == ENOATTR) error = 0; /* 'scool */ } VN_RELE(vp); return -error; }
STATIC int xfs_attrmulti_by_handle( xfs_mount_t *mp, unsigned long arg, struct file *parfilp, struct inode *parinode) { int error; xfs_attr_multiop_t *ops; xfs_fsop_attrmulti_handlereq_t am_hreq; struct inode *inode; vnode_t *vp; unsigned int i, size; error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, sizeof(xfs_fsop_attrmulti_handlereq_t), (xfs_fsop_handlereq_t *)&am_hreq, &vp, &inode); if (error) return -error; size = am_hreq.opcount * sizeof(attr_multiop_t); if (!size || size > 16 * PAGE_SIZE) { VN_RELE(vp); return -XFS_ERROR(E2BIG); } ops = (xfs_attr_multiop_t *)kmalloc(size, GFP_KERNEL); if (!ops) { VN_RELE(vp); return -XFS_ERROR(ENOMEM); } if (copy_from_user(ops, am_hreq.ops, size)) { kfree(ops); VN_RELE(vp); return -XFS_ERROR(EFAULT); } for (i = 0; i < am_hreq.opcount; i++) { switch(ops[i].am_opcode) { case ATTR_OP_GET: VOP_ATTR_GET(vp,ops[i].am_attrname, ops[i].am_attrvalue, &ops[i].am_length, ops[i].am_flags, NULL, ops[i].am_error); break; case ATTR_OP_SET: if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { ops[i].am_error = EPERM; break; } VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue, ops[i].am_length, ops[i].am_flags, NULL, ops[i].am_error); break; case ATTR_OP_REMOVE: if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { ops[i].am_error = EPERM; break; } VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags, NULL, ops[i].am_error); break; default: ops[i].am_error = EINVAL; } } if (copy_to_user(am_hreq.ops, ops, size)) error = -XFS_ERROR(EFAULT); kfree(ops); VN_RELE(vp); return error; }