📄 xattr.c
字号:
discard_metapage(ea_buf->mp); dbFree(inode, blkno, (s64) blocks_needed); goto clean_up; } goto size_check; } ea_buf->flag = EA_EXTENT; ea_buf->mp = read_metapage(inode, addressDXD(&ji->ea), lengthDXD(&ji->ea) << sb->s_blocksize_bits, 1); if (ea_buf->mp == NULL) { rc = -EIO; goto clean_up; } ea_buf->xattr = ea_buf->mp->data; ea_buf->max_size = (ea_size + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1); size_check: if (EALIST_SIZE(ea_buf->xattr) != ea_size) { printk(KERN_ERR "ea_get: invalid extended attribute\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, ea_buf->xattr, ea_size, 1); ea_release(inode, ea_buf); rc = -EIO; goto clean_up; } return ea_size; clean_up: /* Rollback quota allocation */ if (quota_allocation) DQUOT_FREE_BLOCK(inode, quota_allocation); return (rc);}static void ea_release(struct inode *inode, struct ea_buffer *ea_buf){ if (ea_buf->flag & EA_MALLOC) kfree(ea_buf->xattr); else if (ea_buf->flag & EA_EXTENT) { assert(ea_buf->mp); release_metapage(ea_buf->mp); if (ea_buf->flag & EA_NEW) dbFree(inode, addressDXD(&ea_buf->new_ea), lengthDXD(&ea_buf->new_ea)); }}static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf, int new_size){ struct jfs_inode_info *ji = JFS_IP(inode); unsigned long old_blocks, new_blocks; int rc = 0; if (new_size == 0) { ea_release(inode, ea_buf); ea_buf = NULL; } else if (ea_buf->flag & EA_INLINE) { assert(new_size <= sizeof (ji->i_inline_ea)); ji->mode2 &= ~INLINEEA; ea_buf->new_ea.flag = DXD_INLINE; DXDsize(&ea_buf->new_ea, new_size); DXDaddress(&ea_buf->new_ea, 0); DXDlength(&ea_buf->new_ea, 0); } else if (ea_buf->flag & EA_MALLOC) { rc = ea_write(inode, ea_buf->xattr, new_size, &ea_buf->new_ea); kfree(ea_buf->xattr); } else if (ea_buf->flag & EA_NEW) { /* We have already allocated a new dxd */ flush_metapage(ea_buf->mp); } else { /* ->xattr must point to original ea's metapage */ rc = ea_write(inode, ea_buf->xattr, new_size, &ea_buf->new_ea); discard_metapage(ea_buf->mp); } if (rc) return rc; old_blocks = new_blocks = 0; if (ji->ea.flag & DXD_EXTENT) { invalidate_dxd_metapages(inode, ji->ea); old_blocks = lengthDXD(&ji->ea); } if (ea_buf) { txEA(tid, inode, &ji->ea, &ea_buf->new_ea); if (ea_buf->new_ea.flag & DXD_EXTENT) { new_blocks = lengthDXD(&ea_buf->new_ea); if (ji->ea.flag & DXD_INLINE) ji->mode2 |= INLINEEA; } ji->ea = ea_buf->new_ea; } else { txEA(tid, inode, &ji->ea, NULL); if (ji->ea.flag & DXD_INLINE) ji->mode2 |= INLINEEA; ji->ea.flag = 0; ji->ea.size = 0; } /* If old blocks exist, they must be removed from quota allocation. */ if (old_blocks) DQUOT_FREE_BLOCK(inode, old_blocks); inode->i_ctime = CURRENT_TIME; return 0;}/* * can_set_system_xattr * * This code is specific to the system.* namespace. It contains policy * which doesn't belong in the main xattr codepath. */static int can_set_system_xattr(struct inode *inode, const char *name, const void *value, size_t value_len){#ifdef CONFIG_JFS_POSIX_ACL struct posix_acl *acl; int rc; if (!is_owner_or_cap(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(value, value_len); if (IS_ERR(acl)) { rc = PTR_ERR(acl); printk(KERN_ERR "posix_acl_from_xattr returned %d\n", rc); return rc; } if (acl) { mode_t mode = inode->i_mode; rc = posix_acl_equiv_mode(acl, &mode); posix_acl_release(acl); if (rc < 0) { printk(KERN_ERR "posix_acl_equiv_mode returned %d\n", rc); return rc; } inode->i_mode = mode; mark_inode_dirty(inode); } /* * We're changing the ACL. Get rid of the cached one */ acl =JFS_IP(inode)->i_acl; if (acl != JFS_ACL_NOT_CACHED) posix_acl_release(acl); JFS_IP(inode)->i_acl = JFS_ACL_NOT_CACHED; return 0; } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { acl = posix_acl_from_xattr(value, value_len); if (IS_ERR(acl)) { rc = PTR_ERR(acl); printk(KERN_ERR "posix_acl_from_xattr returned %d\n", rc); return rc; } posix_acl_release(acl); /* * We're changing the default ACL. Get rid of the cached one */ acl =JFS_IP(inode)->i_default_acl; if (acl && (acl != JFS_ACL_NOT_CACHED)) posix_acl_release(acl); JFS_IP(inode)->i_default_acl = JFS_ACL_NOT_CACHED; return 0; }#endif /* CONFIG_JFS_POSIX_ACL */ return -EOPNOTSUPP;}/* * Most of the permission checking is done by xattr_permission in the vfs. * The local file system is responsible for handling the system.* namespace. * We also need to verify that this is a namespace that we recognize. */static int can_set_xattr(struct inode *inode, const char *name, const void *value, size_t value_len){ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) return can_set_system_xattr(inode, name, value, value_len); /* * Don't allow setting an attribute in an unknown namespace. */ if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) return -EOPNOTSUPP; return 0;}int __jfs_setxattr(tid_t tid, struct inode *inode, const char *name, const void *value, size_t value_len, int flags){ struct jfs_ea_list *ealist; struct jfs_ea *ea, *old_ea = NULL, *next_ea = NULL; struct ea_buffer ea_buf; int old_ea_size = 0; int xattr_size; int new_size; int namelen = strlen(name); char *os2name = NULL; int found = 0; int rc; int length; if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1, GFP_KERNEL); if (!os2name) return -ENOMEM; strcpy(os2name, name + XATTR_OS2_PREFIX_LEN); name = os2name; namelen -= XATTR_OS2_PREFIX_LEN; } down_write(&JFS_IP(inode)->xattr_sem); xattr_size = ea_get(inode, &ea_buf, 0); if (xattr_size < 0) { rc = xattr_size; goto out; } again: ealist = (struct jfs_ea_list *) ea_buf.xattr; new_size = sizeof (struct jfs_ea_list); if (xattr_size) { for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) { if ((namelen == ea->namelen) && (memcmp(name, ea->name, namelen) == 0)) { found = 1; if (flags & XATTR_CREATE) { rc = -EEXIST; goto release; } old_ea = ea; old_ea_size = EA_SIZE(ea); next_ea = NEXT_EA(ea); } else new_size += EA_SIZE(ea); } } if (!found) { if (flags & XATTR_REPLACE) { rc = -ENODATA; goto release; } if (value == NULL) { rc = 0; goto release; } } if (value) new_size += sizeof (struct jfs_ea) + namelen + 1 + value_len; if (new_size > ea_buf.max_size) { /* * We need to allocate more space for merged ea list. * We should only have loop to again: once. */ ea_release(inode, &ea_buf); xattr_size = ea_get(inode, &ea_buf, new_size); if (xattr_size < 0) { rc = xattr_size; goto out; } goto again; } /* Remove old ea of the same name */ if (found) { /* number of bytes following target EA */ length = (char *) END_EALIST(ealist) - (char *) next_ea; if (length > 0) memmove(old_ea, next_ea, length); xattr_size -= old_ea_size; } /* Add new entry to the end */ if (value) { if (xattr_size == 0) /* Completely new ea list */ xattr_size = sizeof (struct jfs_ea_list); ea = (struct jfs_ea *) ((char *) ealist + xattr_size); ea->flag = 0; ea->namelen = namelen; ea->valuelen = (cpu_to_le16(value_len)); memcpy(ea->name, name, namelen); ea->name[namelen] = 0; if (value_len) memcpy(&ea->name[namelen + 1], value, value_len); xattr_size += EA_SIZE(ea); } /* DEBUG - If we did this right, these number match */ if (xattr_size != new_size) { printk(KERN_ERR "jfs_xsetattr: xattr_size = %d, new_size = %d\n", xattr_size, new_size); rc = -EINVAL; goto release; } /* * If we're left with an empty list, there's no ea */ if (new_size == sizeof (struct jfs_ea_list)) new_size = 0; ealist->size = cpu_to_le32(new_size); rc = ea_put(tid, inode, &ea_buf, new_size); goto out; release: ea_release(inode, &ea_buf); out: up_write(&JFS_IP(inode)->xattr_sem); kfree(os2name); return rc;}int jfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t value_len, int flags){ struct inode *inode = dentry->d_inode; struct jfs_inode_info *ji = JFS_IP(inode); int rc; tid_t tid; if ((rc = can_set_xattr(inode, name, value, value_len))) return rc; if (value == NULL) { /* empty EA, do not remove */ value = ""; value_len = 0; } tid = txBegin(inode->i_sb, 0); mutex_lock(&ji->commit_mutex); rc = __jfs_setxattr(tid, dentry->d_inode, name, value, value_len, flags); if (!rc) rc = txCommit(tid, 1, &inode, 0); txEnd(tid); mutex_unlock(&ji->commit_mutex); return rc;}ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, size_t buf_size){ struct jfs_ea_list *ealist; struct jfs_ea *ea; struct ea_buffer ea_buf; int xattr_size; ssize_t size; int namelen = strlen(name); char *os2name = NULL; char *value; if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1, GFP_KERNEL); if (!os2name) return -ENOMEM; strcpy(os2name, name + XATTR_OS2_PREFIX_LEN); name = os2name; namelen -= XATTR_OS2_PREFIX_LEN; } down_read(&JFS_IP(inode)->xattr_sem); xattr_size = ea_get(inode, &ea_buf, 0); if (xattr_size < 0) { size = xattr_size; goto out; } if (xattr_size == 0) goto not_found; ealist = (struct jfs_ea_list *) ea_buf.xattr; /* Find the named attribute */ for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) if ((namelen == ea->namelen) && memcmp(name, ea->name, namelen) == 0) { /* Found it */ size = le16_to_cpu(ea->valuelen); if (!data) goto release; else if (size > buf_size) { size = -ERANGE; goto release; } value = ((char *) &ea->name) + ea->namelen + 1; memcpy(data, value, size); goto release; } not_found: size = -ENODATA; release: ea_release(inode, &ea_buf); out: up_read(&JFS_IP(inode)->xattr_sem); kfree(os2name); return size;}ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data, size_t buf_size){ int err; err = __jfs_getxattr(dentry->d_inode, name, data, buf_size); return err;}/* * No special permissions are needed to list attributes except for trusted.* */static inline int can_list(struct jfs_ea *ea){ return (strncmp(ea->name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || capable(CAP_SYS_ADMIN));}ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size){ struct inode *inode = dentry->d_inode; char *buffer; ssize_t size = 0; int xattr_size; struct jfs_ea_list *ealist; struct jfs_ea *ea; struct ea_buffer ea_buf; down_read(&JFS_IP(inode)->xattr_sem); xattr_size = ea_get(inode, &ea_buf, 0); if (xattr_size < 0) { size = xattr_size; goto out; } if (xattr_size == 0) goto release; ealist = (struct jfs_ea_list *) ea_buf.xattr; /* compute required size of list */ for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) { if (can_list(ea)) size += name_size(ea) + 1; } if (!data) goto release; if (size > buf_size) { size = -ERANGE; goto release; } /* Copy attribute names to buffer */ buffer = data; for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) { if (can_list(ea)) { int namelen = copy_name(buffer, ea); buffer += namelen + 1; } } release: ea_release(inode, &ea_buf); out: up_read(&JFS_IP(inode)->xattr_sem); return size;}int jfs_removexattr(struct dentry *dentry, const char *name){ struct inode *inode = dentry->d_inode; struct jfs_inode_info *ji = JFS_IP(inode); int rc; tid_t tid; if ((rc = can_set_xattr(inode, name, NULL, 0))) return rc; tid = txBegin(inode->i_sb, 0); mutex_lock(&ji->commit_mutex); rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE); if (!rc) rc = txCommit(tid, 1, &inode, 0); txEnd(tid); mutex_unlock(&ji->commit_mutex); return rc;}#ifdef CONFIG_JFS_SECURITYint jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir){ int rc; size_t len; void *value; char *suffix; char *name; rc = security_inode_init_security(inode, dir, &suffix, &value, &len); if (rc) { if (rc == -EOPNOTSUPP) return 0; return rc; } name = kmalloc(XATTR_SECURITY_PREFIX_LEN + 1 + strlen(suffix), GFP_NOFS); if (!name) { rc = -ENOMEM; goto kmalloc_failed; } strcpy(name, XATTR_SECURITY_PREFIX); strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix); rc = __jfs_setxattr(tid, inode, name, value, len, 0); kfree(name);kmalloc_failed: kfree(suffix); kfree(value); return rc;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -