int hfsplus_rmxattr(struct dentry *dentry, const char *name) { struct inode *inode = dentry->d_inode; struct hfs_btree *btree = HFSPLUS_SB(inode->i_sb)->attr_tree; struct hfs_find_data fd; hfsplus_attr_entry entry; char tmp[32] = {0}; int res = 0; dprint(DBG_XATTR, "hfs: rmattr [%s][%s] [%lu]\n", dentry->d_name.name, name, dentry->d_inode->i_ino); if (!strcmp(name, SZ_XATTR_NAME_TYPE) || !strcmp(name, SZ_XATTR_NAME_CREATOR)) { return hfsplus_setxattr_buildin(dentry, name, tmp, 4, 0); } if (!strcmp(name, SZ_XATTR_NAME_FINDRINFO)) { return hfsplus_setxattr_buildin(dentry, name, tmp, 32, 0); } else if (!strcmp(name, SZ_XATTR_NAME_RFORK)) { return -EOPNOTSUPP; } res = hfs_find_init(btree, &fd); if (res) { return res; } hfsplus_attr_build_key(inode->i_sb, fd.search_key, cpu_to_be32((u32)(unsigned long)dentry->d_fsdata), name, 0); if ((res = hfs_brec_find(&fd))) { hfs_find_exit(&fd); goto out; } hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, sizeof(hfsplus_attr_entry)); if (be32_to_cpu(entry.type) != kHFSPlusAttrData) { res = -EOPNOTSUPP; hfs_find_exit(&fd); goto out; } res = hfs_brec_remove(&fd); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY); hfs_find_exit(&fd); // check xattr after hfs_find_exit (unlock attr btree) if (!hfsplus_has_xattr(dentry)) { hfsplus_set_cat_flag(inode, HFS_HAS_ATTR_MASK, 0); // here would lock cat tree. } //if ((res = filemap_write_and_wait(inode->i_mapping))) { // goto out; //} out: return res; }
// This function would lock the mutex of catalog tree. static ssize_t hfsplus_set_cat_flag(struct inode *inode, u16 flags, int add) { struct hfs_find_data fd; hfsplus_cat_entry entry; ssize_t res = 0; int is_file = 0; res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); if (res) return res; res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); if (res) { goto out; } hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, sizeof(hfsplus_cat_entry)); switch (be16_to_cpu(entry.type)) { case HFSPLUS_FILE: is_file = 1; break; case HFSPLUS_FOLDER: is_file = 0; break; default: res = EINVAL; goto out; } if (is_file) { if (add) entry.file.flags |= cpu_to_be16(flags); else entry.file.flags &= ~cpu_to_be16(flags); } else { if (add) entry.folder.flags |= cpu_to_be16(flags); else entry.folder.flags &= ~cpu_to_be16(flags); } res = 0; hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, is_file ? sizeof(struct hfsplus_cat_file) : sizeof(struct hfsplus_cat_folder)); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); out: hfs_find_exit(&fd); return res; }
int hfsplus_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct inode *inode = dentry->d_inode; struct hfs_find_data fd; hfsplus_cat_entry entry; struct hfsplus_cat_file *file; int res; if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); if (res) return res; res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); if (res) goto out; hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, sizeof(struct hfsplus_cat_file)); file = &entry.file; if (!strcmp(name, "hfs.type")) { if (size == 4) memcpy(&file->user_info.fdType, value, 4); else res = -ERANGE; } else if (!strcmp(name, "hfs.creator")) { if (size == 4) memcpy(&file->user_info.fdCreator, value, 4); else res = -ERANGE; } else res = -EOPNOTSUPP; if (!res) { hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, sizeof(struct hfsplus_cat_file)); hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); } out: hfs_find_exit(&fd); return res; }
void hfsplus_file_truncate(struct inode *inode) { struct super_block *sb = inode->i_sb; struct hfsplus_inode_info *hip = HFSPLUS_I(inode); struct hfs_find_data fd; u32 alloc_cnt, blk_cnt, start; int res; hfs_dbg(INODE, "truncate: %lu, %llu -> %llu\n", inode->i_ino, (long long)hip->phys_size, inode->i_size); if (inode->i_size > hip->phys_size) { struct address_space *mapping = inode->i_mapping; struct page *page; void *fsdata; loff_t size = inode->i_size; res = pagecache_write_begin(NULL, mapping, size, 0, AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); if (res) return; res = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata); if (res < 0) return; mark_inode_dirty(inode); return; } else if (inode->i_size == hip->phys_size) return; blk_cnt = (inode->i_size + HFSPLUS_SB(sb)->alloc_blksz - 1) >> HFSPLUS_SB(sb)->alloc_blksz_shift; mutex_lock(&hip->extents_lock); alloc_cnt = hip->alloc_blocks; if (blk_cnt == alloc_cnt) goto out_unlock; res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); if (res) { mutex_unlock(&hip->extents_lock); /* XXX: We lack error handling of hfsplus_file_truncate() */ return; } while (1) { if (alloc_cnt == hip->first_blocks) { hfsplus_free_extents(sb, hip->first_extents, alloc_cnt, alloc_cnt - blk_cnt); hfsplus_dump_extent(hip->first_extents); hip->first_blocks = blk_cnt; break; } res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt); if (res) break; start = hip->cached_start; hfsplus_free_extents(sb, hip->cached_extents, alloc_cnt - start, alloc_cnt - blk_cnt); hfsplus_dump_extent(hip->cached_extents); if (blk_cnt > start) { hip->extent_state |= HFSPLUS_EXT_DIRTY; break; } alloc_cnt = start; hip->cached_start = hip->cached_blocks = 0; hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); hfs_brec_remove(&fd); } hfs_find_exit(&fd); hip->alloc_blocks = blk_cnt; out_unlock: mutex_unlock(&hip->extents_lock); hip->phys_size = inode->i_size; hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); }
int hfsplus_file_extend(struct inode *inode, bool zeroout) { struct super_block *sb = inode->i_sb; struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); struct hfsplus_inode_info *hip = HFSPLUS_I(inode); u32 start, len, goal; int res; if (sbi->alloc_file->i_size * 8 < sbi->total_blocks - sbi->free_blocks + 8) { /* extend alloc file */ pr_err("extend alloc file! (%llu,%u,%u)\n", sbi->alloc_file->i_size * 8, sbi->total_blocks, sbi->free_blocks); return -ENOSPC; } mutex_lock(&hip->extents_lock); if (hip->alloc_blocks == hip->first_blocks) goal = hfsplus_ext_lastblock(hip->first_extents); else { res = hfsplus_ext_read_extent(inode, hip->alloc_blocks); if (res) goto out; goal = hfsplus_ext_lastblock(hip->cached_extents); } len = hip->clump_blocks; start = hfsplus_block_allocate(sb, sbi->total_blocks, goal, &len); if (start >= sbi->total_blocks) { start = hfsplus_block_allocate(sb, goal, 0, &len); if (start >= goal) { res = -ENOSPC; goto out; } } if (zeroout) { res = sb_issue_zeroout(sb, start, len, GFP_NOFS); if (res) goto out; } hfs_dbg(EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len); if (hip->alloc_blocks <= hip->first_blocks) { if (!hip->first_blocks) { hfs_dbg(EXTENT, "first extents\n"); /* no extents yet */ hip->first_extents[0].start_block = cpu_to_be32(start); hip->first_extents[0].block_count = cpu_to_be32(len); res = 0; } else { /* try to append to extents in inode */ res = hfsplus_add_extent(hip->first_extents, hip->alloc_blocks, start, len); if (res == -ENOSPC) goto insert_extent; } if (!res) { hfsplus_dump_extent(hip->first_extents); hip->first_blocks += len; } } else { res = hfsplus_add_extent(hip->cached_extents, hip->alloc_blocks - hip->cached_start, start, len); if (!res) { hfsplus_dump_extent(hip->cached_extents); hip->extent_state |= HFSPLUS_EXT_DIRTY; hip->cached_blocks += len; } else if (res == -ENOSPC) goto insert_extent; } out: if (!res) { hip->alloc_blocks += len; mutex_unlock(&hip->extents_lock); hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); return 0; } mutex_unlock(&hip->extents_lock); return res; insert_extent: hfs_dbg(EXTENT, "insert new extent\n"); res = hfsplus_ext_write_extent_locked(inode); if (res) goto out; memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); hip->cached_extents[0].start_block = cpu_to_be32(start); hip->cached_extents[0].block_count = cpu_to_be32(len); hfsplus_dump_extent(hip->cached_extents); hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW; hip->cached_start = hip->alloc_blocks; hip->cached_blocks = len; res = 0; goto out; }
int __hfsplus_setxattr(struct inode *inode, const char *name, const void *value, size_t size, int flags) { int err = 0; struct hfs_find_data cat_fd; hfsplus_cat_entry entry; u16 cat_entry_flags, cat_entry_type; u16 folder_finderinfo_len = sizeof(struct DInfo) + sizeof(struct DXInfo); u16 file_finderinfo_len = sizeof(struct FInfo) + sizeof(struct FXInfo); if ((!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) || HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; err = can_set_xattr(inode, name, value, size); if (err) return err; if (strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN) == 0) name += XATTR_MAC_OSX_PREFIX_LEN; if (value == NULL) { value = ""; size = 0; } err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); if (err) { pr_err("can't init xattr find struct\n"); return err; } err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); if (err) { pr_err("catalog searching failed\n"); goto end_setxattr; } if (!strcmp_xattr_finder_info(name)) { if (flags & XATTR_CREATE) { pr_err("xattr exists yet\n"); err = -EOPNOTSUPP; goto end_setxattr; } hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset, sizeof(hfsplus_cat_entry)); if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) { if (size == folder_finderinfo_len) { memcpy(&entry.folder.user_info, value, folder_finderinfo_len); hfs_bnode_write(cat_fd.bnode, &entry, cat_fd.entryoffset, sizeof(struct hfsplus_cat_folder)); hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); } else { err = -ERANGE; goto end_setxattr; } } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) { if (size == file_finderinfo_len) { memcpy(&entry.file.user_info, value, file_finderinfo_len); hfs_bnode_write(cat_fd.bnode, &entry, cat_fd.entryoffset, sizeof(struct hfsplus_cat_file)); hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); } else { err = -ERANGE; goto end_setxattr; } } else { err = -EOPNOTSUPP; goto end_setxattr; } goto end_setxattr; } if (!HFSPLUS_SB(inode->i_sb)->attr_tree) { err = -EOPNOTSUPP; goto end_setxattr; } if (hfsplus_attr_exists(inode, name)) { if (flags & XATTR_CREATE) { pr_err("xattr exists yet\n"); err = -EOPNOTSUPP; goto end_setxattr; } err = hfsplus_delete_attr(inode, name); if (err) goto end_setxattr; err = hfsplus_create_attr(inode, name, value, size); if (err) goto end_setxattr; } else { if (flags & XATTR_REPLACE) { pr_err("cannot replace xattr\n"); err = -EOPNOTSUPP; goto end_setxattr; } err = hfsplus_create_attr(inode, name, value, size); if (err) goto end_setxattr; } cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); if (cat_entry_type == HFSPLUS_FOLDER) { cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + offsetof(struct hfsplus_cat_folder, flags)); cat_entry_flags |= HFSPLUS_XATTR_EXISTS; if (!strcmp_xattr_acl(name)) cat_entry_flags |= HFSPLUS_ACL_EXISTS; hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + offsetof(struct hfsplus_cat_folder, flags), cat_entry_flags); hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); } else if (cat_entry_type == HFSPLUS_FILE) {
static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) { struct hfsplus_vh *vhdr; struct hfsplus_sb_info *sbi; hfsplus_cat_entry entry; struct hfs_find_data fd; struct inode *root, *inode; struct qstr str; struct nls_table *nls = NULL; int err; err = -EINVAL; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) goto out; sb->s_fs_info = sbi; mutex_init(&sbi->alloc_mutex); mutex_init(&sbi->vh_mutex); hfsplus_fill_defaults(sbi); err = -EINVAL; if (!hfsplus_parse_options(data, sbi)) { printk(KERN_ERR "hfs: unable to parse mount options\n"); goto out_unload_nls; } /* temporarily use utf8 to correctly find the hidden dir below */ nls = sbi->nls; sbi->nls = load_nls("utf8"); if (!sbi->nls) { printk(KERN_ERR "hfs: unable to load nls for utf8\n"); goto out_unload_nls; } /* Grab the volume header */ if (hfsplus_read_wrapper(sb)) { if (!silent) printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n"); goto out_unload_nls; } vhdr = sbi->s_vhdr; /* Copy parts of the volume header into the superblock */ sb->s_magic = HFSPLUS_VOLHEAD_SIG; if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION || be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) { printk(KERN_ERR "hfs: wrong filesystem version\n"); goto out_free_vhdr; } sbi->total_blocks = be32_to_cpu(vhdr->total_blocks); sbi->free_blocks = be32_to_cpu(vhdr->free_blocks); sbi->next_cnid = be32_to_cpu(vhdr->next_cnid); sbi->file_count = be32_to_cpu(vhdr->file_count); sbi->folder_count = be32_to_cpu(vhdr->folder_count); sbi->data_clump_blocks = be32_to_cpu(vhdr->data_clump_sz) >> sbi->alloc_blksz_shift; if (!sbi->data_clump_blocks) sbi->data_clump_blocks = 1; sbi->rsrc_clump_blocks = be32_to_cpu(vhdr->rsrc_clump_sz) >> sbi->alloc_blksz_shift; if (!sbi->rsrc_clump_blocks) sbi->rsrc_clump_blocks = 1; /* Set up operations so we can load metadata */ sb->s_op = &hfsplus_sops; sb->s_maxbytes = MAX_LFS_FILESIZE; if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { printk(KERN_WARNING "hfs: Filesystem was " "not cleanly unmounted, " "running fsck.hfsplus is recommended. " "mounting read-only.\n"); sb->s_flags |= MS_RDONLY; } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) { /* nothing */ } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n"); sb->s_flags |= MS_RDONLY; } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) && !(sb->s_flags & MS_RDONLY)) { printk(KERN_WARNING "hfs: write access to " "a journaled filesystem is not supported, " "use the force option at your own risk, " "mounting read-only.\n"); sb->s_flags |= MS_RDONLY; } /* Load metadata objects (B*Trees) */ sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); if (!sbi->ext_tree) { printk(KERN_ERR "hfs: failed to load extents file\n"); goto out_free_vhdr; } sbi->cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID); if (!sbi->cat_tree) { printk(KERN_ERR "hfs: failed to load catalog file\n"); goto out_close_ext_tree; } inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID); if (IS_ERR(inode)) { printk(KERN_ERR "hfs: failed to load allocation file\n"); err = PTR_ERR(inode); goto out_close_cat_tree; } sbi->alloc_file = inode; /* Load the root directory */ root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID); if (IS_ERR(root)) { printk(KERN_ERR "hfs: failed to load root directory\n"); err = PTR_ERR(root); goto out_put_alloc_file; } str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; str.name = HFSP_HIDDENDIR_NAME; hfs_find_init(sbi->cat_tree, &fd); hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { hfs_find_exit(&fd); if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) goto out_put_root; inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id)); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_put_root; } sbi->hidden_dir = inode; } else hfs_find_exit(&fd); if (!(sb->s_flags & MS_RDONLY)) { /* * H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused * all three are registered with Apple for our use */ vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION); vhdr->modify_date = hfsp_now2mt(); be32_add_cpu(&vhdr->write_count, 1); vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT); vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT); hfsplus_sync_fs(sb, 1); if (!sbi->hidden_dir) { mutex_lock(&sbi->vh_mutex); sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR); hfsplus_create_cat(sbi->hidden_dir->i_ino, root, &str, sbi->hidden_dir); mutex_unlock(&sbi->vh_mutex); hfsplus_mark_inode_dirty(sbi->hidden_dir, HFSPLUS_I_CAT_DIRTY); } } sb->s_d_op = &hfsplus_dentry_operations; sb->s_root = d_alloc_root(root); if (!sb->s_root) { err = -ENOMEM; goto out_put_hidden_dir; } unload_nls(sbi->nls); sbi->nls = nls; return 0; out_put_hidden_dir: iput(sbi->hidden_dir); out_put_root: iput(root); out_put_alloc_file: iput(sbi->alloc_file); out_close_cat_tree: hfs_btree_close(sbi->cat_tree); out_close_ext_tree: hfs_btree_close(sbi->ext_tree); out_free_vhdr: kfree(sbi->s_vhdr); kfree(sbi->s_backup_vhdr); out_unload_nls: unload_nls(sbi->nls); unload_nls(nls); kfree(sbi); out: return err; }
/* * The flags XATTR_REPLACE and XATTR_CREATE * specify that an extended attribute must exist and must not exist * previous to the call, respectively. */ int hfsplus_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct inode *inode = dentry->d_inode; struct hfs_btree *btree = HFSPLUS_SB(inode->i_sb)->attr_tree; struct hfs_find_data fd; hfsplus_attr_entry *entry = NULL; int res = 0, entry_size = 0; dprint(DBG_XATTR, "hfs: setattr [%s][%s] [%lu]\n", dentry->d_name.name, name, inode->i_ino); if (!value) { return -EINVAL; } if (!strcmp(name, SZ_XATTR_NAME_TYPE) || !strcmp(name, SZ_XATTR_NAME_CREATOR) || !strcmp(name, SZ_XATTR_NAME_FINDRINFO)) { return hfsplus_setxattr_buildin(dentry, name, value, size, flags); } else if (!strcmp(name, SZ_XATTR_NAME_RFORK)) { return -EOPNOTSUPP; } #if 0 #define HFSPLUS_MAX_ATTR_LEN (128*1024) if (size > HFSPLUS_MAX_ATTR_LEN) { return E2BIG; } #endif if (size > hfsplus_get_maxinline_attrsize(btree)) { return -E2BIG; } res = hfs_find_init(btree, &fd); if (res) { return res; } hfsplus_attr_build_key(inode->i_sb, fd.search_key, cpu_to_be32((u32)(unsigned long)dentry->d_fsdata), name, 0); res = hfs_brec_find(&fd); if (res == -ENOENT) { if (flags & XATTR_REPLACE) { res = -ENODATA; goto out; } } else if (res != 0) { goto out; } else { // res == 0 if (flags & XATTR_CREATE) { res = -EEXIST; goto out; } if ((res = hfs_brec_remove(&fd))) { goto out; } // decrease record count to avoid the next insert worng. --fd.record; //hfsplus_mark_inode_dirty(btree->inode, HFSPLUS_I_ATTR_DIRTY); //if ((res = filemap_write_and_wait(btree->inode->i_mapping))) { // goto out; //} } entry_size = sizeof(struct hfsplus_attr_data) - 2 + size + ((size & 1) ? 1 : 0); entry = kmalloc(entry_size * sizeof(char), GFP_NOFS); if (!entry) { res = -ENOMEM; goto out; } entry->type = cpu_to_be32(kHFSPlusAttrData); entry->data.attr_size = cpu_to_be32(size); memcpy(entry->data.attr_data, value, size); res = hfs_brec_insert(&fd, entry, entry_size); // set has attribute bit on file/folder hfsplus_set_cat_flag(inode, HFS_HAS_ATTR_MASK, 1); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY); //if ((res = filemap_write_and_wait(btree->inode->i_mapping))) { // goto out; //} out: if (entry) { kfree(entry); } hfs_find_exit(&fd); return res; }
int hfsplus_setxattr_buildin(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct inode *inode = dentry->d_inode; struct hfs_btree *btree = HFSPLUS_SB(inode->i_sb)->cat_tree; struct hfs_find_data fd; hfsplus_cat_entry entry; struct hfsplus_cat_file *file; char empty_info[32] = {0}; u8 is_file = 0; int res; if (HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; res = hfs_find_init(btree, &fd); if (res) return res; res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); if (res) goto out; hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, sizeof(struct hfsplus_cat_file)); file = &entry.file; if (entry.type == cpu_to_be16(HFSPLUS_FILE)) { is_file = 1; } res = -ERANGE; if (!strcmp(name, SZ_XATTR_NAME_TYPE) && is_file) { if (size != 4) goto out; memcpy(&file->user_info.fdType, value, 4); } else if (!strcmp(name, SZ_XATTR_NAME_CREATOR) && is_file) { if (size != 4) goto out; memcpy(&file->user_info.fdCreator, value, 4); } else if (!strcmp(name, SZ_XATTR_NAME_FINDRINFO)) { if (memcmp(&file->user_info, &empty_info, sizeof(empty_info))) { if (flags & XATTR_CREATE) { res = -EEXIST; goto out; } } else { if (flags & XATTR_REPLACE) { res = -ENODATA; goto out; } } // reserve the date_added memcpy(&((struct FXInfo *)value + sizeof(struct FInfo))->date_added, &file->finder_info.date_added, sizeof(__be32)); if (size != 32) goto out; memcpy(&file->user_info, value, 32); } else { res = -EOPNOTSUPP; goto out; } res = 0; hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, is_file ? sizeof(struct hfsplus_cat_file) : sizeof(struct hfsplus_cat_folder)); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); //if ((res = filemap_write_and_wait(HFSPLUS_SB(inode->i_sb)->cat_tree->inode->i_mapping))) { // goto out; //} out: hfs_find_exit(&fd); return res; }