|
@@ -50,9 +50,6 @@
|
|
|
#define PRIVROOT_NAME ".reiserfs_priv"
|
|
|
#define XAROOT_NAME "xattrs"
|
|
|
|
|
|
-static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
|
|
|
- *prefix);
|
|
|
-
|
|
|
/* Returns the dentry referring to the root of the extended attribute
|
|
|
* directory tree. If it has already been retrieved, it is used. If it
|
|
|
* hasn't been created and the flags indicate creation is allowed, we
|
|
@@ -143,60 +140,6 @@ static struct dentry *open_xa_dir(const struct inode *inode, int flags)
|
|
|
return xadir;
|
|
|
}
|
|
|
|
|
|
-/* Returns a dentry corresponding to a specific extended attribute file
|
|
|
- * for the inode. If flags allow, the file is created. Otherwise, a
|
|
|
- * valid or negative dentry, or an error is returned. */
|
|
|
-static struct dentry *get_xa_file_dentry(const struct inode *inode,
|
|
|
- const char *name, int flags)
|
|
|
-{
|
|
|
- struct dentry *xadir, *xafile;
|
|
|
- int err = 0;
|
|
|
-
|
|
|
- xadir = open_xa_dir(inode, flags);
|
|
|
- if (IS_ERR(xadir)) {
|
|
|
- return ERR_CAST(xadir);
|
|
|
- } else if (!xadir->d_inode) {
|
|
|
- dput(xadir);
|
|
|
- return ERR_PTR(-ENODATA);
|
|
|
- }
|
|
|
-
|
|
|
- xafile = lookup_one_len(name, xadir, strlen(name));
|
|
|
- if (IS_ERR(xafile)) {
|
|
|
- dput(xadir);
|
|
|
- return ERR_CAST(xafile);
|
|
|
- }
|
|
|
-
|
|
|
- if (xafile->d_inode) { /* file exists */
|
|
|
- if (flags & XATTR_CREATE) {
|
|
|
- err = -EEXIST;
|
|
|
- dput(xafile);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- } else if (flags & XATTR_REPLACE || flags & FL_READONLY) {
|
|
|
- goto out;
|
|
|
- } else {
|
|
|
- /* inode->i_mutex is down, so nothing else can try to create
|
|
|
- * the same xattr */
|
|
|
- err = xadir->d_inode->i_op->create(xadir->d_inode, xafile,
|
|
|
- 0700 | S_IFREG, NULL);
|
|
|
-
|
|
|
- if (err) {
|
|
|
- dput(xafile);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- out:
|
|
|
- dput(xadir);
|
|
|
- if (err)
|
|
|
- xafile = ERR_PTR(err);
|
|
|
- else if (!xafile->d_inode) {
|
|
|
- dput(xafile);
|
|
|
- xafile = ERR_PTR(-ENODATA);
|
|
|
- }
|
|
|
- return xafile;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but
|
|
|
* we need to drop the path before calling the filldir struct. That
|
|
@@ -369,6 +312,251 @@ int xattr_readdir(struct inode *inode, filldir_t filler, void *buf)
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
+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_PRIVATE(dentry->d_inode)) {
|
|
|
+ reiserfs_error(dir->i_sb, "jdm-20003",
|
|
|
+ "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_PRIVATE(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;
|
|
|
+}
|
|
|
+
|
|
|
+/* 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 int
|
|
|
+reiserfs_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 dentry *dir, *root;
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ /* Skip out, an xattr has no xattrs associated with it */
|
|
|
+ if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ lock_kernel();
|
|
|
+ err = xattr_readdir(dir->d_inode, 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, "jdm-20006",
|
|
|
+ "Couldn't remove all entries in directory");
|
|
|
+ }
|
|
|
+ unlock_kernel();
|
|
|
+
|
|
|
+out_dir:
|
|
|
+ dput(dir);
|
|
|
+
|
|
|
+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 int
|
|
|
+reiserfs_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 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_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ lock_kernel();
|
|
|
+
|
|
|
+ attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
|
|
|
+ buf.xadir = dir;
|
|
|
+ buf.attrs = attrs;
|
|
|
+ buf.inode = inode;
|
|
|
+
|
|
|
+ err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf);
|
|
|
+ if (err) {
|
|
|
+ unlock_kernel();
|
|
|
+ goto out_dir;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = notify_change(dir, attrs);
|
|
|
+ unlock_kernel();
|
|
|
+
|
|
|
+out_dir:
|
|
|
+ dput(dir);
|
|
|
+
|
|
|
+out:
|
|
|
+ attrs->ia_valid = ia_valid;
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef CONFIG_REISERFS_FS_XATTR
|
|
|
+static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
|
|
|
+ *prefix);
|
|
|
+
|
|
|
+/* Returns a dentry corresponding to a specific extended attribute file
|
|
|
+ * for the inode. If flags allow, the file is created. Otherwise, a
|
|
|
+ * valid or negative dentry, or an error is returned. */
|
|
|
+static struct dentry *get_xa_file_dentry(const struct inode *inode,
|
|
|
+ const char *name, int flags)
|
|
|
+{
|
|
|
+ struct dentry *xadir, *xafile;
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ xadir = open_xa_dir(inode, flags);
|
|
|
+ if (IS_ERR(xadir)) {
|
|
|
+ return ERR_CAST(xadir);
|
|
|
+ } else if (xadir && !xadir->d_inode) {
|
|
|
+ dput(xadir);
|
|
|
+ return ERR_PTR(-ENODATA);
|
|
|
+ }
|
|
|
+
|
|
|
+ xafile = lookup_one_len(name, xadir, strlen(name));
|
|
|
+ if (IS_ERR(xafile)) {
|
|
|
+ dput(xadir);
|
|
|
+ return ERR_CAST(xafile);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (xafile->d_inode) { /* file exists */
|
|
|
+ if (flags & XATTR_CREATE) {
|
|
|
+ err = -EEXIST;
|
|
|
+ dput(xafile);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ } else if (flags & XATTR_REPLACE || flags & FL_READONLY) {
|
|
|
+ goto out;
|
|
|
+ } else {
|
|
|
+ /* inode->i_mutex is down, so nothing else can try to create
|
|
|
+ * the same xattr */
|
|
|
+ err = xadir->d_inode->i_op->create(xadir->d_inode, xafile,
|
|
|
+ 0700 | S_IFREG, NULL);
|
|
|
+
|
|
|
+ if (err) {
|
|
|
+ dput(xafile);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
+ dput(xadir);
|
|
|
+ if (err)
|
|
|
+ xafile = ERR_PTR(err);
|
|
|
+ else if (!xafile->d_inode) {
|
|
|
+ dput(xafile);
|
|
|
+ xafile = ERR_PTR(-ENODATA);
|
|
|
+ }
|
|
|
+ return xafile;
|
|
|
+}
|
|
|
+
|
|
|
/* Internal operations on file data */
|
|
|
static inline void reiserfs_put_page(struct page *page)
|
|
|
{
|
|
@@ -554,274 +742,85 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
|
|
|
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(dentry->d_inode, file_pos);
|
|
|
- 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, "jdm-20001",
|
|
|
- "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, "jdm-20002",
|
|
|
- "Invalid hash for xattr (%s) associated "
|
|
|
- "with %k", name, INODE_PKEY(inode));
|
|
|
- err = -EIO;
|
|
|
- }
|
|
|
-
|
|
|
- out_dput:
|
|
|
- dput(dentry);
|
|
|
-
|
|
|
- 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_PRIVATE(dentry->d_inode)) {
|
|
|
- reiserfs_error(dir->i_sb, "jdm-20003",
|
|
|
- "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_PRIVATE(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 int
|
|
|
-reiserfs_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 dentry *dir, *root;
|
|
|
- int err = 0;
|
|
|
-
|
|
|
- /* Skip out, an xattr has no xattrs associated with it */
|
|
|
- if (IS_PRIVATE(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;
|
|
|
- }
|
|
|
-
|
|
|
- lock_kernel();
|
|
|
- err = xattr_readdir(dir->d_inode, 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, "jdm-20006",
|
|
|
- "Couldn't remove all entries in directory");
|
|
|
- }
|
|
|
- unlock_kernel();
|
|
|
-
|
|
|
- out_dir:
|
|
|
- dput(dir);
|
|
|
-
|
|
|
- out:
|
|
|
- if (!err)
|
|
|
- REISERFS_I(inode)->i_flags =
|
|
|
- REISERFS_I(inode)->i_flags & ~i_has_xattr_dir;
|
|
|
- return err;
|
|
|
-}
|
|
|
+ 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;
|
|
|
|
|
|
-struct reiserfs_chown_buf {
|
|
|
- struct inode *inode;
|
|
|
- struct dentry *xadir;
|
|
|
- struct iattr *attrs;
|
|
|
-};
|
|
|
+ page = reiserfs_get_page(dentry->d_inode, file_pos);
|
|
|
+ if (IS_ERR(page)) {
|
|
|
+ err = PTR_ERR(page);
|
|
|
+ goto out_dput;
|
|
|
+ }
|
|
|
|
|
|
-/* XXX: If there is a better way to do this, I'd love to hear about it */
|
|
|
-static int
|
|
|
-reiserfs_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;
|
|
|
+ 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, "jdm-20001",
|
|
|
+ "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);
|
|
|
|
|
|
- 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 (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) !=
|
|
|
+ hash) {
|
|
|
+ reiserfs_warning(inode->i_sb, "jdm-20002",
|
|
|
+ "Invalid hash for xattr (%s) associated "
|
|
|
+ "with %k", name, INODE_PKEY(inode));
|
|
|
+ err = -EIO;
|
|
|
}
|
|
|
|
|
|
- if (!S_ISDIR(xafile->d_inode->i_mode))
|
|
|
- err = notify_change(xafile, attrs);
|
|
|
- dput(xafile);
|
|
|
+out_dput:
|
|
|
+ dput(dentry);
|
|
|
|
|
|
+out:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
|
|
|
+int reiserfs_xattr_del(struct inode *inode, const char *name)
|
|
|
{
|
|
|
struct dentry *dir;
|
|
|
- int err = 0;
|
|
|
- struct reiserfs_chown_buf buf;
|
|
|
- unsigned int ia_valid = attrs->ia_valid;
|
|
|
+ int err;
|
|
|
|
|
|
- /* Skip out, an xattr has no xattrs associated with it */
|
|
|
- if (IS_PRIVATE(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);
|
|
|
+ err = PTR_ERR(dir);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- lock_kernel();
|
|
|
-
|
|
|
- attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
|
|
|
- buf.xadir = dir;
|
|
|
- buf.attrs = attrs;
|
|
|
- buf.inode = inode;
|
|
|
+ err = __reiserfs_xattr_del(dir, name, strlen(name));
|
|
|
+ dput(dir);
|
|
|
|
|
|
- err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf);
|
|
|
- if (err) {
|
|
|
- unlock_kernel();
|
|
|
- goto out_dir;
|
|
|
+ if (!err) {
|
|
|
+ inode->i_ctime = CURRENT_TIME_SEC;
|
|
|
+ mark_inode_dirty(inode);
|
|
|
}
|
|
|
|
|
|
- err = notify_change(dir, attrs);
|
|
|
- unlock_kernel();
|
|
|
-
|
|
|
- out_dir:
|
|
|
- dput(dir);
|
|
|
-
|
|
|
out:
|
|
|
- attrs->ia_valid = ia_valid;
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -1101,6 +1100,94 @@ void reiserfs_xattr_unregister_handlers(void)
|
|
|
write_unlock(&handler_lock);
|
|
|
}
|
|
|
|
|
|
+static int reiserfs_check_acl(struct inode *inode, int mask)
|
|
|
+{
|
|
|
+ struct posix_acl *acl;
|
|
|
+ int error = -EAGAIN; /* do regular unix permission checks by default */
|
|
|
+
|
|
|
+ reiserfs_read_lock_xattr_i(inode);
|
|
|
+ reiserfs_read_lock_xattrs(inode->i_sb);
|
|
|
+
|
|
|
+ acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
|
|
|
+
|
|
|
+ reiserfs_read_unlock_xattrs(inode->i_sb);
|
|
|
+ reiserfs_read_unlock_xattr_i(inode);
|
|
|
+
|
|
|
+ if (acl) {
|
|
|
+ if (!IS_ERR(acl)) {
|
|
|
+ error = posix_acl_permission(inode, acl, mask);
|
|
|
+ posix_acl_release(acl);
|
|
|
+ } else if (PTR_ERR(acl) != -ENODATA)
|
|
|
+ error = PTR_ERR(acl);
|
|
|
+ }
|
|
|
+
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+int reiserfs_permission(struct inode *inode, int mask)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * We don't do permission checks on the internal objects.
|
|
|
+ * Permissions are determined by the "owning" object.
|
|
|
+ */
|
|
|
+ if (IS_PRIVATE(inode))
|
|
|
+ return 0;
|
|
|
+ /*
|
|
|
+ * Stat data v1 doesn't support ACLs.
|
|
|
+ */
|
|
|
+ if (get_inode_sd_version(inode) == STAT_DATA_V1)
|
|
|
+ return generic_permission(inode, mask, NULL);
|
|
|
+ else
|
|
|
+ return generic_permission(inode, mask, reiserfs_check_acl);
|
|
|
+}
|
|
|
+
|
|
|
+static int create_privroot(struct dentry *dentry)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ struct inode *inode = dentry->d_parent->d_inode;
|
|
|
+ mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR);
|
|
|
+ err = inode->i_op->mkdir(inode, dentry, 0700);
|
|
|
+ mutex_unlock(&inode->i_mutex);
|
|
|
+ if (err) {
|
|
|
+ dput(dentry);
|
|
|
+ dentry = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dentry && dentry->d_inode)
|
|
|
+ reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr "
|
|
|
+ "storage.\n", PRIVROOT_NAME);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int xattr_mount_check(struct super_block *s)
|
|
|
+{
|
|
|
+ /* We need generation numbers to ensure that the oid mapping is correct
|
|
|
+ * v3.5 filesystems don't have them. */
|
|
|
+ if (!old_format_only(s)) {
|
|
|
+ set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
|
|
+ } else if (reiserfs_xattrs_optional(s)) {
|
|
|
+ /* Old format filesystem, but optional xattrs have been enabled
|
|
|
+ * at mount time. Error out. */
|
|
|
+ reiserfs_warning(s, "jdm-20005",
|
|
|
+ "xattrs/ACLs not supported on pre v3.6 "
|
|
|
+ "format filesystem. Failing mount.");
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ } else {
|
|
|
+ /* Old format filesystem, but no optional xattrs have
|
|
|
+ * been enabled. This means we silently disable xattrs
|
|
|
+ * on the filesystem. */
|
|
|
+ clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#else
|
|
|
+int __init reiserfs_xattr_register_handlers(void) { return 0; }
|
|
|
+void reiserfs_xattr_unregister_handlers(void) {}
|
|
|
+#endif
|
|
|
+
|
|
|
/* This will catch lookups from the fs root to .reiserfs_priv */
|
|
|
static int
|
|
|
xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name)
|
|
@@ -1127,47 +1214,23 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
|
|
|
{
|
|
|
int err = 0;
|
|
|
|
|
|
- /* We need generation numbers to ensure that the oid mapping is correct
|
|
|
- * v3.5 filesystems don't have them. */
|
|
|
- if (!old_format_only(s)) {
|
|
|
- set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
|
|
- } else if (reiserfs_xattrs_optional(s)) {
|
|
|
- /* Old format filesystem, but optional xattrs have been enabled
|
|
|
- * at mount time. Error out. */
|
|
|
- reiserfs_warning(s, "jdm-20005",
|
|
|
- "xattrs/ACLs not supported on pre v3.6 "
|
|
|
- "format filesystem. Failing mount.");
|
|
|
- err = -EOPNOTSUPP;
|
|
|
+#ifdef CONFIG_REISERFS_FS_XATTR
|
|
|
+ err = xattr_mount_check(s);
|
|
|
+ if (err)
|
|
|
goto error;
|
|
|
- } else {
|
|
|
- /* Old format filesystem, but no optional xattrs have been enabled. This
|
|
|
- * means we silently disable xattrs on the filesystem. */
|
|
|
- clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
|
|
- }
|
|
|
+#endif
|
|
|
|
|
|
/* If we don't have the privroot located yet - go find it */
|
|
|
- if (reiserfs_xattrs(s) && !REISERFS_SB(s)->priv_root) {
|
|
|
+ if (!REISERFS_SB(s)->priv_root) {
|
|
|
struct dentry *dentry;
|
|
|
dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
|
|
|
strlen(PRIVROOT_NAME));
|
|
|
if (!IS_ERR(dentry)) {
|
|
|
- if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) {
|
|
|
- struct inode *inode = dentry->d_parent->d_inode;
|
|
|
- mutex_lock_nested(&inode->i_mutex,
|
|
|
- I_MUTEX_XATTR);
|
|
|
- err = inode->i_op->mkdir(inode, dentry, 0700);
|
|
|
- mutex_unlock(&inode->i_mutex);
|
|
|
- if (err) {
|
|
|
- dput(dentry);
|
|
|
- dentry = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (dentry && dentry->d_inode)
|
|
|
- reiserfs_info(s, "Created %s - "
|
|
|
- "reserved for xattr "
|
|
|
- "storage.\n",
|
|
|
- PRIVROOT_NAME);
|
|
|
- } else if (!dentry->d_inode) {
|
|
|
+#ifdef CONFIG_REISERFS_FS_XATTR
|
|
|
+ if (!(mount_flags & MS_RDONLY) && !dentry->d_inode)
|
|
|
+ err = create_privroot(dentry);
|
|
|
+#endif
|
|
|
+ if (!dentry->d_inode) {
|
|
|
dput(dentry);
|
|
|
dentry = NULL;
|
|
|
}
|
|
@@ -1178,73 +1241,37 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
|
|
|
s->s_root->d_op = &xattr_lookup_poison_ops;
|
|
|
dentry->d_inode->i_flags |= S_PRIVATE;
|
|
|
REISERFS_SB(s)->priv_root = dentry;
|
|
|
- } else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */
|
|
|
- /* If we're read-only it just means that the dir hasn't been
|
|
|
- * created. Not an error -- just no xattrs on the fs. We'll
|
|
|
- * check again if we go read-write */
|
|
|
+#ifdef CONFIG_REISERFS_FS_XATTR
|
|
|
+ /* xattrs are unavailable */
|
|
|
+ } else if (!(mount_flags & MS_RDONLY)) {
|
|
|
+ /* If we're read-only it just means that the dir
|
|
|
+ * hasn't been created. Not an error -- just no
|
|
|
+ * xattrs on the fs. We'll check again if we
|
|
|
+ * go read-write */
|
|
|
reiserfs_warning(s, "jdm-20006",
|
|
|
"xattrs/ACLs enabled and couldn't "
|
|
|
"find/create .reiserfs_priv. "
|
|
|
"Failing mount.");
|
|
|
err = -EOPNOTSUPP;
|
|
|
+#endif
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- error:
|
|
|
- /* This is only nonzero if there was an error initializing the xattr
|
|
|
- * directory or if there is a condition where we don't support them. */
|
|
|
+#ifdef CONFIG_REISERFS_FS_XATTR
|
|
|
+error:
|
|
|
if (err) {
|
|
|
clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
|
|
|
clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt));
|
|
|
clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt));
|
|
|
}
|
|
|
+#endif
|
|
|
|
|
|
/* The super_block MS_POSIXACL must mirror the (no)acl mount option. */
|
|
|
s->s_flags = s->s_flags & ~MS_POSIXACL;
|
|
|
+#ifdef CONFIG_REISERFS_FS_POSIX_ACL
|
|
|
if (reiserfs_posixacl(s))
|
|
|
s->s_flags |= MS_POSIXACL;
|
|
|
+#endif
|
|
|
|
|
|
return err;
|
|
|
}
|
|
|
-
|
|
|
-static int reiserfs_check_acl(struct inode *inode, int mask)
|
|
|
-{
|
|
|
- struct posix_acl *acl;
|
|
|
- int error = -EAGAIN; /* do regular unix permission checks by default */
|
|
|
-
|
|
|
- reiserfs_read_lock_xattr_i(inode);
|
|
|
- reiserfs_read_lock_xattrs(inode->i_sb);
|
|
|
-
|
|
|
- acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
|
|
|
-
|
|
|
- reiserfs_read_unlock_xattrs(inode->i_sb);
|
|
|
- reiserfs_read_unlock_xattr_i(inode);
|
|
|
-
|
|
|
- if (acl) {
|
|
|
- if (!IS_ERR(acl)) {
|
|
|
- error = posix_acl_permission(inode, acl, mask);
|
|
|
- posix_acl_release(acl);
|
|
|
- } else if (PTR_ERR(acl) != -ENODATA)
|
|
|
- error = PTR_ERR(acl);
|
|
|
- }
|
|
|
-
|
|
|
- return error;
|
|
|
-}
|
|
|
-
|
|
|
-int reiserfs_permission(struct inode *inode, int mask)
|
|
|
-{
|
|
|
- /*
|
|
|
- * We don't do permission checks on the internal objects.
|
|
|
- * Permissions are determined by the "owning" object.
|
|
|
- */
|
|
|
- if (IS_PRIVATE(inode))
|
|
|
- return 0;
|
|
|
-
|
|
|
- /*
|
|
|
- * Stat data v1 doesn't support ACLs.
|
|
|
- */
|
|
|
- if (get_inode_sd_version(inode) == STAT_DATA_V1)
|
|
|
- return generic_permission(inode, mask, NULL);
|
|
|
- else
|
|
|
- return generic_permission(inode, mask, reiserfs_check_acl);
|
|
|
-}
|