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 + -
显示快捷键?