📄 xattr.c
字号:
size_t buffer_size, int flags){ int err = 0; struct file *fp; struct page *page; char *data; struct address_space *mapping; size_t file_pos = 0; size_t buffer_pos = 0; struct inode *xinode; struct iattr newattrs; __u32 xahash = 0; if (get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; /* Empty xattrs are ok, they're just empty files, no hash */ if (buffer && buffer_size) xahash = xattr_hash(buffer, buffer_size); open_file: fp = open_xa_file(inode, name, flags); if (IS_ERR(fp)) { err = PTR_ERR(fp); goto out; } xinode = fp->f_path.dentry->d_inode; REISERFS_I(inode)->i_flags |= i_has_xattr_dir; /* we need to copy it off.. */ if (xinode->i_nlink > 1) { fput(fp); err = reiserfs_xattr_del(inode, name); if (err < 0) goto out; /* We just killed the old one, we're not replacing anymore */ if (flags & XATTR_REPLACE) flags &= ~XATTR_REPLACE; goto open_file; } /* Resize it so we're ok to write there */ newattrs.ia_size = buffer_size; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR); err = notify_change(fp->f_path.dentry, &newattrs); if (err) goto out_filp; mapping = xinode->i_mapping; while (buffer_pos < buffer_size || buffer_pos == 0) { size_t chunk; size_t skip = 0; size_t page_offset = (file_pos & (PAGE_CACHE_SIZE - 1)); if (buffer_size - buffer_pos > PAGE_CACHE_SIZE) chunk = PAGE_CACHE_SIZE; else chunk = buffer_size - buffer_pos; page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT); if (IS_ERR(page)) { err = PTR_ERR(page); goto out_filp; } lock_page(page); data = page_address(page); if (file_pos == 0) { struct reiserfs_xattr_header *rxh; skip = file_pos = sizeof(struct reiserfs_xattr_header); if (chunk + skip > PAGE_CACHE_SIZE) chunk = PAGE_CACHE_SIZE - skip; rxh = (struct reiserfs_xattr_header *)data; rxh->h_magic = cpu_to_le32(REISERFS_XATTR_MAGIC); rxh->h_hash = cpu_to_le32(xahash); } err = reiserfs_prepare_write(fp, page, page_offset, page_offset + chunk + skip); if (!err) { if (buffer) memcpy(data + skip, buffer + buffer_pos, chunk); err = reiserfs_commit_write(fp, page, page_offset, page_offset + chunk + skip); } unlock_page(page); reiserfs_put_page(page); buffer_pos += chunk; file_pos += chunk; skip = 0; if (err || buffer_size == 0 || !buffer) break; } /* We can't mark the inode dirty if it's not hashed. This is the case * when we're inheriting the default ACL. If we dirty it, the inode * gets marked dirty, but won't (ever) make it onto the dirty list until * it's synced explicitly to clear I_DIRTY. This is bad. */ if (!hlist_unhashed(&inode->i_hash)) { inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); } out_filp: mutex_unlock(&xinode->i_mutex); fput(fp); out: return err;}/* * inode->i_mutex: down */intreiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, size_t buffer_size){ ssize_t err = 0; struct file *fp; size_t isize; size_t file_pos = 0; size_t buffer_pos = 0; struct page *page; struct inode *xinode; __u32 hash = 0; if (name == NULL) return -EINVAL; /* We can't have xattrs attached to v1 items since they don't have * generation numbers */ if (get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; fp = open_xa_file(inode, name, FL_READONLY); if (IS_ERR(fp)) { err = PTR_ERR(fp); goto out; } xinode = fp->f_path.dentry->d_inode; isize = xinode->i_size; REISERFS_I(inode)->i_flags |= i_has_xattr_dir; /* Just return the size needed */ if (buffer == NULL) { err = isize - sizeof(struct reiserfs_xattr_header); goto out_dput; } if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) { err = -ERANGE; goto out_dput; } while (file_pos < isize) { size_t chunk; char *data; size_t skip = 0; if (isize - file_pos > PAGE_CACHE_SIZE) chunk = PAGE_CACHE_SIZE; else chunk = isize - file_pos; page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT); if (IS_ERR(page)) { err = PTR_ERR(page); goto out_dput; } lock_page(page); data = page_address(page); if (file_pos == 0) { struct reiserfs_xattr_header *rxh = (struct reiserfs_xattr_header *)data; skip = file_pos = sizeof(struct reiserfs_xattr_header); chunk -= skip; /* Magic doesn't match up.. */ if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) { unlock_page(page); reiserfs_put_page(page); reiserfs_warning(inode->i_sb, "Invalid magic for xattr (%s) " "associated with %k", name, INODE_PKEY(inode)); err = -EIO; goto out_dput; } hash = le32_to_cpu(rxh->h_hash); } memcpy(buffer + buffer_pos, data + skip, chunk); unlock_page(page); reiserfs_put_page(page); file_pos += chunk; buffer_pos += chunk; skip = 0; } err = isize - sizeof(struct reiserfs_xattr_header); if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) != hash) { reiserfs_warning(inode->i_sb, "Invalid hash for xattr (%s) associated " "with %k", name, INODE_PKEY(inode)); err = -EIO; } out_dput: fput(fp); out: return err;}static int__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen){ struct dentry *dentry; struct inode *dir = xadir->d_inode; int err = 0; dentry = lookup_one_len(name, xadir, namelen); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); goto out; } else if (!dentry->d_inode) { err = -ENODATA; goto out_file; } /* Skip directories.. */ if (S_ISDIR(dentry->d_inode->i_mode)) goto out_file; if (!is_reiserfs_priv_object(dentry->d_inode)) { reiserfs_warning(dir->i_sb, "OID %08x [%.*s/%.*s] doesn't have " "priv flag set [parent is %sset].", le32_to_cpu(INODE_PKEY(dentry->d_inode)-> k_objectid), xadir->d_name.len, xadir->d_name.name, namelen, name, is_reiserfs_priv_object(xadir-> d_inode) ? "" : "not "); dput(dentry); return -EIO; } err = dir->i_op->unlink(dir, dentry); if (!err) d_delete(dentry); out_file: dput(dentry); out: return err;}int reiserfs_xattr_del(struct inode *inode, const char *name){ struct dentry *dir; int err; dir = open_xa_dir(inode, FL_READONLY); if (IS_ERR(dir)) { err = PTR_ERR(dir); goto out; } err = __reiserfs_xattr_del(dir, name, strlen(name)); dput(dir); if (!err) { inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); } out: return err;}/* The following are side effects of other operations that aren't explicitly * modifying extended attributes. This includes operations such as permissions * or ownership changes, object deletions, etc. */static intreiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned int d_type){ struct dentry *xadir = (struct dentry *)buf; return __reiserfs_xattr_del(xadir, name, namelen);}/* This is called w/ inode->i_mutex downed */int reiserfs_delete_xattrs(struct inode *inode){ struct file *fp; struct dentry *dir, *root; int err = 0; /* Skip out, an xattr has no xattrs associated with it */ if (is_reiserfs_priv_object(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 || !reiserfs_xattrs(inode->i_sb)) { return 0; } reiserfs_read_lock_xattrs(inode->i_sb); dir = open_xa_dir(inode, FL_READONLY); reiserfs_read_unlock_xattrs(inode->i_sb); if (IS_ERR(dir)) { err = PTR_ERR(dir); goto out; } else if (!dir->d_inode) { dput(dir); return 0; } fp = dentry_open(dir, NULL, O_RDWR); if (IS_ERR(fp)) { err = PTR_ERR(fp); /* dentry_open dputs the dentry if it fails */ goto out; } lock_kernel(); err = xattr_readdir(fp, reiserfs_delete_xattrs_filler, dir); if (err) { unlock_kernel(); goto out_dir; } /* Leftovers besides . and .. -- that's not good. */ if (dir->d_inode->i_nlink <= 2) { root = get_xa_root(inode->i_sb, XATTR_REPLACE); reiserfs_write_lock_xattrs(inode->i_sb); err = vfs_rmdir(root->d_inode, dir); reiserfs_write_unlock_xattrs(inode->i_sb); dput(root); } else { reiserfs_warning(inode->i_sb, "Couldn't remove all entries in directory"); } unlock_kernel(); out_dir: fput(fp); out: if (!err) REISERFS_I(inode)->i_flags = REISERFS_I(inode)->i_flags & ~i_has_xattr_dir; return err;}struct reiserfs_chown_buf { struct inode *inode; struct dentry *xadir; struct iattr *attrs;};/* XXX: If there is a better way to do this, I'd love to hear about it */static intreiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned int d_type){ struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; struct dentry *xafile, *xadir = chown_buf->xadir; struct iattr *attrs = chown_buf->attrs; int err = 0; xafile = lookup_one_len(name, xadir, namelen); if (IS_ERR(xafile)) return PTR_ERR(xafile); else if (!xafile->d_inode) { dput(xafile); return -ENODATA; } if (!S_ISDIR(xafile->d_inode->i_mode)) err = notify_change(xafile, attrs); dput(xafile); return err;}int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs){ struct file *fp; struct dentry *dir; int err = 0; struct reiserfs_chown_buf buf; unsigned int ia_valid = attrs->ia_valid; /* Skip out, an xattr has no xattrs associated with it */ if (is_reiserfs_priv_object(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 || !reiserfs_xattrs(inode->i_sb)) { return 0; } reiserfs_read_lock_xattrs(inode->i_sb); dir = open_xa_dir(inode, FL_READONLY); reiserfs_read_unlock_xattrs(inode->i_sb); if (IS_ERR(dir)) { if (PTR_ERR(dir) != -ENODATA) err = PTR_ERR(dir); goto out; } else if (!dir->d_inode) { dput(dir); goto out; } fp = dentry_open(dir, NULL, O_RDWR); if (IS_ERR(fp)) { err = PTR_ERR(fp); /* dentry_open dputs the dentry if it fails */ goto out; } lock_kernel(); attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); buf.xadir = dir; buf.attrs = attrs; buf.inode = inode; err = xattr_readdir(fp, reiserfs_chown_xattrs_filler, &buf); if (err) { unlock_kernel(); goto out_dir; } err = notify_change(dir, attrs); unlock_kernel();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -