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