xattr.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,455 行 · 第 1/3 页
C
1,455 行
/* * Inode operation setxattr() * * dentry->d_inode->i_sem 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; if (IS_RDONLY (dentry->d_inode)) return -EROFS; if (IS_IMMUTABLE (dentry->d_inode) || IS_APPEND (dentry->d_inode)) return -EROFS; 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_sem down */intreiserfs_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; if (IS_RDONLY (dentry->d_inode)) return -EROFS; if (IS_IMMUTABLE (dentry->d_inode) || IS_APPEND (dentry->d_inode)) return -EPERM; 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; 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, ino_t 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_sem */ssize_treiserfs_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 rwlock_t handler_lock = RW_LOCK_UNLOCKED;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 __initreiserfs_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;}voidreiserfs_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 */intreiserfs_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; down (&inode->i_sem); err = inode->i_op->mkdir (inode, dentry, 0700); up (&inode->i_sem); 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_I(dentry->d_inode)->i_flags |= i_priv_object; 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_permission (struct inode *inode, int mask, struct nameidata *nd, int need_lock){ umode_t mode = inode->i_mode; if (mask & MAY_WRITE) { /* * Nobody gets write access to a read-only fs. */ if (IS_RDONLY(inode) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; /* * Nobody gets write access to an immutable file. */ if (IS_IMMUTABLE(inode)) return -EACCES; } /* 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; if (current->fsuid == inode->i_uid) { mode >>= 6;#ifdef CONFIG_REISERFS_FS_POSIX_ACL } else if (reiserfs_posixacl(inode->i_sb) && get_inode_sd_version (inode) != STAT_DATA_V1) { struct posix_acl *acl; /* ACL can't contain additional permissions if the ACL_MASK entry is 0 */ if (!(mode & S_IRWXG)) goto check_groups; if (need_lock) { reiserfs_read_lock_xattr_i (inode); reiserfs_read_lock_xattrs (inode->i_sb); } acl = reiserfs_get_acl (inode, ACL_TYPE_ACCESS); if (need_lock) { reiserfs_read_unlock_xattrs (inode->i_sb); reiserfs_read_unlock_xattr_i (inode); } if (IS_ERR (acl)) { if (PTR_ERR (acl) == -ENODATA) goto check_groups; return PTR_ERR (acl); } if (acl) { int err = posix_acl_permission (inode, acl, mask); posix_acl_release (acl); if (err == -EACCES) { goto check_capabilities; } return err; } else { goto check_groups; }#endif } else {check_groups: if (in_group_p(inode->i_gid)) mode >>= 3; } /* * If the DACs are ok we don't need any capability check. */ if (((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask)) return 0;check_capabilities: /* * Read/write DACs are always overridable. * Executable DACs are overridable if at least one exec bit is set. */ if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode)) if (capable(CAP_DAC_OVERRIDE)) return 0; /* * Searching includes executable on directories, else just read. */ if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE))) if (capable(CAP_DAC_READ_SEARCH)) return 0; return -EACCES;}intreiserfs_permission (struct inode *inode, int mask, struct nameidata *nd){ return __reiserfs_permission (inode, mask, nd, 1);}intreiserfs_permission_locked (struct inode *inode, int mask, struct nameidata *nd){ return __reiserfs_permission (inode, mask, nd, 0);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?