static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) { struct hfsplus_inode_info *hip = HFSPLUS_I(inode); int res; WARN_ON(!mutex_is_locked(&hip->extents_lock)); hfsplus_ext_build_key(fd->search_key, inode->i_ino, hip->cached_start, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); res = hfs_brec_find(fd); if (hip->extent_state & HFSPLUS_EXT_NEW) { if (res != -ENOENT) return; hfs_brec_insert(fd, hip->cached_extents, sizeof(hfsplus_extent_rec)); hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); } else { if (res) return; hfs_bnode_write(fd->bnode, hip->cached_extents, fd->entryoffset, fd->entrylength); hip->extent_state &= ~HFSPLUS_EXT_DIRTY; } /* * We can't just use hfsplus_mark_inode_dirty here, because we * also get called from hfsplus_write_inode, which should not * redirty the inode. Instead the callers have to be careful * to explicily mark the inode dirty, too. */ set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags); }
static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block) { struct hfsplus_inode_info *hip = HFSPLUS_I(inode); int res; WARN_ON(!mutex_is_locked(&hip->extents_lock)); if (hip->extent_state & HFSPLUS_EXT_DIRTY) { res = __hfsplus_ext_write_extent(inode, fd); if (res) return res; } res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino, block, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); if (!res) { hip->cached_start = be32_to_cpu(fd->key->ext.start_block); hip->cached_blocks = hfsplus_ext_block_count(hip->cached_extents); } else { hip->cached_start = hip->cached_blocks = 0; hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); } return res; }
static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; struct inode *inode = dentry->d_inode; struct qstr str; char name[32]; u32 cnid; int res; hfsplus_handle_t hfsplus_handle; if (HFSPLUS_IS_RSRC(inode)) return -EPERM; if ((res = hfsplus_journal_start(__FUNCTION__, dir->i_sb, &hfsplus_handle))) return res; cnid = (u32)(unsigned long)dentry->d_fsdata; if (inode->i_ino == cnid && atomic_read(&HFSPLUS_I(inode).opencnt)) { str.name = name; str.len = sprintf(name, "temp%lu", inode->i_ino); res = hfsplus_rename_cat(&hfsplus_handle, inode->i_ino, dir, &dentry->d_name, HFSPLUS_SB(sb).hidden_dir, &str); if (!res) inode->i_flags |= S_DEAD; hfsplus_journal_stop(&hfsplus_handle); return res; } res = hfsplus_delete_cat(&hfsplus_handle, cnid, dir, &dentry->d_name); if (res) { hfsplus_journal_stop(&hfsplus_handle); return res; } if (inode->i_nlink > 0) drop_nlink(inode); if (inode->i_ino == cnid) clear_nlink(inode); if (!inode->i_nlink) { if (inode->i_ino != cnid) { HFSPLUS_SB(sb).file_count--; if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { res = hfsplus_delete_cat(&hfsplus_handle, inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL); if (!res) hfsplus_delete_inode(&hfsplus_handle, inode); } else inode->i_flags |= S_DEAD; } else hfsplus_delete_inode(&hfsplus_handle,inode); } else HFSPLUS_SB(sb).file_count--; inode->i_ctime = CURRENT_TIME_SEC; res = hfsplus_journalled_mark_inode_dirty(__FUNCTION__, &hfsplus_handle, inode); hfsplus_journal_stop(&hfsplus_handle); return res; }
static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, struct dentry *dst_dentry) { struct hfsplus_sb_info *sbi = HFSPLUS_SB(dst_dir->i_sb); struct inode *inode = src_dentry->d_inode; struct inode *src_dir = src_dentry->d_parent->d_inode; struct qstr str; char name[32]; u32 cnid, id; int res; if (HFSPLUS_IS_RSRC(inode)) return -EPERM; if (!S_ISREG(inode->i_mode)) return -EPERM; mutex_lock(&sbi->vh_mutex); if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) { for (;;) { get_random_bytes(&id, sizeof(cnid)); id &= 0x3fffffff; str.name = name; str.len = sprintf(name, "iNode%d", id); res = hfsplus_rename_cat(inode->i_ino, src_dir, &src_dentry->d_name, sbi->hidden_dir, &str); if (!res) break; if (res != -EEXIST) goto out; } HFSPLUS_I(inode)->linkid = id; cnid = sbi->next_cnid++; src_dentry->d_fsdata = (void *)(unsigned long)cnid; res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode); if (res) /* panic? */ goto out; sbi->file_count++; } cnid = sbi->next_cnid++; res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode); if (res) goto out; inc_nlink(inode); hfsplus_instantiate(dst_dentry, inode, cnid); ihold(inode); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); sbi->file_count++; hfsplus_mark_mdb_dirty(dst_dir->i_sb); out: mutex_unlock(&sbi->vh_mutex); return res; }
static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) { struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); struct inode *inode = dentry->d_inode; struct qstr str; char name[32]; u32 cnid; int res; if (HFSPLUS_IS_RSRC(inode)) return -EPERM; mutex_lock(&sbi->vh_mutex); cnid = (u32)(unsigned long)dentry->d_fsdata; if (inode->i_ino == cnid && atomic_read(&HFSPLUS_I(inode)->opencnt)) { str.name = name; str.len = sprintf(name, "temp%lu", inode->i_ino); res = hfsplus_rename_cat(inode->i_ino, dir, &dentry->d_name, sbi->hidden_dir, &str); if (!res) { inode->i_flags |= S_DEAD; drop_nlink(inode); } goto out; } res = hfsplus_delete_cat(cnid, dir, &dentry->d_name); if (res) goto out; if (inode->i_nlink > 0) drop_nlink(inode); if (inode->i_ino == cnid) clear_nlink(inode); if (!inode->i_nlink) { if (inode->i_ino != cnid) { sbi->file_count--; if (!atomic_read(&HFSPLUS_I(inode)->opencnt)) { res = hfsplus_delete_cat(inode->i_ino, sbi->hidden_dir, NULL); if (!res) hfsplus_delete_inode(inode); } else inode->i_flags |= S_DEAD; } else hfsplus_delete_inode(inode); } else sbi->file_count--; inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); out: mutex_unlock(&sbi->vh_mutex); return res; }
static void hfsplus_evict_inode(struct inode *inode) { dprint(DBG_INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino); truncate_inode_pages(&inode->i_data, 0); end_writeback(inode); if (HFSPLUS_IS_RSRC(inode)) { HFSPLUS_I(HFSPLUS_I(inode)->rsrc_inode)->rsrc_inode = NULL; iput(HFSPLUS_I(inode)->rsrc_inode); } }
static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, struct dentry *dst_dentry) { struct super_block *sb = dst_dir->i_sb; struct inode *inode = src_dentry->d_inode; struct inode *src_dir = src_dentry->d_parent->d_inode; struct qstr str; char name[32]; u32 cnid, id; int res; if (HFSPLUS_IS_RSRC(inode)) return -EPERM; if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) { for (;;) { get_random_bytes(&id, sizeof(cnid)); id &= 0x3fffffff; str.name = name; str.len = sprintf(name, "iNode%d", id); res = hfsplus_rename_cat(inode->i_ino, src_dir, &src_dentry->d_name, HFSPLUS_SB(sb).hidden_dir, &str); if (!res) break; if (res != -EEXIST) return res; } HFSPLUS_I(inode).dev = id; cnid = HFSPLUS_SB(sb).next_cnid++; src_dentry->d_fsdata = (void *)(unsigned long)cnid; res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode); if (res) /* panic? */ return res; HFSPLUS_SB(sb).file_count++; } cnid = HFSPLUS_SB(sb).next_cnid++; res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode); if (res) return res; inc_nlink(inode); hfsplus_instantiate(dst_dentry, inode, cnid); atomic_inc(&inode->i_count); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); HFSPLUS_SB(sb).file_count++; sb->s_dirt = 1; return 0; }
ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) { struct inode *inode = dentry->d_inode; if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; if (!buffer || !size) return HFSPLUS_ATTRLIST_SIZE; if (size < HFSPLUS_ATTRLIST_SIZE) return -ERANGE; strcpy(buffer, "hfs.type"); strcpy(buffer + sizeof("hfs.type"), "hfs.creator"); return HFSPLUS_ATTRLIST_SIZE; }
static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; struct inode *inode = dentry->d_inode; struct qstr str; char name[32]; u32 cnid; int res; if (HFSPLUS_IS_RSRC(inode)) return -EPERM; cnid = (u32)(unsigned long)dentry->d_fsdata; if (inode->i_ino == cnid && atomic_read(&HFSPLUS_I(inode).opencnt)) { str.name = name; str.len = sprintf(name, "temp%lu", inode->i_ino); res = hfsplus_rename_cat(inode->i_ino, dir, &dentry->d_name, HFSPLUS_SB(sb).hidden_dir, &str); if (!res) inode->i_flags |= S_DEAD; return res; } res = hfsplus_delete_cat(cnid, dir, &dentry->d_name); if (res) return res; if (inode->i_nlink > 0) drop_nlink(inode); hfsplus_delete_inode(inode); if (inode->i_ino != cnid && !inode->i_nlink) { if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { res = hfsplus_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL); if (!res) hfsplus_delete_inode(inode); } else inode->i_flags |= S_DEAD; } else clear_nlink(inode); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); return res; }
static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block) { int res; if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_DIRTY) __hfsplus_ext_write_extent(inode, fd); res = __hfsplus_ext_read_extent(fd, HFSPLUS_I(inode).cached_extents, inode->i_ino, block, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); if (!res) { HFSPLUS_I(inode).cached_start = be32_to_cpu(fd->key->ext.start_block); HFSPLUS_I(inode).cached_blocks = hfsplus_ext_block_count(HFSPLUS_I(inode).cached_extents); } else { HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).cached_blocks = 0; HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); } return res; }
static ssize_t hfsplus_getxattr_buildin(struct dentry *dentry, const char *name, void *value, size_t size) { struct inode *inode = dentry->d_inode; hfsplus_cat_entry entry; struct hfsplus_cat_file *file; ssize_t res = 0; dprint(DBG_XATTR, "hfs: getattr [%s][%s] [%lu]\n", dentry->d_name.name, name, inode->i_ino); if (HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; res = hfsplus_get_cat_entry(inode, &entry); file = &entry.file; if (!strcmp(name, SZ_XATTR_NAME_TYPE) && S_ISREG(inode->i_mode)) { if (size >= 4) { memcpy(value, &file->user_info.fdType, 4); res = 4; } else { res = size ? -ERANGE : 4; } } else if (!strcmp(name, SZ_XATTR_NAME_CREATOR) && S_ISREG(inode->i_mode)) { if (size >= 4) { memcpy(value, &file->user_info.fdCreator, 4); res = 4; } else { res = size ? -ERANGE : 4; } } else if (!strcmp(name, SZ_XATTR_NAME_FINDRINFO)) { // 32 byte = user_info + finder_info if (size >= 32) { // follow xnu implementation: zero out the dateadded file->finder_info.date_added = 0; memcpy(value, &file->user_info, 32); res = 32; } else { res = size ? -ERANGE : 32; } } else { res = -EOPNOTSUPP; } return res; }
static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) { int res; hfsplus_ext_build_key(fd->search_key, inode->i_ino, HFSPLUS_I(inode).cached_start, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); res = hfs_brec_find(fd); if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_NEW) { if (res != -ENOENT) return; hfs_brec_insert(fd, HFSPLUS_I(inode).cached_extents, sizeof(hfsplus_extent_rec)); HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); } else { if (res) return; hfs_bnode_write(fd->bnode, HFSPLUS_I(inode).cached_extents, fd->entryoffset, fd->entrylength); HFSPLUS_I(inode).flags &= ~HFSPLUS_FLG_EXT_DIRTY; } }
ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) { struct inode *inode = dentry->d_inode; struct hfs_find_data fd; hfsplus_cat_entry entry; struct hfsplus_cat_file *file; ssize_t res = 0; if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; if (size) { 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(value, &file->user_info.fdType, 4); res = 4; } else res = size ? -ERANGE : 4; } else if (!strcmp(name, "hfs.creator")) { if (size >= 4) { memcpy(value, &file->user_info.fdCreator, 4); res = 4; } else res = size ? -ERANGE : 4; } else res = -EOPNOTSUPP; out: if (size) 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; }
static ssize_t hfsplus_listxattr_ex(struct dentry *dentry, char *buffer, size_t size, int check_buildin) { ssize_t res = 0; char strbuf[HFSPLUS_XATTR_MAX_NAMELEN + 1] = {0}, empty_info[32] = {0}; hfsplus_cnid cnid = cpu_to_be32((u32)(unsigned long)dentry->d_fsdata); int len = 0; size_t strbuflen = 0; struct inode *inode = dentry->d_inode; struct hfs_find_data fd; hfsplus_cat_entry entry; struct hfsplus_cat_file *file; u16 type = 0; #define __APPEND_XATTRNAME(name, namelen) \ do { \ if (size > strbuflen + namelen) strcpy(buffer + strbuflen, name); \ strbuflen += namelen + 1; \ } while (0) if (HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; if (!buffer) size = 0; // check FinderInfo & ResourceFork(file only) if (check_buildin && !hfsplus_get_cat_entry(inode, &entry)) { file = &entry.file; type = be16_to_cpu(entry.type); if (type != HFSPLUS_FILE && type != HFSPLUS_FOLDER) { printk(KERN_ERR "hfs: invalid catalog entry type in lookup\n"); res = -EIO; goto out; } if (type == HFSPLUS_FILE) { if (0 < be64_to_cpu(entry.file.rsrc_fork.total_size)) { len = strlen(SZ_XATTR_NAME_RFORK); __APPEND_XATTRNAME(SZ_XATTR_NAME_RFORK, len); } } entry.file.finder_info.date_added = 0; if (memcmp(&entry.file.user_info, &empty_info, sizeof(empty_info))) { len = strlen(SZ_XATTR_NAME_FINDRINFO); __APPEND_XATTRNAME(SZ_XATTR_NAME_FINDRINFO, len); } } if ((res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd))) { goto out; } hfsplus_attr_build_key(inode->i_sb, fd.search_key, cnid, NULL, 0); if ((res = hfsplus_brec_find_first(&fd))) { goto out; } // traverse other EA while (!res && fd.key->attr.file_id == cnid) { len = sizeof(strbuf); memset(strbuf, 0, len); hfsplus_uni2asc(inode->i_sb, (struct hfsplus_unistr *)&fd.key->attr.name, strbuf, &len); __APPEND_XATTRNAME(strbuf, len); dprint(DBG_XATTR, "hfs: enum [%u] bnode:[%u,%d][%s] key:[%d,%d] entry:[%d,%d].\n", be32_to_cpu(fd.key->attr.file_id), fd.bnode->this, fd.record, strbuf, fd.keyoffset, fd.keylength, fd.entryoffset, fd.entrylength); res = hfs_brec_goto(&fd, 1); } #undef __APPEND_XATTRNAME out: if (strbuflen > 0 && (res == -ENOENT || res == 0)) { res = strbuflen; if (size < strbuflen && size > 0) { res = -ERANGE; } } hfs_find_exit(&fd); return res; }
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) {
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; }