📄 xattr.c
字号:
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_mutex */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;}/* * Inode operation setxattr() * * dentry->d_inode->i_mutex down */intreiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags){ struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); int err; int lock; if (!xah || !reiserfs_xattrs(dentry->d_sb) || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) return -EOPNOTSUPP; reiserfs_write_lock_xattr_i(dentry->d_inode); lock = !has_xattr_dir(dentry->d_inode); if (lock) reiserfs_write_lock_xattrs(dentry->d_sb); else reiserfs_read_lock_xattrs(dentry->d_sb); err = xah->set(dentry->d_inode, name, value, size, flags); if (lock) reiserfs_write_unlock_xattrs(dentry->d_sb); else reiserfs_read_unlock_xattrs(dentry->d_sb); reiserfs_write_unlock_xattr_i(dentry->d_inode); return err;}/* * Inode operation removexattr() * * dentry->d_inode->i_mutex down */int reiserfs_removexattr(struct dentry *dentry, const char *name){ int err; struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); if (!xah || !reiserfs_xattrs(dentry->d_sb) || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) return -EOPNOTSUPP; reiserfs_write_lock_xattr_i(dentry->d_inode); reiserfs_read_lock_xattrs(dentry->d_sb); /* Deletion pre-operation */ if (xah->del) { err = xah->del(dentry->d_inode, name); if (err) goto out; } err = reiserfs_xattr_del(dentry->d_inode, name); dentry->d_inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(dentry->d_inode); out: reiserfs_read_unlock_xattrs(dentry->d_sb); reiserfs_write_unlock_xattr_i(dentry->d_inode); return err;}/* This is what filldir will use: * r_pos will always contain the amount of space required for the entire * list. If r_pos becomes larger than r_size, we need more space and we * return an error indicating this. If r_pos is less than r_size, then we've * filled the buffer successfully and we return success */struct reiserfs_listxattr_buf { int r_pos; int r_size; char *r_buf; struct inode *r_inode;};static intreiserfs_listxattr_filler(void *buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned int d_type){ struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf; int len = 0; if (name[0] != '.' || (namelen != 1 && (name[1] != '.' || namelen != 2))) { struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); if (!xah) return 0; /* Unsupported xattr name, skip it */ /* We call ->list() twice because the operation isn't required to just * return the name back - we want to make sure we have enough space */ len += xah->list(b->r_inode, name, namelen, NULL); if (len) { if (b->r_pos + len + 1 <= b->r_size) { char *p = b->r_buf + b->r_pos; p += xah->list(b->r_inode, name, namelen, p); *p++ = '\0'; } b->r_pos += len + 1; } } return 0;}/* * Inode operation listxattr() * * Preliminary locking: we down dentry->d_inode->i_mutex */ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size){ struct file *fp; struct dentry *dir; int err = 0; struct reiserfs_listxattr_buf buf; if (!dentry->d_inode) return -EINVAL; if (!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); dir = open_xa_dir(dentry->d_inode, FL_READONLY); reiserfs_read_unlock_xattrs(dentry->d_sb); if (IS_ERR(dir)) { err = PTR_ERR(dir); if (err == -ENODATA) err = 0; /* Not an error if there aren't any xattrs */ 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; } buf.r_buf = buffer; buf.r_size = buffer ? size : 0; buf.r_pos = 0; buf.r_inode = dentry->d_inode; REISERFS_I(dentry->d_inode)->i_flags |= i_has_xattr_dir; err = xattr_readdir(fp, reiserfs_listxattr_filler, &buf); if (err) goto out_dir; if (buf.r_pos > buf.r_size && buffer != NULL) err = -ERANGE; else err = buf.r_pos; out_dir: fput(fp); out: reiserfs_read_unlock_xattr_i(dentry->d_inode); return err;}/* This is the implementation for the xattr plugin infrastructure */static struct list_head xattr_handlers = LIST_HEAD_INIT(xattr_handlers);static DEFINE_RWLOCK(handler_lock);static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char *prefix){ struct reiserfs_xattr_handler *xah = NULL; struct list_head *p; read_lock(&handler_lock); list_for_each(p, &xattr_handlers) { xah = list_entry(p, struct reiserfs_xattr_handler, handlers); if (strncmp(xah->prefix, prefix, strlen(xah->prefix)) == 0) break; xah = NULL; } read_unlock(&handler_lock); return xah;}static void __unregister_handlers(void){ struct reiserfs_xattr_handler *xah; struct list_head *p, *tmp; list_for_each_safe(p, tmp, &xattr_handlers) { xah = list_entry(p, struct reiserfs_xattr_handler, handlers); if (xah->exit) xah->exit(); list_del_init(p); } INIT_LIST_HEAD(&xattr_handlers);}int __init reiserfs_xattr_register_handlers(void){ int err = 0; struct reiserfs_xattr_handler *xah; struct list_head *p; write_lock(&handler_lock); /* If we're already initialized, nothing to do */ if (!list_empty(&xattr_handlers)) { write_unlock(&handler_lock); return 0; } /* Add the handlers */ list_add_tail(&user_handler.handlers, &xattr_handlers); list_add_tail(&trusted_handler.handlers, &xattr_handlers);#ifdef CONFIG_REISERFS_FS_SECURITY list_add_tail(&security_handler.handlers, &xattr_handlers);#endif#ifdef CONFIG_REISERFS_FS_POSIX_ACL list_add_tail(&posix_acl_access_handler.handlers, &xattr_handlers); list_add_tail(&posix_acl_default_handler.handlers, &xattr_handlers);#endif /* Run initializers, if available */ list_for_each(p, &xattr_handlers) { xah = list_entry(p, struct reiserfs_xattr_handler, handlers); if (xah->init) { err = xah->init(); if (err) { list_del_init(p); break; } } } /* Clean up other handlers, if any failed */ if (err) __unregister_handlers(); write_unlock(&handler_lock); return err;}void reiserfs_xattr_unregister_handlers(void){ write_lock(&handler_lock); __unregister_handlers(); write_unlock(&handler_lock);}/* This will catch lookups from the fs root to .reiserfs_priv */static intxattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name){ struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root; if (name->len == priv_root->d_name.len && name->hash == priv_root->d_name.hash && !memcmp(name->name, priv_root->d_name.name, name->len)) { return -ENOENT; } else if (q1->len == name->len && !memcmp(q1->name, name->name, name->len)) return 0; return 1;}static struct dentry_operations xattr_lookup_poison_ops = { .d_compare = xattr_lookup_poison,};/* We need to take a copy of the mount flags since things like * MS_RDONLY don't get set until *after* we're called. * mount_flags != mount_options */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, "xattrs/ACLs not supported on pre v3.6 " "format filesystem. Failing mount."); err = -EOPNOTSUPP; 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)); } /* If we don't have the privroot located yet - go find it */ if (reiserfs_xattrs(s) && !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_warning(s, "Created %s on %s - reserved for " "xattr storage.", PRIVROOT_NAME, reiserfs_bdevname (inode->i_sb)); } else if (!dentry->d_inode) { dput(dentry); dentry = NULL; } } else err = PTR_ERR(dentry); if (!err && dentry) { s->s_root->d_op = &xattr_lookup_poison_ops; reiserfs_mark_inode_private(dentry->d_inode); 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 */ reiserfs_warning(s, "xattrs/ACLs enabled and couldn't " "find/create .reiserfs_priv. Failing mount."); err = -EOPNOTSUPP; } } 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. */ 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)); } /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */ s->s_flags = s->s_flags & ~MS_POSIXACL; if (reiserfs_posixacl(s)) s->s_flags |= MS_POSIXACL; 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, struct nameidata *nd){ /* * We don't do permission checks on the internal objects. * Permissions are determined by the "owning" object. */ if (is_reiserfs_priv_object(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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -