xattr.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,455 行 · 第 1/3 页
C
1,455 行
* inode->i_sem: down */intreiserfs_xattr_set (struct inode *inode, const char *name, const void *buffer, 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 (IS_RDONLY (inode)) return -EROFS; if (IS_IMMUTABLE (inode) || IS_APPEND (inode)) return -EPERM; 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_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; down (&xinode->i_sem); err = notify_change(fp->f_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 = mapping->a_ops->prepare_write (fp, page, page_offset, page_offset + chunk + skip); if (!err) { if (buffer) memcpy (data + skip, buffer + buffer_pos, chunk); err = mapping->a_ops->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; mark_inode_dirty (inode); }out_filp: up (&xinode->i_sem); fput(fp);out: return err;}/* * inode->i_sem: 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_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;}intreiserfs_xattr_del (struct inode *inode, const char *name){ struct dentry *dir; int err; if (IS_RDONLY (inode)) return -EROFS; 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; 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, ino_t ino, unsigned int d_type){ struct dentry *xadir = (struct dentry *)buf; return __reiserfs_xattr_del (xadir, name, namelen);}/* This is called w/ inode->i_sem downed */intreiserfs_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); 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, ino_t 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;}intreiserfs_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 ();out_dir: fput(fp);out: attrs->ia_valid = ia_valid; return err;}/* Actual operations that are exported to VFS-land *//* * Inode operation getxattr() * Preliminary locking: we down dentry->d_inode->i_sem */ssize_treiserfs_getxattr (struct dentry *dentry, const char *name, void *buffer, size_t size){ struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix (name); int err; if (!xah || !reiserfs_xattrs(dentry->d_sb) || get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1) return -EOPNOTSUPP; reiserfs_read_lock_xattr_i (dentry->d_inode); reiserfs_read_lock_xattrs (dentry->d_sb); err = xah->get (dentry->d_inode, name, buffer, size); reiserfs_read_unlock_xattrs (dentry->d_sb); reiserfs_read_unlock_xattr_i (dentry->d_inode); return err;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?