Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/hch/hfsplus

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/hch/hfsplus: (29 commits)
  hfsplus: fix getxattr return value
  hfsplus: remove the unused hfsplus_kmap/hfsplus_kunmap helpers
  hfsplus: create correct initial catalog entries for device files
  hfsplus: remove superflous rootflags field in hfsplus_inode_info
  hfsplus: fix link corruption
  hfsplus: validate btree flags
  hfsplus: handle more on-disk corruptions without oopsing
  hfsplus: hfs_bnode_find() can fail, resulting in hfs_bnode_split() breakage
  hfsplus: fix oops on mount with corrupted btree extent records
  hfsplus: fix rename over directories
  hfsplus: convert tree_lock to mutex
  hfsplus: add missing extent locking in hfsplus_write_inode
  hfsplus: protect readdir against removals from open_dir_list
  hfsplus: use atomic bitops for the superblock flags
  hfsplus: add per-superblock lock for volume header updates
  hfsplus: remove the rsrc_inodes list
  hfsplus: do not cache and write next_alloc
  hfsplus: fix error handling in hfsplus_symlink
  hfsplus: merge mknod/mkdir/creat
  hfsplus: clean up hfsplus_write_inode
  ...
This commit is contained in:
Linus Torvalds 2010-10-21 12:33:45 -07:00
commit 9f1ad09493
16 changed files with 777 additions and 661 deletions

View File

@ -23,7 +23,7 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
fd->search_key = ptr; fd->search_key = ptr;
fd->key = ptr + tree->max_key_len + 2; fd->key = ptr + tree->max_key_len + 2;
dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0)); dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0));
down(&tree->tree_lock); mutex_lock(&tree->tree_lock);
return 0; return 0;
} }
@ -32,7 +32,7 @@ void hfs_find_exit(struct hfs_find_data *fd)
hfs_bnode_put(fd->bnode); hfs_bnode_put(fd->bnode);
kfree(fd->search_key); kfree(fd->search_key);
dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0)); dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0));
up(&fd->tree->tree_lock); mutex_unlock(&fd->tree->tree_lock);
fd->tree = NULL; fd->tree = NULL;
} }
@ -52,6 +52,10 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
rec = (e + b) / 2; rec = (e + b) / 2;
len = hfs_brec_lenoff(bnode, rec, &off); len = hfs_brec_lenoff(bnode, rec, &off);
keylen = hfs_brec_keylen(bnode, rec); keylen = hfs_brec_keylen(bnode, rec);
if (keylen == 0) {
res = -EINVAL;
goto fail;
}
hfs_bnode_read(bnode, fd->key, off, keylen); hfs_bnode_read(bnode, fd->key, off, keylen);
cmpval = bnode->tree->keycmp(fd->key, fd->search_key); cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
if (!cmpval) { if (!cmpval) {
@ -67,6 +71,10 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
if (rec != e && e >= 0) { if (rec != e && e >= 0) {
len = hfs_brec_lenoff(bnode, e, &off); len = hfs_brec_lenoff(bnode, e, &off);
keylen = hfs_brec_keylen(bnode, e); keylen = hfs_brec_keylen(bnode, e);
if (keylen == 0) {
res = -EINVAL;
goto fail;
}
hfs_bnode_read(bnode, fd->key, off, keylen); hfs_bnode_read(bnode, fd->key, off, keylen);
} }
done: done:
@ -75,6 +83,7 @@ done:
fd->keylength = keylen; fd->keylength = keylen;
fd->entryoffset = off + keylen; fd->entryoffset = off + keylen;
fd->entrylength = len - keylen; fd->entrylength = len - keylen;
fail:
return res; return res;
} }
@ -198,6 +207,10 @@ int hfs_brec_goto(struct hfs_find_data *fd, int cnt)
len = hfs_brec_lenoff(bnode, fd->record, &off); len = hfs_brec_lenoff(bnode, fd->record, &off);
keylen = hfs_brec_keylen(bnode, fd->record); keylen = hfs_brec_keylen(bnode, fd->record);
if (keylen == 0) {
res = -EINVAL;
goto out;
}
fd->keyoffset = off; fd->keyoffset = off;
fd->keylength = keylen; fd->keylength = keylen;
fd->entryoffset = off + keylen; fd->entryoffset = off + keylen;

View File

@ -17,6 +17,7 @@
int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *max) int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *max)
{ {
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
struct page *page; struct page *page;
struct address_space *mapping; struct address_space *mapping;
__be32 *pptr, *curr, *end; __be32 *pptr, *curr, *end;
@ -29,8 +30,8 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
return size; return size;
dprint(DBG_BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len); dprint(DBG_BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len);
mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex); mutex_lock(&sbi->alloc_mutex);
mapping = HFSPLUS_SB(sb).alloc_file->i_mapping; mapping = sbi->alloc_file->i_mapping;
page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL); page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL);
if (IS_ERR(page)) { if (IS_ERR(page)) {
start = size; start = size;
@ -150,16 +151,17 @@ done:
set_page_dirty(page); set_page_dirty(page);
kunmap(page); kunmap(page);
*max = offset + (curr - pptr) * 32 + i - start; *max = offset + (curr - pptr) * 32 + i - start;
HFSPLUS_SB(sb).free_blocks -= *max; sbi->free_blocks -= *max;
sb->s_dirt = 1; sb->s_dirt = 1;
dprint(DBG_BITMAP, "-> %u,%u\n", start, *max); dprint(DBG_BITMAP, "-> %u,%u\n", start, *max);
out: out:
mutex_unlock(&HFSPLUS_SB(sb).alloc_file->i_mutex); mutex_unlock(&sbi->alloc_mutex);
return start; return start;
} }
int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count) int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
{ {
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
struct page *page; struct page *page;
struct address_space *mapping; struct address_space *mapping;
__be32 *pptr, *curr, *end; __be32 *pptr, *curr, *end;
@ -172,11 +174,11 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
dprint(DBG_BITMAP, "block_free: %u,%u\n", offset, count); dprint(DBG_BITMAP, "block_free: %u,%u\n", offset, count);
/* are all of the bits in range? */ /* are all of the bits in range? */
if ((offset + count) > HFSPLUS_SB(sb).total_blocks) if ((offset + count) > sbi->total_blocks)
return -2; return -2;
mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex); mutex_lock(&sbi->alloc_mutex);
mapping = HFSPLUS_SB(sb).alloc_file->i_mapping; mapping = sbi->alloc_file->i_mapping;
pnr = offset / PAGE_CACHE_BITS; pnr = offset / PAGE_CACHE_BITS;
page = read_mapping_page(mapping, pnr, NULL); page = read_mapping_page(mapping, pnr, NULL);
pptr = kmap(page); pptr = kmap(page);
@ -224,9 +226,9 @@ done:
out: out:
set_page_dirty(page); set_page_dirty(page);
kunmap(page); kunmap(page);
HFSPLUS_SB(sb).free_blocks += len; sbi->free_blocks += len;
sb->s_dirt = 1; sb->s_dirt = 1;
mutex_unlock(&HFSPLUS_SB(sb).alloc_file->i_mutex); mutex_unlock(&sbi->alloc_mutex);
return 0; return 0;
} }

View File

@ -42,10 +42,13 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2); recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
if (!recoff) if (!recoff)
return 0; return 0;
if (node->tree->attributes & HFS_TREE_BIGKEYS)
retval = hfs_bnode_read_u16(node, recoff) + 2; retval = hfs_bnode_read_u16(node, recoff) + 2;
else if (retval > node->tree->max_key_len + 2) {
retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1; printk(KERN_ERR "hfs: keylen %d too large\n",
retval);
retval = 0;
}
} }
return retval; return retval;
} }
@ -216,7 +219,7 @@ skip:
static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
{ {
struct hfs_btree *tree; struct hfs_btree *tree;
struct hfs_bnode *node, *new_node; struct hfs_bnode *node, *new_node, *next_node;
struct hfs_bnode_desc node_desc; struct hfs_bnode_desc node_desc;
int num_recs, new_rec_off, new_off, old_rec_off; int num_recs, new_rec_off, new_off, old_rec_off;
int data_start, data_end, size; int data_start, data_end, size;
@ -235,6 +238,17 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
new_node->type = node->type; new_node->type = node->type;
new_node->height = node->height; new_node->height = node->height;
if (node->next)
next_node = hfs_bnode_find(tree, node->next);
else
next_node = NULL;
if (IS_ERR(next_node)) {
hfs_bnode_put(node);
hfs_bnode_put(new_node);
return next_node;
}
size = tree->node_size / 2 - node->num_recs * 2 - 14; size = tree->node_size / 2 - node->num_recs * 2 - 14;
old_rec_off = tree->node_size - 4; old_rec_off = tree->node_size - 4;
num_recs = 1; num_recs = 1;
@ -248,6 +262,8 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
/* panic? */ /* panic? */
hfs_bnode_put(node); hfs_bnode_put(node);
hfs_bnode_put(new_node); hfs_bnode_put(new_node);
if (next_node)
hfs_bnode_put(next_node);
return ERR_PTR(-ENOSPC); return ERR_PTR(-ENOSPC);
} }
@ -302,8 +318,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc)); hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));
/* update next bnode header */ /* update next bnode header */
if (new_node->next) { if (next_node) {
struct hfs_bnode *next_node = hfs_bnode_find(tree, new_node->next);
next_node->prev = new_node->this; next_node->prev = new_node->this;
hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc)); hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
node_desc.prev = cpu_to_be32(next_node->prev); node_desc.prev = cpu_to_be32(next_node->prev);

View File

@ -30,7 +30,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
if (!tree) if (!tree)
return NULL; return NULL;
init_MUTEX(&tree->tree_lock); mutex_init(&tree->tree_lock);
spin_lock_init(&tree->hash_lock); spin_lock_init(&tree->hash_lock);
tree->sb = sb; tree->sb = sb;
tree->cnid = id; tree->cnid = id;
@ -39,10 +39,16 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
goto free_tree; goto free_tree;
tree->inode = inode; tree->inode = inode;
if (!HFSPLUS_I(tree->inode)->first_blocks) {
printk(KERN_ERR
"hfs: invalid btree extent records (0 size).\n");
goto free_inode;
}
mapping = tree->inode->i_mapping; mapping = tree->inode->i_mapping;
page = read_mapping_page(mapping, 0, NULL); page = read_mapping_page(mapping, 0, NULL);
if (IS_ERR(page)) if (IS_ERR(page))
goto free_tree; goto free_inode;
/* Load the header */ /* Load the header */
head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc)); head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
@ -57,27 +63,56 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
tree->max_key_len = be16_to_cpu(head->max_key_len); tree->max_key_len = be16_to_cpu(head->max_key_len);
tree->depth = be16_to_cpu(head->depth); tree->depth = be16_to_cpu(head->depth);
/* Set the correct compare function */ /* Verify the tree and set the correct compare function */
if (id == HFSPLUS_EXT_CNID) { switch (id) {
case HFSPLUS_EXT_CNID:
if (tree->max_key_len != HFSPLUS_EXT_KEYLEN - sizeof(u16)) {
printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
tree->max_key_len);
goto fail_page;
}
if (tree->attributes & HFS_TREE_VARIDXKEYS) {
printk(KERN_ERR "hfs: invalid extent btree flag\n");
goto fail_page;
}
tree->keycmp = hfsplus_ext_cmp_key; tree->keycmp = hfsplus_ext_cmp_key;
} else if (id == HFSPLUS_CAT_CNID) { break;
if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && case HFSPLUS_CAT_CNID:
if (tree->max_key_len != HFSPLUS_CAT_KEYLEN - sizeof(u16)) {
printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
tree->max_key_len);
goto fail_page;
}
if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
printk(KERN_ERR "hfs: invalid catalog btree flag\n");
goto fail_page;
}
if (test_bit(HFSPLUS_SB_HFSX, &HFSPLUS_SB(sb)->flags) &&
(head->key_type == HFSPLUS_KEY_BINARY)) (head->key_type == HFSPLUS_KEY_BINARY))
tree->keycmp = hfsplus_cat_bin_cmp_key; tree->keycmp = hfsplus_cat_bin_cmp_key;
else { else {
tree->keycmp = hfsplus_cat_case_cmp_key; tree->keycmp = hfsplus_cat_case_cmp_key;
HFSPLUS_SB(sb).flags |= HFSPLUS_SB_CASEFOLD; set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
} }
} else { break;
default:
printk(KERN_ERR "hfs: unknown B*Tree requested\n"); printk(KERN_ERR "hfs: unknown B*Tree requested\n");
goto fail_page; goto fail_page;
} }
if (!(tree->attributes & HFS_TREE_BIGKEYS)) {
printk(KERN_ERR "hfs: invalid btree flag\n");
goto fail_page;
}
size = tree->node_size; size = tree->node_size;
if (!is_power_of_2(size)) if (!is_power_of_2(size))
goto fail_page; goto fail_page;
if (!tree->node_count) if (!tree->node_count)
goto fail_page; goto fail_page;
tree->node_size_shift = ffs(size) - 1; tree->node_size_shift = ffs(size) - 1;
tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
@ -87,10 +122,11 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
return tree; return tree;
fail_page: fail_page:
tree->inode->i_mapping->a_ops = &hfsplus_aops;
page_cache_release(page); page_cache_release(page);
free_tree: free_inode:
tree->inode->i_mapping->a_ops = &hfsplus_aops;
iput(tree->inode); iput(tree->inode);
free_tree:
kfree(tree); kfree(tree);
return NULL; return NULL;
} }
@ -192,17 +228,18 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
while (!tree->free_nodes) { while (!tree->free_nodes) {
struct inode *inode = tree->inode; struct inode *inode = tree->inode;
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
u32 count; u32 count;
int res; int res;
res = hfsplus_file_extend(inode); res = hfsplus_file_extend(inode);
if (res) if (res)
return ERR_PTR(res); return ERR_PTR(res);
HFSPLUS_I(inode).phys_size = inode->i_size = hip->phys_size = inode->i_size =
(loff_t)HFSPLUS_I(inode).alloc_blocks << (loff_t)hip->alloc_blocks <<
HFSPLUS_SB(tree->sb).alloc_blksz_shift; HFSPLUS_SB(tree->sb)->alloc_blksz_shift;
HFSPLUS_I(inode).fs_blocks = HFSPLUS_I(inode).alloc_blocks << hip->fs_blocks =
HFSPLUS_SB(tree->sb).fs_shift; hip->alloc_blocks << HFSPLUS_SB(tree->sb)->fs_shift;
inode_set_bytes(inode, inode->i_size); inode_set_bytes(inode, inode->i_size);
count = inode->i_size >> tree->node_size_shift; count = inode->i_size >> tree->node_size_shift;
tree->free_nodes = count - tree->node_count; tree->free_nodes = count - tree->node_count;

View File

@ -67,7 +67,7 @@ static void hfsplus_cat_build_key_uni(hfsplus_btree_key *key, u32 parent,
key->key_len = cpu_to_be16(6 + ustrlen); key->key_len = cpu_to_be16(6 + ustrlen);
} }
static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms) void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms)
{ {
if (inode->i_flags & S_IMMUTABLE) if (inode->i_flags & S_IMMUTABLE)
perms->rootflags |= HFSPLUS_FLG_IMMUTABLE; perms->rootflags |= HFSPLUS_FLG_IMMUTABLE;
@ -77,15 +77,24 @@ static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
perms->rootflags |= HFSPLUS_FLG_APPEND; perms->rootflags |= HFSPLUS_FLG_APPEND;
else else
perms->rootflags &= ~HFSPLUS_FLG_APPEND; perms->rootflags &= ~HFSPLUS_FLG_APPEND;
HFSPLUS_I(inode).rootflags = perms->rootflags;
HFSPLUS_I(inode).userflags = perms->userflags; perms->userflags = HFSPLUS_I(inode)->userflags;
perms->mode = cpu_to_be16(inode->i_mode); perms->mode = cpu_to_be16(inode->i_mode);
perms->owner = cpu_to_be32(inode->i_uid); perms->owner = cpu_to_be32(inode->i_uid);
perms->group = cpu_to_be32(inode->i_gid); perms->group = cpu_to_be32(inode->i_gid);
if (S_ISREG(inode->i_mode))
perms->dev = cpu_to_be32(inode->i_nlink);
else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
perms->dev = cpu_to_be32(inode->i_rdev);
else
perms->dev = 0;
} }
static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct inode *inode) static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct inode *inode)
{ {
struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode)) {
struct hfsplus_cat_folder *folder; struct hfsplus_cat_folder *folder;
@ -93,13 +102,13 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
memset(folder, 0, sizeof(*folder)); memset(folder, 0, sizeof(*folder));
folder->type = cpu_to_be16(HFSPLUS_FOLDER); folder->type = cpu_to_be16(HFSPLUS_FOLDER);
folder->id = cpu_to_be32(inode->i_ino); folder->id = cpu_to_be32(inode->i_ino);
HFSPLUS_I(inode).create_date = HFSPLUS_I(inode)->create_date =
folder->create_date = folder->create_date =
folder->content_mod_date = folder->content_mod_date =
folder->attribute_mod_date = folder->attribute_mod_date =
folder->access_date = hfsp_now2mt(); folder->access_date = hfsp_now2mt();
hfsplus_set_perms(inode, &folder->permissions); hfsplus_cat_set_perms(inode, &folder->permissions);
if (inode == HFSPLUS_SB(inode->i_sb).hidden_dir) if (inode == sbi->hidden_dir)
/* invisible and namelocked */ /* invisible and namelocked */
folder->user_info.frFlags = cpu_to_be16(0x5000); folder->user_info.frFlags = cpu_to_be16(0x5000);
return sizeof(*folder); return sizeof(*folder);
@ -111,19 +120,19 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
file->type = cpu_to_be16(HFSPLUS_FILE); file->type = cpu_to_be16(HFSPLUS_FILE);
file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS); file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS);
file->id = cpu_to_be32(cnid); file->id = cpu_to_be32(cnid);
HFSPLUS_I(inode).create_date = HFSPLUS_I(inode)->create_date =
file->create_date = file->create_date =
file->content_mod_date = file->content_mod_date =
file->attribute_mod_date = file->attribute_mod_date =
file->access_date = hfsp_now2mt(); file->access_date = hfsp_now2mt();
if (cnid == inode->i_ino) { if (cnid == inode->i_ino) {
hfsplus_set_perms(inode, &file->permissions); hfsplus_cat_set_perms(inode, &file->permissions);
if (S_ISLNK(inode->i_mode)) { if (S_ISLNK(inode->i_mode)) {
file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE); file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE);
file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR); file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR);
} else { } else {
file->user_info.fdType = cpu_to_be32(HFSPLUS_SB(inode->i_sb).type); file->user_info.fdType = cpu_to_be32(sbi->type);
file->user_info.fdCreator = cpu_to_be32(HFSPLUS_SB(inode->i_sb).creator); file->user_info.fdCreator = cpu_to_be32(sbi->creator);
} }
if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
@ -131,8 +140,8 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE); file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE);
file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR); file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR);
file->user_info.fdFlags = cpu_to_be16(0x100); file->user_info.fdFlags = cpu_to_be16(0x100);
file->create_date = HFSPLUS_I(HFSPLUS_SB(inode->i_sb).hidden_dir).create_date; file->create_date = HFSPLUS_I(sbi->hidden_dir)->create_date;
file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode).dev); file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode)->linkid);
} }
return sizeof(*file); return sizeof(*file);
} }
@ -180,15 +189,14 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode) int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode)
{ {
struct super_block *sb = dir->i_sb;
struct hfs_find_data fd; struct hfs_find_data fd;
struct super_block *sb;
hfsplus_cat_entry entry; hfsplus_cat_entry entry;
int entry_size; int entry_size;
int err; int err;
dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink); dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink);
sb = dir->i_sb; hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
entry_size = hfsplus_fill_cat_thread(sb, &entry, S_ISDIR(inode->i_mode) ? entry_size = hfsplus_fill_cat_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
@ -234,7 +242,7 @@ err2:
int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
{ {
struct super_block *sb; struct super_block *sb = dir->i_sb;
struct hfs_find_data fd; struct hfs_find_data fd;
struct hfsplus_fork_raw fork; struct hfsplus_fork_raw fork;
struct list_head *pos; struct list_head *pos;
@ -242,8 +250,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
u16 type; u16 type;
dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid); dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
sb = dir->i_sb; hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
if (!str) { if (!str) {
int len; int len;
@ -279,7 +286,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC); hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC);
} }
list_for_each(pos, &HFSPLUS_I(dir).open_dir_list) { list_for_each(pos, &HFSPLUS_I(dir)->open_dir_list) {
struct hfsplus_readdir_data *rd = struct hfsplus_readdir_data *rd =
list_entry(pos, struct hfsplus_readdir_data, list); list_entry(pos, struct hfsplus_readdir_data, list);
if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0) if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
@ -312,7 +319,7 @@ int hfsplus_rename_cat(u32 cnid,
struct inode *src_dir, struct qstr *src_name, struct inode *src_dir, struct qstr *src_name,
struct inode *dst_dir, struct qstr *dst_name) struct inode *dst_dir, struct qstr *dst_name)
{ {
struct super_block *sb; struct super_block *sb = src_dir->i_sb;
struct hfs_find_data src_fd, dst_fd; struct hfs_find_data src_fd, dst_fd;
hfsplus_cat_entry entry; hfsplus_cat_entry entry;
int entry_size, type; int entry_size, type;
@ -320,8 +327,7 @@ int hfsplus_rename_cat(u32 cnid,
dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name, dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name,
dst_dir->i_ino, dst_name->name); dst_dir->i_ino, dst_name->name);
sb = src_dir->i_sb; hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &src_fd);
dst_fd = src_fd; dst_fd = src_fd;
/* find the old dir entry and read the data */ /* find the old dir entry and read the data */

View File

@ -39,7 +39,7 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
dentry->d_op = &hfsplus_dentry_operations; dentry->d_op = &hfsplus_dentry_operations;
dentry->d_fsdata = NULL; dentry->d_fsdata = NULL;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name);
again: again:
err = hfs_brec_read(&fd, &entry, sizeof(entry)); err = hfs_brec_read(&fd, &entry, sizeof(entry));
@ -68,9 +68,9 @@ again:
cnid = be32_to_cpu(entry.file.id); cnid = be32_to_cpu(entry.file.id);
if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) && if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) &&
entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) && entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
(entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb).hidden_dir).create_date || (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->create_date ||
entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode).create_date) && entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode)->create_date) &&
HFSPLUS_SB(sb).hidden_dir) { HFSPLUS_SB(sb)->hidden_dir) {
struct qstr str; struct qstr str;
char name[32]; char name[32];
@ -86,7 +86,8 @@ again:
linkid = be32_to_cpu(entry.file.permissions.dev); linkid = be32_to_cpu(entry.file.permissions.dev);
str.len = sprintf(name, "iNode%d", linkid); str.len = sprintf(name, "iNode%d", linkid);
str.name = name; str.name = name;
hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str); hfsplus_cat_build_key(sb, fd.search_key,
HFSPLUS_SB(sb)->hidden_dir->i_ino, &str);
goto again; goto again;
} }
} else if (!dentry->d_fsdata) } else if (!dentry->d_fsdata)
@ -101,7 +102,7 @@ again:
if (IS_ERR(inode)) if (IS_ERR(inode))
return ERR_CAST(inode); return ERR_CAST(inode);
if (S_ISREG(inode->i_mode)) if (S_ISREG(inode->i_mode))
HFSPLUS_I(inode).dev = linkid; HFSPLUS_I(inode)->linkid = linkid;
out: out:
d_add(dentry, inode); d_add(dentry, inode);
return NULL; return NULL;
@ -124,7 +125,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (filp->f_pos >= inode->i_size) if (filp->f_pos >= inode->i_size)
return 0; return 0;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
err = hfs_brec_find(&fd); err = hfs_brec_find(&fd);
if (err) if (err)
@ -180,8 +181,9 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
err = -EIO; err = -EIO;
goto out; goto out;
} }
if (HFSPLUS_SB(sb).hidden_dir && if (HFSPLUS_SB(sb)->hidden_dir &&
HFSPLUS_SB(sb).hidden_dir->i_ino == be32_to_cpu(entry.folder.id)) HFSPLUS_SB(sb)->hidden_dir->i_ino ==
be32_to_cpu(entry.folder.id))
goto next; goto next;
if (filldir(dirent, strbuf, len, filp->f_pos, if (filldir(dirent, strbuf, len, filp->f_pos,
be32_to_cpu(entry.folder.id), DT_DIR)) be32_to_cpu(entry.folder.id), DT_DIR))
@ -217,7 +219,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
} }
filp->private_data = rd; filp->private_data = rd;
rd->file = filp; rd->file = filp;
list_add(&rd->list, &HFSPLUS_I(inode).open_dir_list); list_add(&rd->list, &HFSPLUS_I(inode)->open_dir_list);
} }
memcpy(&rd->key, fd.key, sizeof(struct hfsplus_cat_key)); memcpy(&rd->key, fd.key, sizeof(struct hfsplus_cat_key));
out: out:
@ -229,38 +231,18 @@ static int hfsplus_dir_release(struct inode *inode, struct file *file)
{ {
struct hfsplus_readdir_data *rd = file->private_data; struct hfsplus_readdir_data *rd = file->private_data;
if (rd) { if (rd) {
mutex_lock(&inode->i_mutex);
list_del(&rd->list); list_del(&rd->list);
mutex_unlock(&inode->i_mutex);
kfree(rd); kfree(rd);
} }
return 0; return 0;
} }
static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *nd)
{
struct inode *inode;
int res;
inode = hfsplus_new_inode(dir->i_sb, mode);
if (!inode)
return -ENOSPC;
res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
if (res) {
inode->i_nlink = 0;
hfsplus_delete_inode(inode);
iput(inode);
return res;
}
hfsplus_instantiate(dentry, inode, inode->i_ino);
mark_inode_dirty(inode);
return 0;
}
static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
struct dentry *dst_dentry) struct dentry *dst_dentry)
{ {
struct super_block *sb = dst_dir->i_sb; struct hfsplus_sb_info *sbi = HFSPLUS_SB(dst_dir->i_sb);
struct inode *inode = src_dentry->d_inode; struct inode *inode = src_dentry->d_inode;
struct inode *src_dir = src_dentry->d_parent->d_inode; struct inode *src_dir = src_dentry->d_parent->d_inode;
struct qstr str; struct qstr str;
@ -270,7 +252,10 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
if (HFSPLUS_IS_RSRC(inode)) if (HFSPLUS_IS_RSRC(inode))
return -EPERM; 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) { if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) {
for (;;) { for (;;) {
get_random_bytes(&id, sizeof(cnid)); get_random_bytes(&id, sizeof(cnid));
@ -279,40 +264,41 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
str.len = sprintf(name, "iNode%d", id); str.len = sprintf(name, "iNode%d", id);
res = hfsplus_rename_cat(inode->i_ino, res = hfsplus_rename_cat(inode->i_ino,
src_dir, &src_dentry->d_name, src_dir, &src_dentry->d_name,
HFSPLUS_SB(sb).hidden_dir, &str); sbi->hidden_dir, &str);
if (!res) if (!res)
break; break;
if (res != -EEXIST) if (res != -EEXIST)
return res; goto out;
} }
HFSPLUS_I(inode).dev = id; HFSPLUS_I(inode)->linkid = id;
cnid = HFSPLUS_SB(sb).next_cnid++; cnid = sbi->next_cnid++;
src_dentry->d_fsdata = (void *)(unsigned long)cnid; src_dentry->d_fsdata = (void *)(unsigned long)cnid;
res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode); res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode);
if (res) if (res)
/* panic? */ /* panic? */
return res; goto out;
HFSPLUS_SB(sb).file_count++; sbi->file_count++;
} }
cnid = HFSPLUS_SB(sb).next_cnid++; cnid = sbi->next_cnid++;
res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode); res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode);
if (res) if (res)
return res; goto out;
inc_nlink(inode); inc_nlink(inode);
hfsplus_instantiate(dst_dentry, inode, cnid); hfsplus_instantiate(dst_dentry, inode, cnid);
atomic_inc(&inode->i_count); atomic_inc(&inode->i_count);
inode->i_ctime = CURRENT_TIME_SEC; inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode); mark_inode_dirty(inode);
HFSPLUS_SB(sb).file_count++; sbi->file_count++;
sb->s_dirt = 1; dst_dir->i_sb->s_dirt = 1;
out:
return 0; mutex_unlock(&sbi->vh_mutex);
return res;
} }
static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
{ {
struct super_block *sb = dir->i_sb; struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct qstr str; struct qstr str;
char name[32]; char name[32];
@ -322,21 +308,22 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
if (HFSPLUS_IS_RSRC(inode)) if (HFSPLUS_IS_RSRC(inode))
return -EPERM; return -EPERM;
mutex_lock(&sbi->vh_mutex);
cnid = (u32)(unsigned long)dentry->d_fsdata; cnid = (u32)(unsigned long)dentry->d_fsdata;
if (inode->i_ino == cnid && if (inode->i_ino == cnid &&
atomic_read(&HFSPLUS_I(inode).opencnt)) { atomic_read(&HFSPLUS_I(inode)->opencnt)) {
str.name = name; str.name = name;
str.len = sprintf(name, "temp%lu", inode->i_ino); str.len = sprintf(name, "temp%lu", inode->i_ino);
res = hfsplus_rename_cat(inode->i_ino, res = hfsplus_rename_cat(inode->i_ino,
dir, &dentry->d_name, dir, &dentry->d_name,
HFSPLUS_SB(sb).hidden_dir, &str); sbi->hidden_dir, &str);
if (!res) if (!res)
inode->i_flags |= S_DEAD; inode->i_flags |= S_DEAD;
return res; goto out;
} }
res = hfsplus_delete_cat(cnid, dir, &dentry->d_name); res = hfsplus_delete_cat(cnid, dir, &dentry->d_name);
if (res) if (res)
return res; goto out;
if (inode->i_nlink > 0) if (inode->i_nlink > 0)
drop_nlink(inode); drop_nlink(inode);
@ -344,10 +331,10 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
clear_nlink(inode); clear_nlink(inode);
if (!inode->i_nlink) { if (!inode->i_nlink) {
if (inode->i_ino != cnid) { if (inode->i_ino != cnid) {
HFSPLUS_SB(sb).file_count--; sbi->file_count--;
if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { if (!atomic_read(&HFSPLUS_I(inode)->opencnt)) {
res = hfsplus_delete_cat(inode->i_ino, res = hfsplus_delete_cat(inode->i_ino,
HFSPLUS_SB(sb).hidden_dir, sbi->hidden_dir,
NULL); NULL);
if (!res) if (!res)
hfsplus_delete_inode(inode); hfsplus_delete_inode(inode);
@ -356,107 +343,108 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
} else } else
hfsplus_delete_inode(inode); hfsplus_delete_inode(inode);
} else } else
HFSPLUS_SB(sb).file_count--; sbi->file_count--;
inode->i_ctime = CURRENT_TIME_SEC; inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode); mark_inode_dirty(inode);
out:
mutex_unlock(&sbi->vh_mutex);
return res; return res;
} }
static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct inode *inode;
int res;
inode = hfsplus_new_inode(dir->i_sb, S_IFDIR | mode);
if (!inode)
return -ENOSPC;
res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
if (res) {
inode->i_nlink = 0;
hfsplus_delete_inode(inode);
iput(inode);
return res;
}
hfsplus_instantiate(dentry, inode, inode->i_ino);
mark_inode_dirty(inode);
return 0;
}
static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry) static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
{ {
struct inode *inode; struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
struct inode *inode = dentry->d_inode;
int res; int res;
inode = dentry->d_inode;
if (inode->i_size != 2) if (inode->i_size != 2)
return -ENOTEMPTY; return -ENOTEMPTY;
mutex_lock(&sbi->vh_mutex);
res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
if (res) if (res)
return res; goto out;
clear_nlink(inode); clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC; inode->i_ctime = CURRENT_TIME_SEC;
hfsplus_delete_inode(inode); hfsplus_delete_inode(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
return 0; out:
mutex_unlock(&sbi->vh_mutex);
return res;
} }
static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, static int hfsplus_symlink(struct inode *dir, struct dentry *dentry,
const char *symname) const char *symname)
{ {
struct super_block *sb; struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
struct inode *inode; struct inode *inode;
int res; int res = -ENOSPC;
sb = dir->i_sb; mutex_lock(&sbi->vh_mutex);
inode = hfsplus_new_inode(sb, S_IFLNK | S_IRWXUGO); inode = hfsplus_new_inode(dir->i_sb, S_IFLNK | S_IRWXUGO);
if (!inode) if (!inode)
return -ENOSPC; goto out;
res = page_symlink(inode, symname, strlen(symname) + 1); res = page_symlink(inode, symname, strlen(symname) + 1);
if (res) { if (res)
goto out_err;
res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
if (res)
goto out_err;
hfsplus_instantiate(dentry, inode, inode->i_ino);
mark_inode_dirty(inode);
goto out;
out_err:
inode->i_nlink = 0; inode->i_nlink = 0;
hfsplus_delete_inode(inode); hfsplus_delete_inode(inode);
iput(inode); iput(inode);
return res; out:
} mutex_unlock(&sbi->vh_mutex);
mark_inode_dirty(inode);
res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
if (!res) {
hfsplus_instantiate(dentry, inode, inode->i_ino);
mark_inode_dirty(inode);
}
return res; return res;
} }
static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, static int hfsplus_mknod(struct inode *dir, struct dentry *dentry,
int mode, dev_t rdev) int mode, dev_t rdev)
{ {
struct super_block *sb; struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
struct inode *inode; struct inode *inode;
int res; int res = -ENOSPC;
sb = dir->i_sb; mutex_lock(&sbi->vh_mutex);
inode = hfsplus_new_inode(sb, mode); inode = hfsplus_new_inode(dir->i_sb, mode);
if (!inode) if (!inode)
return -ENOSPC; goto out;
if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode))
init_special_inode(inode, mode, rdev);
res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
if (res) { if (res) {
inode->i_nlink = 0; inode->i_nlink = 0;
hfsplus_delete_inode(inode); hfsplus_delete_inode(inode);
iput(inode); iput(inode);
return res; goto out;
} }
init_special_inode(inode, mode, rdev);
hfsplus_instantiate(dentry, inode, inode->i_ino); hfsplus_instantiate(dentry, inode, inode->i_ino);
mark_inode_dirty(inode); mark_inode_dirty(inode);
out:
mutex_unlock(&sbi->vh_mutex);
return res;
}
return 0; static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *nd)
{
return hfsplus_mknod(dir, dentry, mode, 0);
}
static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
return hfsplus_mknod(dir, dentry, mode | S_IFDIR, 0);
} }
static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry, static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
@ -466,6 +454,9 @@ static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
/* Unlink destination if it already exists */ /* Unlink destination if it already exists */
if (new_dentry->d_inode) { if (new_dentry->d_inode) {
if (S_ISDIR(new_dentry->d_inode->i_mode))
res = hfsplus_rmdir(new_dir, new_dentry);
else
res = hfsplus_unlink(new_dir, new_dentry); res = hfsplus_unlink(new_dir, new_dentry);
if (res) if (res)
return res; return res;

View File

@ -85,33 +85,47 @@ static u32 hfsplus_ext_lastblock(struct hfsplus_extent *ext)
static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd)
{ {
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
int res; int res;
hfsplus_ext_build_key(fd->search_key, inode->i_ino, HFSPLUS_I(inode).cached_start, WARN_ON(!mutex_is_locked(&hip->extents_lock));
HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
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); res = hfs_brec_find(fd);
if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_NEW) { if (hip->flags & HFSPLUS_FLG_EXT_NEW) {
if (res != -ENOENT) if (res != -ENOENT)
return; return;
hfs_brec_insert(fd, HFSPLUS_I(inode).cached_extents, sizeof(hfsplus_extent_rec)); hfs_brec_insert(fd, hip->cached_extents,
HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); sizeof(hfsplus_extent_rec));
hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
} else { } else {
if (res) if (res)
return; return;
hfs_bnode_write(fd->bnode, HFSPLUS_I(inode).cached_extents, fd->entryoffset, fd->entrylength); hfs_bnode_write(fd->bnode, hip->cached_extents,
HFSPLUS_I(inode).flags &= ~HFSPLUS_FLG_EXT_DIRTY; fd->entryoffset, fd->entrylength);
hip->flags &= ~HFSPLUS_FLG_EXT_DIRTY;
}
}
static void hfsplus_ext_write_extent_locked(struct inode *inode)
{
if (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_EXT_DIRTY) {
struct hfs_find_data fd;
hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
__hfsplus_ext_write_extent(inode, &fd);
hfs_find_exit(&fd);
} }
} }
void hfsplus_ext_write_extent(struct inode *inode) void hfsplus_ext_write_extent(struct inode *inode)
{ {
if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_DIRTY) { mutex_lock(&HFSPLUS_I(inode)->extents_lock);
struct hfs_find_data fd; hfsplus_ext_write_extent_locked(inode);
mutex_unlock(&HFSPLUS_I(inode)->extents_lock);
hfs_find_init(HFSPLUS_SB(inode->i_sb).ext_tree, &fd);
__hfsplus_ext_write_extent(inode, &fd);
hfs_find_exit(&fd);
}
} }
static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
@ -136,33 +150,39 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block) 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; int res;
if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_DIRTY) WARN_ON(!mutex_is_locked(&hip->extents_lock));
if (hip->flags & HFSPLUS_FLG_EXT_DIRTY)
__hfsplus_ext_write_extent(inode, fd); __hfsplus_ext_write_extent(inode, fd);
res = __hfsplus_ext_read_extent(fd, HFSPLUS_I(inode).cached_extents, inode->i_ino, res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino,
block, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); block, HFSPLUS_IS_RSRC(inode) ?
HFSPLUS_TYPE_RSRC :
HFSPLUS_TYPE_DATA);
if (!res) { if (!res) {
HFSPLUS_I(inode).cached_start = be32_to_cpu(fd->key->ext.start_block); hip->cached_start = be32_to_cpu(fd->key->ext.start_block);
HFSPLUS_I(inode).cached_blocks = hfsplus_ext_block_count(HFSPLUS_I(inode).cached_extents); hip->cached_blocks = hfsplus_ext_block_count(hip->cached_extents);
} else { } else {
HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).cached_blocks = 0; hip->cached_start = hip->cached_blocks = 0;
HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
} }
return res; return res;
} }
static int hfsplus_ext_read_extent(struct inode *inode, u32 block) static int hfsplus_ext_read_extent(struct inode *inode, u32 block)
{ {
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
struct hfs_find_data fd; struct hfs_find_data fd;
int res; int res;
if (block >= HFSPLUS_I(inode).cached_start && if (block >= hip->cached_start &&
block < HFSPLUS_I(inode).cached_start + HFSPLUS_I(inode).cached_blocks) block < hip->cached_start + hip->cached_blocks)
return 0; return 0;
hfs_find_init(HFSPLUS_SB(inode->i_sb).ext_tree, &fd); hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
res = __hfsplus_ext_cache_extent(&fd, inode, block); res = __hfsplus_ext_cache_extent(&fd, inode, block);
hfs_find_exit(&fd); hfs_find_exit(&fd);
return res; return res;
@ -172,21 +192,21 @@ static int hfsplus_ext_read_extent(struct inode *inode, u32 block)
int hfsplus_get_block(struct inode *inode, sector_t iblock, int hfsplus_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create)
{ {
struct super_block *sb; struct super_block *sb = inode->i_sb;
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
int res = -EIO; int res = -EIO;
u32 ablock, dblock, mask; u32 ablock, dblock, mask;
int shift; int shift;
sb = inode->i_sb;
/* Convert inode block to disk allocation block */ /* Convert inode block to disk allocation block */
shift = HFSPLUS_SB(sb).alloc_blksz_shift - sb->s_blocksize_bits; shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
ablock = iblock >> HFSPLUS_SB(sb).fs_shift; ablock = iblock >> sbi->fs_shift;
if (iblock >= HFSPLUS_I(inode).fs_blocks) { if (iblock >= hip->fs_blocks) {
if (iblock > HFSPLUS_I(inode).fs_blocks || !create) if (iblock > hip->fs_blocks || !create)
return -EIO; return -EIO;
if (ablock >= HFSPLUS_I(inode).alloc_blocks) { if (ablock >= hip->alloc_blocks) {
res = hfsplus_file_extend(inode); res = hfsplus_file_extend(inode);
if (res) if (res)
return res; return res;
@ -194,33 +214,33 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
} else } else
create = 0; create = 0;
if (ablock < HFSPLUS_I(inode).first_blocks) { if (ablock < hip->first_blocks) {
dblock = hfsplus_ext_find_block(HFSPLUS_I(inode).first_extents, ablock); dblock = hfsplus_ext_find_block(hip->first_extents, ablock);
goto done; goto done;
} }
if (inode->i_ino == HFSPLUS_EXT_CNID) if (inode->i_ino == HFSPLUS_EXT_CNID)
return -EIO; return -EIO;
mutex_lock(&HFSPLUS_I(inode).extents_lock); mutex_lock(&hip->extents_lock);
res = hfsplus_ext_read_extent(inode, ablock); res = hfsplus_ext_read_extent(inode, ablock);
if (!res) { if (!res) {
dblock = hfsplus_ext_find_block(HFSPLUS_I(inode).cached_extents, ablock - dblock = hfsplus_ext_find_block(hip->cached_extents,
HFSPLUS_I(inode).cached_start); ablock - hip->cached_start);
} else { } else {
mutex_unlock(&HFSPLUS_I(inode).extents_lock); mutex_unlock(&hip->extents_lock);
return -EIO; return -EIO;
} }
mutex_unlock(&HFSPLUS_I(inode).extents_lock); mutex_unlock(&hip->extents_lock);
done: done:
dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", inode->i_ino, (long long)iblock, dblock); dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", inode->i_ino, (long long)iblock, dblock);
mask = (1 << HFSPLUS_SB(sb).fs_shift) - 1; mask = (1 << sbi->fs_shift) - 1;
map_bh(bh_result, sb, (dblock << HFSPLUS_SB(sb).fs_shift) + HFSPLUS_SB(sb).blockoffset + (iblock & mask)); map_bh(bh_result, sb, (dblock << sbi->fs_shift) + sbi->blockoffset + (iblock & mask));
if (create) { if (create) {
set_buffer_new(bh_result); set_buffer_new(bh_result);
HFSPLUS_I(inode).phys_size += sb->s_blocksize; hip->phys_size += sb->s_blocksize;
HFSPLUS_I(inode).fs_blocks++; hip->fs_blocks++;
inode_add_bytes(inode, sb->s_blocksize); inode_add_bytes(inode, sb->s_blocksize);
mark_inode_dirty(inode); mark_inode_dirty(inode);
} }
@ -327,7 +347,7 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw
if (total_blocks == blocks) if (total_blocks == blocks)
return 0; return 0;
hfs_find_init(HFSPLUS_SB(sb).ext_tree, &fd); hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
do { do {
res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid, res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid,
total_blocks, type); total_blocks, type);
@ -348,29 +368,33 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw
int hfsplus_file_extend(struct inode *inode) int hfsplus_file_extend(struct inode *inode)
{ {
struct super_block *sb = inode->i_sb; 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; u32 start, len, goal;
int res; int res;
if (HFSPLUS_SB(sb).alloc_file->i_size * 8 < HFSPLUS_SB(sb).total_blocks - HFSPLUS_SB(sb).free_blocks + 8) { if (sbi->alloc_file->i_size * 8 <
sbi->total_blocks - sbi->free_blocks + 8) {
// extend alloc file // extend alloc file
printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8, printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n",
HFSPLUS_SB(sb).total_blocks, HFSPLUS_SB(sb).free_blocks); sbi->alloc_file->i_size * 8,
sbi->total_blocks, sbi->free_blocks);
return -ENOSPC; return -ENOSPC;
} }
mutex_lock(&HFSPLUS_I(inode).extents_lock); mutex_lock(&hip->extents_lock);
if (HFSPLUS_I(inode).alloc_blocks == HFSPLUS_I(inode).first_blocks) if (hip->alloc_blocks == hip->first_blocks)
goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).first_extents); goal = hfsplus_ext_lastblock(hip->first_extents);
else { else {
res = hfsplus_ext_read_extent(inode, HFSPLUS_I(inode).alloc_blocks); res = hfsplus_ext_read_extent(inode, hip->alloc_blocks);
if (res) if (res)
goto out; goto out;
goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).cached_extents); goal = hfsplus_ext_lastblock(hip->cached_extents);
} }
len = HFSPLUS_I(inode).clump_blocks; len = hip->clump_blocks;
start = hfsplus_block_allocate(sb, HFSPLUS_SB(sb).total_blocks, goal, &len); start = hfsplus_block_allocate(sb, sbi->total_blocks, goal, &len);
if (start >= HFSPLUS_SB(sb).total_blocks) { if (start >= sbi->total_blocks) {
start = hfsplus_block_allocate(sb, goal, 0, &len); start = hfsplus_block_allocate(sb, goal, 0, &len);
if (start >= goal) { if (start >= goal) {
res = -ENOSPC; res = -ENOSPC;
@ -379,56 +403,56 @@ int hfsplus_file_extend(struct inode *inode)
} }
dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len); dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
if (HFSPLUS_I(inode).alloc_blocks <= HFSPLUS_I(inode).first_blocks) {
if (!HFSPLUS_I(inode).first_blocks) { if (hip->alloc_blocks <= hip->first_blocks) {
if (!hip->first_blocks) {
dprint(DBG_EXTENT, "first extents\n"); dprint(DBG_EXTENT, "first extents\n");
/* no extents yet */ /* no extents yet */
HFSPLUS_I(inode).first_extents[0].start_block = cpu_to_be32(start); hip->first_extents[0].start_block = cpu_to_be32(start);
HFSPLUS_I(inode).first_extents[0].block_count = cpu_to_be32(len); hip->first_extents[0].block_count = cpu_to_be32(len);
res = 0; res = 0;
} else { } else {
/* try to append to extents in inode */ /* try to append to extents in inode */
res = hfsplus_add_extent(HFSPLUS_I(inode).first_extents, res = hfsplus_add_extent(hip->first_extents,
HFSPLUS_I(inode).alloc_blocks, hip->alloc_blocks,
start, len); start, len);
if (res == -ENOSPC) if (res == -ENOSPC)
goto insert_extent; goto insert_extent;
} }
if (!res) { if (!res) {
hfsplus_dump_extent(HFSPLUS_I(inode).first_extents); hfsplus_dump_extent(hip->first_extents);
HFSPLUS_I(inode).first_blocks += len; hip->first_blocks += len;
} }
} else { } else {
res = hfsplus_add_extent(HFSPLUS_I(inode).cached_extents, res = hfsplus_add_extent(hip->cached_extents,
HFSPLUS_I(inode).alloc_blocks - hip->alloc_blocks - hip->cached_start,
HFSPLUS_I(inode).cached_start,
start, len); start, len);
if (!res) { if (!res) {
hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); hfsplus_dump_extent(hip->cached_extents);
HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY; hip->flags |= HFSPLUS_FLG_EXT_DIRTY;
HFSPLUS_I(inode).cached_blocks += len; hip->cached_blocks += len;
} else if (res == -ENOSPC) } else if (res == -ENOSPC)
goto insert_extent; goto insert_extent;
} }
out: out:
mutex_unlock(&HFSPLUS_I(inode).extents_lock); mutex_unlock(&hip->extents_lock);
if (!res) { if (!res) {
HFSPLUS_I(inode).alloc_blocks += len; hip->alloc_blocks += len;
mark_inode_dirty(inode); mark_inode_dirty(inode);
} }
return res; return res;
insert_extent: insert_extent:
dprint(DBG_EXTENT, "insert new extent\n"); dprint(DBG_EXTENT, "insert new extent\n");
hfsplus_ext_write_extent(inode); hfsplus_ext_write_extent_locked(inode);
memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec)); memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
HFSPLUS_I(inode).cached_extents[0].start_block = cpu_to_be32(start); hip->cached_extents[0].start_block = cpu_to_be32(start);
HFSPLUS_I(inode).cached_extents[0].block_count = cpu_to_be32(len); hip->cached_extents[0].block_count = cpu_to_be32(len);
hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); hfsplus_dump_extent(hip->cached_extents);
HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW; hip->flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW;
HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).alloc_blocks; hip->cached_start = hip->alloc_blocks;
HFSPLUS_I(inode).cached_blocks = len; hip->cached_blocks = len;
res = 0; res = 0;
goto out; goto out;
@ -437,13 +461,15 @@ insert_extent:
void hfsplus_file_truncate(struct inode *inode) void hfsplus_file_truncate(struct inode *inode)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
struct hfs_find_data fd; struct hfs_find_data fd;
u32 alloc_cnt, blk_cnt, start; u32 alloc_cnt, blk_cnt, start;
int res; int res;
dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n", inode->i_ino, dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n",
(long long)HFSPLUS_I(inode).phys_size, inode->i_size); inode->i_ino, (long long)hip->phys_size, inode->i_size);
if (inode->i_size > HFSPLUS_I(inode).phys_size) {
if (inode->i_size > hip->phys_size) {
struct address_space *mapping = inode->i_mapping; struct address_space *mapping = inode->i_mapping;
struct page *page; struct page *page;
void *fsdata; void *fsdata;
@ -460,47 +486,48 @@ void hfsplus_file_truncate(struct inode *inode)
return; return;
mark_inode_dirty(inode); mark_inode_dirty(inode);
return; return;
} else if (inode->i_size == HFSPLUS_I(inode).phys_size) } else if (inode->i_size == hip->phys_size)
return; return;
blk_cnt = (inode->i_size + HFSPLUS_SB(sb).alloc_blksz - 1) >> HFSPLUS_SB(sb).alloc_blksz_shift; blk_cnt = (inode->i_size + HFSPLUS_SB(sb)->alloc_blksz - 1) >>
alloc_cnt = HFSPLUS_I(inode).alloc_blocks; HFSPLUS_SB(sb)->alloc_blksz_shift;
alloc_cnt = hip->alloc_blocks;
if (blk_cnt == alloc_cnt) if (blk_cnt == alloc_cnt)
goto out; goto out;
mutex_lock(&HFSPLUS_I(inode).extents_lock); mutex_lock(&hip->extents_lock);
hfs_find_init(HFSPLUS_SB(sb).ext_tree, &fd); hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
while (1) { while (1) {
if (alloc_cnt == HFSPLUS_I(inode).first_blocks) { if (alloc_cnt == hip->first_blocks) {
hfsplus_free_extents(sb, HFSPLUS_I(inode).first_extents, hfsplus_free_extents(sb, hip->first_extents,
alloc_cnt, alloc_cnt - blk_cnt); alloc_cnt, alloc_cnt - blk_cnt);
hfsplus_dump_extent(HFSPLUS_I(inode).first_extents); hfsplus_dump_extent(hip->first_extents);
HFSPLUS_I(inode).first_blocks = blk_cnt; hip->first_blocks = blk_cnt;
break; break;
} }
res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt); res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt);
if (res) if (res)
break; break;
start = HFSPLUS_I(inode).cached_start; start = hip->cached_start;
hfsplus_free_extents(sb, HFSPLUS_I(inode).cached_extents, hfsplus_free_extents(sb, hip->cached_extents,
alloc_cnt - start, alloc_cnt - blk_cnt); alloc_cnt - start, alloc_cnt - blk_cnt);
hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); hfsplus_dump_extent(hip->cached_extents);
if (blk_cnt > start) { if (blk_cnt > start) {
HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY; hip->flags |= HFSPLUS_FLG_EXT_DIRTY;
break; break;
} }
alloc_cnt = start; alloc_cnt = start;
HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).cached_blocks = 0; hip->cached_start = hip->cached_blocks = 0;
HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
hfs_brec_remove(&fd); hfs_brec_remove(&fd);
} }
hfs_find_exit(&fd); hfs_find_exit(&fd);
mutex_unlock(&HFSPLUS_I(inode).extents_lock); mutex_unlock(&hip->extents_lock);
HFSPLUS_I(inode).alloc_blocks = blk_cnt; hip->alloc_blocks = blk_cnt;
out: out:
HFSPLUS_I(inode).phys_size = inode->i_size; hip->phys_size = inode->i_size;
HFSPLUS_I(inode).fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
inode_set_bytes(inode, HFSPLUS_I(inode).fs_blocks << sb->s_blocksize_bits); inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
mark_inode_dirty(inode); mark_inode_dirty(inode);
} }

View File

@ -62,7 +62,7 @@ struct hfs_btree {
unsigned int depth; unsigned int depth;
//unsigned int map1_size, map_size; //unsigned int map1_size, map_size;
struct semaphore tree_lock; struct mutex tree_lock;
unsigned int pages_per_bnode; unsigned int pages_per_bnode;
spinlock_t hash_lock; spinlock_t hash_lock;
@ -121,16 +121,21 @@ struct hfsplus_sb_info {
u32 sect_count; u32 sect_count;
int fs_shift; int fs_shift;
/* Stuff in host order from Vol Header */ /* immutable data from the volume header */
u32 alloc_blksz; u32 alloc_blksz;
int alloc_blksz_shift; int alloc_blksz_shift;
u32 total_blocks; u32 total_blocks;
u32 data_clump_blocks, rsrc_clump_blocks;
/* mutable data from the volume header, protected by alloc_mutex */
u32 free_blocks; u32 free_blocks;
u32 next_alloc; struct mutex alloc_mutex;
/* mutable data from the volume header, protected by vh_mutex */
u32 next_cnid; u32 next_cnid;
u32 file_count; u32 file_count;
u32 folder_count; u32 folder_count;
u32 data_clump_blocks, rsrc_clump_blocks; struct mutex vh_mutex;
/* Config options */ /* Config options */
u32 creator; u32 creator;
@ -143,40 +148,50 @@ struct hfsplus_sb_info {
int part, session; int part, session;
unsigned long flags; unsigned long flags;
struct hlist_head rsrc_inodes;
}; };
#define HFSPLUS_SB_WRITEBACKUP 0x0001 #define HFSPLUS_SB_WRITEBACKUP 0
#define HFSPLUS_SB_NODECOMPOSE 0x0002 #define HFSPLUS_SB_NODECOMPOSE 1
#define HFSPLUS_SB_FORCE 0x0004 #define HFSPLUS_SB_FORCE 2
#define HFSPLUS_SB_HFSX 0x0008 #define HFSPLUS_SB_HFSX 3
#define HFSPLUS_SB_CASEFOLD 0x0010 #define HFSPLUS_SB_CASEFOLD 4
struct hfsplus_inode_info { struct hfsplus_inode_info {
struct mutex extents_lock;
u32 clump_blocks, alloc_blocks;
sector_t fs_blocks;
/* Allocation extents from catalog record or volume header */
hfsplus_extent_rec first_extents;
u32 first_blocks;
hfsplus_extent_rec cached_extents;
u32 cached_start, cached_blocks;
atomic_t opencnt; atomic_t opencnt;
struct inode *rsrc_inode; /*
* Extent allocation information, protected by extents_lock.
*/
u32 first_blocks;
u32 clump_blocks;
u32 alloc_blocks;
u32 cached_start;
u32 cached_blocks;
hfsplus_extent_rec first_extents;
hfsplus_extent_rec cached_extents;
unsigned long flags; unsigned long flags;
struct mutex extents_lock;
/*
* Immutable data.
*/
struct inode *rsrc_inode;
__be32 create_date; __be32 create_date;
/* Device number in hfsplus_permissions in catalog */
u32 dev;
/* BSD system and user file flags */
u8 rootflags;
u8 userflags;
/*
* Protected by sbi->vh_mutex.
*/
u32 linkid;
/*
* Protected by i_mutex.
*/
sector_t fs_blocks;
u8 userflags; /* BSD user file flags */
struct list_head open_dir_list; struct list_head open_dir_list;
loff_t phys_size; loff_t phys_size;
struct inode vfs_inode; struct inode vfs_inode;
}; };
@ -184,8 +199,8 @@ struct hfsplus_inode_info {
#define HFSPLUS_FLG_EXT_DIRTY 0x0002 #define HFSPLUS_FLG_EXT_DIRTY 0x0002
#define HFSPLUS_FLG_EXT_NEW 0x0004 #define HFSPLUS_FLG_EXT_NEW 0x0004
#define HFSPLUS_IS_DATA(inode) (!(HFSPLUS_I(inode).flags & HFSPLUS_FLG_RSRC)) #define HFSPLUS_IS_DATA(inode) (!(HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC))
#define HFSPLUS_IS_RSRC(inode) (HFSPLUS_I(inode).flags & HFSPLUS_FLG_RSRC) #define HFSPLUS_IS_RSRC(inode) (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC)
struct hfs_find_data { struct hfs_find_data {
/* filled by caller */ /* filled by caller */
@ -311,6 +326,7 @@ int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *);
int hfsplus_delete_cat(u32, struct inode *, struct qstr *); int hfsplus_delete_cat(u32, struct inode *, struct qstr *);
int hfsplus_rename_cat(u32, struct inode *, struct qstr *, int hfsplus_rename_cat(u32, struct inode *, struct qstr *,
struct inode *, struct qstr *); struct inode *, struct qstr *);
void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms);
/* dir.c */ /* dir.c */
extern const struct inode_operations hfsplus_dir_inode_operations; extern const struct inode_operations hfsplus_dir_inode_operations;
@ -372,26 +388,15 @@ int hfsplus_read_wrapper(struct super_block *);
int hfs_part_find(struct super_block *, sector_t *, sector_t *); int hfs_part_find(struct super_block *, sector_t *, sector_t *);
/* access macros */ /* access macros */
/*
static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb) static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
{ {
return sb->s_fs_info; return sb->s_fs_info;
} }
static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode) static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
{ {
return list_entry(inode, struct hfsplus_inode_info, vfs_inode); return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
} }
*/
#define HFSPLUS_SB(super) (*(struct hfsplus_sb_info *)(super)->s_fs_info)
#define HFSPLUS_I(inode) (*list_entry(inode, struct hfsplus_inode_info, vfs_inode))
#if 1
#define hfsplus_kmap(p) ({ struct page *__p = (p); kmap(__p); })
#define hfsplus_kunmap(p) ({ struct page *__p = (p); kunmap(__p); __p; })
#else
#define hfsplus_kmap(p) kmap(p)
#define hfsplus_kunmap(p) kunmap(p)
#endif
#define sb_bread512(sb, sec, data) ({ \ #define sb_bread512(sb, sec, data) ({ \
struct buffer_head *__bh; \ struct buffer_head *__bh; \
@ -419,6 +424,4 @@ static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
#define hfsp_ut2mt(t) __hfsp_ut2mt((t).tv_sec) #define hfsp_ut2mt(t) __hfsp_ut2mt((t).tv_sec)
#define hfsp_now2mt() __hfsp_ut2mt(get_seconds()) #define hfsp_now2mt() __hfsp_ut2mt(get_seconds())
#define kdev_t_to_nr(x) (x)
#endif #endif

View File

@ -200,6 +200,7 @@ struct hfsplus_cat_key {
struct hfsplus_unistr name; struct hfsplus_unistr name;
} __packed; } __packed;
#define HFSPLUS_CAT_KEYLEN (sizeof(struct hfsplus_cat_key))
/* Structs from hfs.h */ /* Structs from hfs.h */
struct hfsp_point { struct hfsp_point {
@ -323,7 +324,7 @@ struct hfsplus_ext_key {
__be32 start_block; __be32 start_block;
} __packed; } __packed;
#define HFSPLUS_EXT_KEYLEN 12 #define HFSPLUS_EXT_KEYLEN sizeof(struct hfsplus_ext_key)
/* HFS+ generic BTree key */ /* HFS+ generic BTree key */
typedef union { typedef union {

View File

@ -36,7 +36,7 @@ static int hfsplus_write_begin(struct file *file, struct address_space *mapping,
*pagep = NULL; *pagep = NULL;
ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
hfsplus_get_block, hfsplus_get_block,
&HFSPLUS_I(mapping->host).phys_size); &HFSPLUS_I(mapping->host)->phys_size);
if (unlikely(ret)) { if (unlikely(ret)) {
loff_t isize = mapping->host->i_size; loff_t isize = mapping->host->i_size;
if (pos + len > isize) if (pos + len > isize)
@ -62,13 +62,13 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
switch (inode->i_ino) { switch (inode->i_ino) {
case HFSPLUS_EXT_CNID: case HFSPLUS_EXT_CNID:
tree = HFSPLUS_SB(sb).ext_tree; tree = HFSPLUS_SB(sb)->ext_tree;
break; break;
case HFSPLUS_CAT_CNID: case HFSPLUS_CAT_CNID:
tree = HFSPLUS_SB(sb).cat_tree; tree = HFSPLUS_SB(sb)->cat_tree;
break; break;
case HFSPLUS_ATTR_CNID: case HFSPLUS_ATTR_CNID:
tree = HFSPLUS_SB(sb).attr_tree; tree = HFSPLUS_SB(sb)->attr_tree;
break; break;
default: default:
BUG(); BUG();
@ -172,12 +172,13 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
struct hfs_find_data fd; struct hfs_find_data fd;
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
struct inode *inode = NULL; struct inode *inode = NULL;
struct hfsplus_inode_info *hip;
int err; int err;
if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc")) if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
goto out; goto out;
inode = HFSPLUS_I(dir).rsrc_inode; inode = HFSPLUS_I(dir)->rsrc_inode;
if (inode) if (inode)
goto out; goto out;
@ -185,12 +186,13 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
if (!inode) if (!inode)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
hip = HFSPLUS_I(inode);
inode->i_ino = dir->i_ino; inode->i_ino = dir->i_ino;
INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); INIT_LIST_HEAD(&hip->open_dir_list);
mutex_init(&HFSPLUS_I(inode).extents_lock); mutex_init(&hip->extents_lock);
HFSPLUS_I(inode).flags = HFSPLUS_FLG_RSRC; hip->flags = HFSPLUS_FLG_RSRC;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
err = hfsplus_find_cat(sb, dir->i_ino, &fd); err = hfsplus_find_cat(sb, dir->i_ino, &fd);
if (!err) if (!err)
err = hfsplus_cat_read_inode(inode, &fd); err = hfsplus_cat_read_inode(inode, &fd);
@ -199,10 +201,18 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
iput(inode); iput(inode);
return ERR_PTR(err); return ERR_PTR(err);
} }
HFSPLUS_I(inode).rsrc_inode = dir; hip->rsrc_inode = dir;
HFSPLUS_I(dir).rsrc_inode = inode; HFSPLUS_I(dir)->rsrc_inode = inode;
igrab(dir); igrab(dir);
hlist_add_head(&inode->i_hash, &HFSPLUS_SB(sb).rsrc_inodes);
/*
* __mark_inode_dirty expects inodes to be hashed. Since we don't
* want resource fork inodes in the regular inode space, we make them
* appear hashed, but do not put on any lists. hlist_del()
* will work fine and require no locking.
*/
inode->i_hash.pprev = &inode->i_hash.next;
mark_inode_dirty(inode); mark_inode_dirty(inode);
out: out:
d_add(dentry, inode); d_add(dentry, inode);
@ -211,30 +221,27 @@ out:
static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir) static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir)
{ {
struct super_block *sb = inode->i_sb; struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
u16 mode; u16 mode;
mode = be16_to_cpu(perms->mode); mode = be16_to_cpu(perms->mode);
inode->i_uid = be32_to_cpu(perms->owner); inode->i_uid = be32_to_cpu(perms->owner);
if (!inode->i_uid && !mode) if (!inode->i_uid && !mode)
inode->i_uid = HFSPLUS_SB(sb).uid; inode->i_uid = sbi->uid;
inode->i_gid = be32_to_cpu(perms->group); inode->i_gid = be32_to_cpu(perms->group);
if (!inode->i_gid && !mode) if (!inode->i_gid && !mode)
inode->i_gid = HFSPLUS_SB(sb).gid; inode->i_gid = sbi->gid;
if (dir) { if (dir) {
mode = mode ? (mode & S_IALLUGO) : mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask));
(S_IRWXUGO & ~(HFSPLUS_SB(sb).umask));
mode |= S_IFDIR; mode |= S_IFDIR;
} else if (!mode) } else if (!mode)
mode = S_IFREG | ((S_IRUGO|S_IWUGO) & mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask));
~(HFSPLUS_SB(sb).umask));
inode->i_mode = mode; inode->i_mode = mode;
HFSPLUS_I(inode).rootflags = perms->rootflags; HFSPLUS_I(inode)->userflags = perms->userflags;
HFSPLUS_I(inode).userflags = perms->userflags;
if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE) if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
inode->i_flags |= S_IMMUTABLE; inode->i_flags |= S_IMMUTABLE;
else else
@ -245,30 +252,13 @@ static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, i
inode->i_flags &= ~S_APPEND; inode->i_flags &= ~S_APPEND;
} }
static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
{
if (inode->i_flags & S_IMMUTABLE)
perms->rootflags |= HFSPLUS_FLG_IMMUTABLE;
else
perms->rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
if (inode->i_flags & S_APPEND)
perms->rootflags |= HFSPLUS_FLG_APPEND;
else
perms->rootflags &= ~HFSPLUS_FLG_APPEND;
perms->userflags = HFSPLUS_I(inode).userflags;
perms->mode = cpu_to_be16(inode->i_mode);
perms->owner = cpu_to_be32(inode->i_uid);
perms->group = cpu_to_be32(inode->i_gid);
perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
}
static int hfsplus_file_open(struct inode *inode, struct file *file) static int hfsplus_file_open(struct inode *inode, struct file *file)
{ {
if (HFSPLUS_IS_RSRC(inode)) if (HFSPLUS_IS_RSRC(inode))
inode = HFSPLUS_I(inode).rsrc_inode; inode = HFSPLUS_I(inode)->rsrc_inode;
if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
return -EOVERFLOW; return -EOVERFLOW;
atomic_inc(&HFSPLUS_I(inode).opencnt); atomic_inc(&HFSPLUS_I(inode)->opencnt);
return 0; return 0;
} }
@ -277,12 +267,13 @@ static int hfsplus_file_release(struct inode *inode, struct file *file)
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
if (HFSPLUS_IS_RSRC(inode)) if (HFSPLUS_IS_RSRC(inode))
inode = HFSPLUS_I(inode).rsrc_inode; inode = HFSPLUS_I(inode)->rsrc_inode;
if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) { if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) {
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
hfsplus_file_truncate(inode); hfsplus_file_truncate(inode);
if (inode->i_flags & S_DEAD) { if (inode->i_flags & S_DEAD) {
hfsplus_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL); hfsplus_delete_cat(inode->i_ino,
HFSPLUS_SB(sb)->hidden_dir, NULL);
hfsplus_delete_inode(inode); hfsplus_delete_inode(inode);
} }
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
@ -361,47 +352,52 @@ static const struct file_operations hfsplus_file_operations = {
struct inode *hfsplus_new_inode(struct super_block *sb, int mode) struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
{ {
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
struct inode *inode = new_inode(sb); struct inode *inode = new_inode(sb);
struct hfsplus_inode_info *hip;
if (!inode) if (!inode)
return NULL; return NULL;
inode->i_ino = HFSPLUS_SB(sb).next_cnid++; inode->i_ino = sbi->next_cnid++;
inode->i_mode = mode; inode->i_mode = mode;
inode->i_uid = current_fsuid(); inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid(); inode->i_gid = current_fsgid();
inode->i_nlink = 1; inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
mutex_init(&HFSPLUS_I(inode).extents_lock); hip = HFSPLUS_I(inode);
atomic_set(&HFSPLUS_I(inode).opencnt, 0); INIT_LIST_HEAD(&hip->open_dir_list);
HFSPLUS_I(inode).flags = 0; mutex_init(&hip->extents_lock);
memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec)); atomic_set(&hip->opencnt, 0);
memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec)); hip->flags = 0;
HFSPLUS_I(inode).alloc_blocks = 0; memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
HFSPLUS_I(inode).first_blocks = 0; memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
HFSPLUS_I(inode).cached_start = 0; hip->alloc_blocks = 0;
HFSPLUS_I(inode).cached_blocks = 0; hip->first_blocks = 0;
HFSPLUS_I(inode).phys_size = 0; hip->cached_start = 0;
HFSPLUS_I(inode).fs_blocks = 0; hip->cached_blocks = 0;
HFSPLUS_I(inode).rsrc_inode = NULL; hip->phys_size = 0;
hip->fs_blocks = 0;
hip->rsrc_inode = NULL;
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode)) {
inode->i_size = 2; inode->i_size = 2;
HFSPLUS_SB(sb).folder_count++; sbi->folder_count++;
inode->i_op = &hfsplus_dir_inode_operations; inode->i_op = &hfsplus_dir_inode_operations;
inode->i_fop = &hfsplus_dir_operations; inode->i_fop = &hfsplus_dir_operations;
} else if (S_ISREG(inode->i_mode)) { } else if (S_ISREG(inode->i_mode)) {
HFSPLUS_SB(sb).file_count++; sbi->file_count++;
inode->i_op = &hfsplus_file_inode_operations; inode->i_op = &hfsplus_file_inode_operations;
inode->i_fop = &hfsplus_file_operations; inode->i_fop = &hfsplus_file_operations;
inode->i_mapping->a_ops = &hfsplus_aops; inode->i_mapping->a_ops = &hfsplus_aops;
HFSPLUS_I(inode).clump_blocks = HFSPLUS_SB(sb).data_clump_blocks; hip->clump_blocks = sbi->data_clump_blocks;
} else if (S_ISLNK(inode->i_mode)) { } else if (S_ISLNK(inode->i_mode)) {
HFSPLUS_SB(sb).file_count++; sbi->file_count++;
inode->i_op = &page_symlink_inode_operations; inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &hfsplus_aops; inode->i_mapping->a_ops = &hfsplus_aops;
HFSPLUS_I(inode).clump_blocks = 1; hip->clump_blocks = 1;
} else } else
HFSPLUS_SB(sb).file_count++; sbi->file_count++;
insert_inode_hash(inode); insert_inode_hash(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
sb->s_dirt = 1; sb->s_dirt = 1;
@ -414,11 +410,11 @@ void hfsplus_delete_inode(struct inode *inode)
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode)) {
HFSPLUS_SB(sb).folder_count--; HFSPLUS_SB(sb)->folder_count--;
sb->s_dirt = 1; sb->s_dirt = 1;
return; return;
} }
HFSPLUS_SB(sb).file_count--; HFSPLUS_SB(sb)->file_count--;
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
if (!inode->i_nlink) { if (!inode->i_nlink) {
inode->i_size = 0; inode->i_size = 0;
@ -434,34 +430,39 @@ void hfsplus_delete_inode(struct inode *inode)
void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork) void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
u32 count; u32 count;
int i; int i;
memcpy(&HFSPLUS_I(inode).first_extents, &fork->extents, memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec));
sizeof(hfsplus_extent_rec));
for (count = 0, i = 0; i < 8; i++) for (count = 0, i = 0; i < 8; i++)
count += be32_to_cpu(fork->extents[i].block_count); count += be32_to_cpu(fork->extents[i].block_count);
HFSPLUS_I(inode).first_blocks = count; hip->first_blocks = count;
memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec)); memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
HFSPLUS_I(inode).cached_start = 0; hip->cached_start = 0;
HFSPLUS_I(inode).cached_blocks = 0; hip->cached_blocks = 0;
HFSPLUS_I(inode).alloc_blocks = be32_to_cpu(fork->total_blocks); hip->alloc_blocks = be32_to_cpu(fork->total_blocks);
inode->i_size = HFSPLUS_I(inode).phys_size = be64_to_cpu(fork->total_size); hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size);
HFSPLUS_I(inode).fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; hip->fs_blocks =
inode_set_bytes(inode, HFSPLUS_I(inode).fs_blocks << sb->s_blocksize_bits); (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
HFSPLUS_I(inode).clump_blocks = be32_to_cpu(fork->clump_size) >> HFSPLUS_SB(sb).alloc_blksz_shift; inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
if (!HFSPLUS_I(inode).clump_blocks) hip->clump_blocks =
HFSPLUS_I(inode).clump_blocks = HFSPLUS_IS_RSRC(inode) ? HFSPLUS_SB(sb).rsrc_clump_blocks : be32_to_cpu(fork->clump_size) >> sbi->alloc_blksz_shift;
HFSPLUS_SB(sb).data_clump_blocks; if (!hip->clump_blocks) {
hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ?
sbi->rsrc_clump_blocks :
sbi->data_clump_blocks;
}
} }
void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork) void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
{ {
memcpy(&fork->extents, &HFSPLUS_I(inode).first_extents, memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
sizeof(hfsplus_extent_rec)); sizeof(hfsplus_extent_rec));
fork->total_size = cpu_to_be64(inode->i_size); fork->total_size = cpu_to_be64(inode->i_size);
fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode).alloc_blocks); fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks);
} }
int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
@ -472,7 +473,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset); type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
HFSPLUS_I(inode).dev = 0; HFSPLUS_I(inode)->linkid = 0;
if (type == HFSPLUS_FOLDER) { if (type == HFSPLUS_FOLDER) {
struct hfsplus_cat_folder *folder = &entry.folder; struct hfsplus_cat_folder *folder = &entry.folder;
@ -486,8 +487,8 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
inode->i_atime = hfsp_mt2ut(folder->access_date); inode->i_atime = hfsp_mt2ut(folder->access_date);
inode->i_mtime = hfsp_mt2ut(folder->content_mod_date); inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date); inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
HFSPLUS_I(inode).create_date = folder->create_date; HFSPLUS_I(inode)->create_date = folder->create_date;
HFSPLUS_I(inode).fs_blocks = 0; HFSPLUS_I(inode)->fs_blocks = 0;
inode->i_op = &hfsplus_dir_inode_operations; inode->i_op = &hfsplus_dir_inode_operations;
inode->i_fop = &hfsplus_dir_operations; inode->i_fop = &hfsplus_dir_operations;
} else if (type == HFSPLUS_FILE) { } else if (type == HFSPLUS_FILE) {
@ -518,7 +519,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
inode->i_atime = hfsp_mt2ut(file->access_date); inode->i_atime = hfsp_mt2ut(file->access_date);
inode->i_mtime = hfsp_mt2ut(file->content_mod_date); inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date); inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date);
HFSPLUS_I(inode).create_date = file->create_date; HFSPLUS_I(inode)->create_date = file->create_date;
} else { } else {
printk(KERN_ERR "hfs: bad catalog entry used to create inode\n"); printk(KERN_ERR "hfs: bad catalog entry used to create inode\n");
res = -EIO; res = -EIO;
@ -533,12 +534,12 @@ int hfsplus_cat_write_inode(struct inode *inode)
hfsplus_cat_entry entry; hfsplus_cat_entry entry;
if (HFSPLUS_IS_RSRC(inode)) if (HFSPLUS_IS_RSRC(inode))
main_inode = HFSPLUS_I(inode).rsrc_inode; main_inode = HFSPLUS_I(inode)->rsrc_inode;
if (!main_inode->i_nlink) if (!main_inode->i_nlink)
return 0; return 0;
if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb).cat_tree, &fd)) if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd))
/* panic? */ /* panic? */
return -EIO; return -EIO;
@ -554,7 +555,7 @@ int hfsplus_cat_write_inode(struct inode *inode)
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
sizeof(struct hfsplus_cat_folder)); sizeof(struct hfsplus_cat_folder));
/* simple node checks? */ /* simple node checks? */
hfsplus_set_perms(inode, &folder->permissions); hfsplus_cat_set_perms(inode, &folder->permissions);
folder->access_date = hfsp_ut2mt(inode->i_atime); folder->access_date = hfsp_ut2mt(inode->i_atime);
folder->content_mod_date = hfsp_ut2mt(inode->i_mtime); folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime); folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
@ -576,11 +577,7 @@ int hfsplus_cat_write_inode(struct inode *inode)
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
sizeof(struct hfsplus_cat_file)); sizeof(struct hfsplus_cat_file));
hfsplus_inode_write_fork(inode, &file->data_fork); hfsplus_inode_write_fork(inode, &file->data_fork);
if (S_ISREG(inode->i_mode)) hfsplus_cat_set_perms(inode, &file->permissions);
HFSPLUS_I(inode).dev = inode->i_nlink;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
HFSPLUS_I(inode).dev = kdev_t_to_nr(inode->i_rdev);
hfsplus_set_perms(inode, &file->permissions);
if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
else else

View File

@ -17,83 +17,98 @@
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "hfsplus_fs.h" #include "hfsplus_fs.h"
long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
{ {
struct inode *inode = filp->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode;
unsigned int flags; struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
unsigned int flags = 0;
lock_kernel(); if (inode->i_flags & S_IMMUTABLE)
switch (cmd) { flags |= FS_IMMUTABLE_FL;
case HFSPLUS_IOC_EXT2_GETFLAGS: if (inode->i_flags |= S_APPEND)
flags = 0; flags |= FS_APPEND_FL;
if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE) if (hip->userflags & HFSPLUS_FLG_NODUMP)
flags |= FS_IMMUTABLE_FL; /* EXT2_IMMUTABLE_FL */ flags |= FS_NODUMP_FL;
if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND)
flags |= FS_APPEND_FL; /* EXT2_APPEND_FL */ return put_user(flags, user_flags);
if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP)
flags |= FS_NODUMP_FL; /* EXT2_NODUMP_FL */
return put_user(flags, (int __user *)arg);
case HFSPLUS_IOC_EXT2_SETFLAGS: {
int err = 0;
err = mnt_want_write(filp->f_path.mnt);
if (err) {
unlock_kernel();
return err;
} }
static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
{
struct inode *inode = file->f_path.dentry->d_inode;
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
unsigned int flags;
int err = 0;
err = mnt_want_write(file->f_path.mnt);
if (err)
goto out;
if (!is_owner_or_cap(inode)) { if (!is_owner_or_cap(inode)) {
err = -EACCES; err = -EACCES;
goto setflags_out; goto out_drop_write;
} }
if (get_user(flags, (int __user *)arg)) {
if (get_user(flags, user_flags)) {
err = -EFAULT; err = -EFAULT;
goto setflags_out; goto out_drop_write;
} }
if (flags & (FS_IMMUTABLE_FL|FS_APPEND_FL) ||
HFSPLUS_I(inode).rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) { mutex_lock(&inode->i_mutex);
if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) ||
inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
if (!capable(CAP_LINUX_IMMUTABLE)) { if (!capable(CAP_LINUX_IMMUTABLE)) {
err = -EPERM; err = -EPERM;
goto setflags_out; goto out_unlock_inode;
} }
} }
/* don't silently ignore unsupported ext2 flags */ /* don't silently ignore unsupported ext2 flags */
if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) { if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto setflags_out; goto out_unlock_inode;
} }
if (flags & FS_IMMUTABLE_FL) { /* EXT2_IMMUTABLE_FL */
if (flags & FS_IMMUTABLE_FL)
inode->i_flags |= S_IMMUTABLE; inode->i_flags |= S_IMMUTABLE;
HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_IMMUTABLE;
} else {
inode->i_flags &= ~S_IMMUTABLE;
HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
}
if (flags & FS_APPEND_FL) { /* EXT2_APPEND_FL */
inode->i_flags |= S_APPEND;
HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_APPEND;
} else {
inode->i_flags &= ~S_APPEND;
HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_APPEND;
}
if (flags & FS_NODUMP_FL) /* EXT2_NODUMP_FL */
HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP;
else else
HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP; inode->i_flags &= ~S_IMMUTABLE;
if (flags & FS_APPEND_FL)
inode->i_flags |= S_APPEND;
else
inode->i_flags &= ~S_APPEND;
if (flags & FS_NODUMP_FL)
hip->userflags |= HFSPLUS_FLG_NODUMP;
else
hip->userflags &= ~HFSPLUS_FLG_NODUMP;
inode->i_ctime = CURRENT_TIME_SEC; inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode); mark_inode_dirty(inode);
setflags_out:
mnt_drop_write(filp->f_path.mnt); out_unlock_inode:
unlock_kernel(); mutex_lock(&inode->i_mutex);
out_drop_write:
mnt_drop_write(file->f_path.mnt);
out:
return err; return err;
} }
long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
switch (cmd) {
case HFSPLUS_IOC_EXT2_GETFLAGS:
return hfsplus_ioctl_getflags(file, argp);
case HFSPLUS_IOC_EXT2_SETFLAGS:
return hfsplus_ioctl_setflags(file, argp);
default: default:
unlock_kernel();
return -ENOTTY; return -ENOTTY;
} }
} }
@ -110,7 +125,7 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
return -EOPNOTSUPP; return -EOPNOTSUPP;
res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
if (res) if (res)
return res; return res;
res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
@ -153,7 +168,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (size) { if (size) {
res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
if (res) if (res)
return res; return res;
res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
@ -177,7 +192,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
} else } else
res = size ? -ERANGE : 4; res = size ? -ERANGE : 4;
} else } else
res = -ENODATA; res = -EOPNOTSUPP;
out: out:
if (size) if (size)
hfs_find_exit(&fd); hfs_find_exit(&fd);

View File

@ -143,13 +143,13 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
kfree(p); kfree(p);
break; break;
case opt_decompose: case opt_decompose:
sbi->flags &= ~HFSPLUS_SB_NODECOMPOSE; clear_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
break; break;
case opt_nodecompose: case opt_nodecompose:
sbi->flags |= HFSPLUS_SB_NODECOMPOSE; set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
break; break;
case opt_force: case opt_force:
sbi->flags |= HFSPLUS_SB_FORCE; set_bit(HFSPLUS_SB_FORCE, &sbi->flags);
break; break;
default: default:
return 0; return 0;
@ -171,7 +171,7 @@ done:
int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt) int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
{ {
struct hfsplus_sb_info *sbi = &HFSPLUS_SB(mnt->mnt_sb); struct hfsplus_sb_info *sbi = HFSPLUS_SB(mnt->mnt_sb);
if (sbi->creator != HFSPLUS_DEF_CR_TYPE) if (sbi->creator != HFSPLUS_DEF_CR_TYPE)
seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator); seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator);
@ -184,7 +184,7 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
seq_printf(seq, ",session=%u", sbi->session); seq_printf(seq, ",session=%u", sbi->session);
if (sbi->nls) if (sbi->nls)
seq_printf(seq, ",nls=%s", sbi->nls->charset); seq_printf(seq, ",nls=%s", sbi->nls->charset);
if (sbi->flags & HFSPLUS_SB_NODECOMPOSE) if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags))
seq_printf(seq, ",nodecompose"); seq_printf(seq, ",nodecompose");
return 0; return 0;
} }

View File

@ -74,6 +74,7 @@ struct old_pmap {
int hfs_part_find(struct super_block *sb, int hfs_part_find(struct super_block *sb,
sector_t *part_start, sector_t *part_size) sector_t *part_start, sector_t *part_size)
{ {
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
struct buffer_head *bh; struct buffer_head *bh;
__be16 *data; __be16 *data;
int i, size, res; int i, size, res;
@ -95,7 +96,7 @@ int hfs_part_find(struct super_block *sb,
for (i = 0; i < size; p++, i++) { for (i = 0; i < size; p++, i++) {
if (p->pdStart && p->pdSize && if (p->pdStart && p->pdSize &&
p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ && p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
(HFSPLUS_SB(sb).part < 0 || HFSPLUS_SB(sb).part == i)) { (sbi->part < 0 || sbi->part == i)) {
*part_start += be32_to_cpu(p->pdStart); *part_start += be32_to_cpu(p->pdStart);
*part_size = be32_to_cpu(p->pdSize); *part_size = be32_to_cpu(p->pdSize);
res = 0; res = 0;
@ -111,7 +112,7 @@ int hfs_part_find(struct super_block *sb,
size = be32_to_cpu(pm->pmMapBlkCnt); size = be32_to_cpu(pm->pmMapBlkCnt);
for (i = 0; i < size;) { for (i = 0; i < size;) {
if (!memcmp(pm->pmPartType,"Apple_HFS", 9) && if (!memcmp(pm->pmPartType,"Apple_HFS", 9) &&
(HFSPLUS_SB(sb).part < 0 || HFSPLUS_SB(sb).part == i)) { (sbi->part < 0 || sbi->part == i)) {
*part_start += be32_to_cpu(pm->pmPyPartStart); *part_start += be32_to_cpu(pm->pmPyPartStart);
*part_size = be32_to_cpu(pm->pmPartBlkCnt); *part_size = be32_to_cpu(pm->pmPartBlkCnt);
res = 0; res = 0;

View File

@ -12,7 +12,6 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/nls.h> #include <linux/nls.h>
@ -21,40 +20,11 @@ static void hfsplus_destroy_inode(struct inode *inode);
#include "hfsplus_fs.h" #include "hfsplus_fs.h"
struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino) static int hfsplus_system_read_inode(struct inode *inode)
{ {
struct hfs_find_data fd; struct hfsplus_vh *vhdr = HFSPLUS_SB(inode->i_sb)->s_vhdr;
struct hfsplus_vh *vhdr;
struct inode *inode;
long err = -EIO;
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW))
return inode;
INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
mutex_init(&HFSPLUS_I(inode).extents_lock);
HFSPLUS_I(inode).flags = 0;
HFSPLUS_I(inode).rsrc_inode = NULL;
atomic_set(&HFSPLUS_I(inode).opencnt, 0);
if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) {
read_inode:
hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd);
err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
if (!err)
err = hfsplus_cat_read_inode(inode, &fd);
hfs_find_exit(&fd);
if (err)
goto bad_inode;
goto done;
}
vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr;
switch (inode->i_ino) { switch (inode->i_ino) {
case HFSPLUS_ROOT_CNID:
goto read_inode;
case HFSPLUS_EXT_CNID: case HFSPLUS_EXT_CNID:
hfsplus_inode_read_fork(inode, &vhdr->ext_file); hfsplus_inode_read_fork(inode, &vhdr->ext_file);
inode->i_mapping->a_ops = &hfsplus_btree_aops; inode->i_mapping->a_ops = &hfsplus_btree_aops;
@ -75,74 +45,101 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
inode->i_mapping->a_ops = &hfsplus_btree_aops; inode->i_mapping->a_ops = &hfsplus_btree_aops;
break; break;
default: default:
goto bad_inode; return -EIO;
} }
done: return 0;
unlock_new_inode(inode); }
struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
{
struct hfs_find_data fd;
struct inode *inode;
int err;
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW))
return inode; return inode;
bad_inode: INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
mutex_init(&HFSPLUS_I(inode)->extents_lock);
HFSPLUS_I(inode)->flags = 0;
HFSPLUS_I(inode)->rsrc_inode = NULL;
atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
inode->i_ino == HFSPLUS_ROOT_CNID) {
hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
if (!err)
err = hfsplus_cat_read_inode(inode, &fd);
hfs_find_exit(&fd);
} else {
err = hfsplus_system_read_inode(inode);
}
if (err) {
iget_failed(inode); iget_failed(inode);
return ERR_PTR(err); return ERR_PTR(err);
} }
unlock_new_inode(inode);
return inode;
}
static int hfsplus_system_write_inode(struct inode *inode)
{
struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
struct hfsplus_vh *vhdr = sbi->s_vhdr;
struct hfsplus_fork_raw *fork;
struct hfs_btree *tree = NULL;
switch (inode->i_ino) {
case HFSPLUS_EXT_CNID:
fork = &vhdr->ext_file;
tree = sbi->ext_tree;
break;
case HFSPLUS_CAT_CNID:
fork = &vhdr->cat_file;
tree = sbi->cat_tree;
break;
case HFSPLUS_ALLOC_CNID:
fork = &vhdr->alloc_file;
break;
case HFSPLUS_START_CNID:
fork = &vhdr->start_file;
break;
case HFSPLUS_ATTR_CNID:
fork = &vhdr->attr_file;
tree = sbi->attr_tree;
default:
return -EIO;
}
if (fork->total_size != cpu_to_be64(inode->i_size)) {
set_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags);
inode->i_sb->s_dirt = 1;
}
hfsplus_inode_write_fork(inode, fork);
if (tree)
hfs_btree_write(tree);
return 0;
}
static int hfsplus_write_inode(struct inode *inode, static int hfsplus_write_inode(struct inode *inode,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
struct hfsplus_vh *vhdr;
int ret = 0;
dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino); dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
hfsplus_ext_write_extent(inode); hfsplus_ext_write_extent(inode);
if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) {
if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
inode->i_ino == HFSPLUS_ROOT_CNID)
return hfsplus_cat_write_inode(inode); return hfsplus_cat_write_inode(inode);
} else
vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr; return hfsplus_system_write_inode(inode);
switch (inode->i_ino) {
case HFSPLUS_ROOT_CNID:
ret = hfsplus_cat_write_inode(inode);
break;
case HFSPLUS_EXT_CNID:
if (vhdr->ext_file.total_size != cpu_to_be64(inode->i_size)) {
HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
inode->i_sb->s_dirt = 1;
}
hfsplus_inode_write_fork(inode, &vhdr->ext_file);
hfs_btree_write(HFSPLUS_SB(inode->i_sb).ext_tree);
break;
case HFSPLUS_CAT_CNID:
if (vhdr->cat_file.total_size != cpu_to_be64(inode->i_size)) {
HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
inode->i_sb->s_dirt = 1;
}
hfsplus_inode_write_fork(inode, &vhdr->cat_file);
hfs_btree_write(HFSPLUS_SB(inode->i_sb).cat_tree);
break;
case HFSPLUS_ALLOC_CNID:
if (vhdr->alloc_file.total_size != cpu_to_be64(inode->i_size)) {
HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
inode->i_sb->s_dirt = 1;
}
hfsplus_inode_write_fork(inode, &vhdr->alloc_file);
break;
case HFSPLUS_START_CNID:
if (vhdr->start_file.total_size != cpu_to_be64(inode->i_size)) {
HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
inode->i_sb->s_dirt = 1;
}
hfsplus_inode_write_fork(inode, &vhdr->start_file);
break;
case HFSPLUS_ATTR_CNID:
if (vhdr->attr_file.total_size != cpu_to_be64(inode->i_size)) {
HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
inode->i_sb->s_dirt = 1;
}
hfsplus_inode_write_fork(inode, &vhdr->attr_file);
hfs_btree_write(HFSPLUS_SB(inode->i_sb).attr_tree);
break;
}
return ret;
} }
static void hfsplus_evict_inode(struct inode *inode) static void hfsplus_evict_inode(struct inode *inode)
@ -151,51 +148,53 @@ static void hfsplus_evict_inode(struct inode *inode)
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode); end_writeback(inode);
if (HFSPLUS_IS_RSRC(inode)) { if (HFSPLUS_IS_RSRC(inode)) {
HFSPLUS_I(HFSPLUS_I(inode).rsrc_inode).rsrc_inode = NULL; HFSPLUS_I(HFSPLUS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
iput(HFSPLUS_I(inode).rsrc_inode); iput(HFSPLUS_I(inode)->rsrc_inode);
} }
} }
int hfsplus_sync_fs(struct super_block *sb, int wait) int hfsplus_sync_fs(struct super_block *sb, int wait)
{ {
struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
struct hfsplus_vh *vhdr = sbi->s_vhdr;
dprint(DBG_SUPER, "hfsplus_write_super\n"); dprint(DBG_SUPER, "hfsplus_write_super\n");
lock_super(sb); mutex_lock(&sbi->vh_mutex);
mutex_lock(&sbi->alloc_mutex);
sb->s_dirt = 0; sb->s_dirt = 0;
vhdr->free_blocks = cpu_to_be32(HFSPLUS_SB(sb).free_blocks); vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
vhdr->next_alloc = cpu_to_be32(HFSPLUS_SB(sb).next_alloc); vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
vhdr->next_cnid = cpu_to_be32(HFSPLUS_SB(sb).next_cnid); vhdr->folder_count = cpu_to_be32(sbi->folder_count);
vhdr->folder_count = cpu_to_be32(HFSPLUS_SB(sb).folder_count); vhdr->file_count = cpu_to_be32(sbi->file_count);
vhdr->file_count = cpu_to_be32(HFSPLUS_SB(sb).file_count);
mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh); mark_buffer_dirty(sbi->s_vhbh);
if (HFSPLUS_SB(sb).flags & HFSPLUS_SB_WRITEBACKUP) { if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
if (HFSPLUS_SB(sb).sect_count) { if (sbi->sect_count) {
struct buffer_head *bh; struct buffer_head *bh;
u32 block, offset; u32 block, offset;
block = HFSPLUS_SB(sb).blockoffset; block = sbi->blockoffset;
block += (HFSPLUS_SB(sb).sect_count - 2) >> (sb->s_blocksize_bits - 9); block += (sbi->sect_count - 2) >> (sb->s_blocksize_bits - 9);
offset = ((HFSPLUS_SB(sb).sect_count - 2) << 9) & (sb->s_blocksize - 1); offset = ((sbi->sect_count - 2) << 9) & (sb->s_blocksize - 1);
printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n", HFSPLUS_SB(sb).blockoffset, printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n",
HFSPLUS_SB(sb).sect_count, block, offset); sbi->blockoffset, sbi->sect_count,
block, offset);
bh = sb_bread(sb, block); bh = sb_bread(sb, block);
if (bh) { if (bh) {
vhdr = (struct hfsplus_vh *)(bh->b_data + offset); vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) { if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) {
memcpy(vhdr, HFSPLUS_SB(sb).s_vhdr, sizeof(*vhdr)); memcpy(vhdr, sbi->s_vhdr, sizeof(*vhdr));
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
brelse(bh); brelse(bh);
} else } else
printk(KERN_WARNING "hfs: backup not found!\n"); printk(KERN_WARNING "hfs: backup not found!\n");
} }
} }
HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP;
} }
unlock_super(sb); mutex_unlock(&sbi->alloc_mutex);
mutex_unlock(&sbi->vh_mutex);
return 0; return 0;
} }
@ -209,48 +208,48 @@ static void hfsplus_write_super(struct super_block *sb)
static void hfsplus_put_super(struct super_block *sb) static void hfsplus_put_super(struct super_block *sb)
{ {
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
dprint(DBG_SUPER, "hfsplus_put_super\n"); dprint(DBG_SUPER, "hfsplus_put_super\n");
if (!sb->s_fs_info) if (!sb->s_fs_info)
return; return;
lock_kernel();
if (sb->s_dirt) if (sb->s_dirt)
hfsplus_write_super(sb); hfsplus_write_super(sb);
if (!(sb->s_flags & MS_RDONLY) && HFSPLUS_SB(sb).s_vhdr) { if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; struct hfsplus_vh *vhdr = sbi->s_vhdr;
vhdr->modify_date = hfsp_now2mt(); vhdr->modify_date = hfsp_now2mt();
vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT); vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT);
vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT); vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT);
mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh); mark_buffer_dirty(sbi->s_vhbh);
sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); sync_dirty_buffer(sbi->s_vhbh);
} }
hfs_btree_close(HFSPLUS_SB(sb).cat_tree); hfs_btree_close(sbi->cat_tree);
hfs_btree_close(HFSPLUS_SB(sb).ext_tree); hfs_btree_close(sbi->ext_tree);
iput(HFSPLUS_SB(sb).alloc_file); iput(sbi->alloc_file);
iput(HFSPLUS_SB(sb).hidden_dir); iput(sbi->hidden_dir);
brelse(HFSPLUS_SB(sb).s_vhbh); brelse(sbi->s_vhbh);
unload_nls(HFSPLUS_SB(sb).nls); unload_nls(sbi->nls);
kfree(sb->s_fs_info); kfree(sb->s_fs_info);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
unlock_kernel();
} }
static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf) static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
{ {
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
u64 id = huge_encode_dev(sb->s_bdev->bd_dev); u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
buf->f_type = HFSPLUS_SUPER_MAGIC; buf->f_type = HFSPLUS_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize; buf->f_bsize = sb->s_blocksize;
buf->f_blocks = HFSPLUS_SB(sb).total_blocks << HFSPLUS_SB(sb).fs_shift; buf->f_blocks = sbi->total_blocks << sbi->fs_shift;
buf->f_bfree = HFSPLUS_SB(sb).free_blocks << HFSPLUS_SB(sb).fs_shift; buf->f_bfree = sbi->free_blocks << sbi->fs_shift;
buf->f_bavail = buf->f_bfree; buf->f_bavail = buf->f_bfree;
buf->f_files = 0xFFFFFFFF; buf->f_files = 0xFFFFFFFF;
buf->f_ffree = 0xFFFFFFFF - HFSPLUS_SB(sb).next_cnid; buf->f_ffree = 0xFFFFFFFF - sbi->next_cnid;
buf->f_fsid.val[0] = (u32)id; buf->f_fsid.val[0] = (u32)id;
buf->f_fsid.val[1] = (u32)(id >> 32); buf->f_fsid.val[1] = (u32)(id >> 32);
buf->f_namelen = HFSPLUS_MAX_STRLEN; buf->f_namelen = HFSPLUS_MAX_STRLEN;
@ -263,11 +262,11 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
return 0; return 0;
if (!(*flags & MS_RDONLY)) { if (!(*flags & MS_RDONLY)) {
struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr;
struct hfsplus_sb_info sbi; struct hfsplus_sb_info sbi;
memset(&sbi, 0, sizeof(struct hfsplus_sb_info)); memset(&sbi, 0, sizeof(struct hfsplus_sb_info));
sbi.nls = HFSPLUS_SB(sb).nls; sbi.nls = HFSPLUS_SB(sb)->nls;
if (!hfsplus_parse_options(data, &sbi)) if (!hfsplus_parse_options(data, &sbi))
return -EINVAL; return -EINVAL;
@ -276,7 +275,7 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
"running fsck.hfsplus is recommended. leaving read-only.\n"); "running fsck.hfsplus is recommended. leaving read-only.\n");
sb->s_flags |= MS_RDONLY; sb->s_flags |= MS_RDONLY;
*flags |= MS_RDONLY; *flags |= MS_RDONLY;
} else if (sbi.flags & HFSPLUS_SB_FORCE) { } else if (test_bit(HFSPLUS_SB_FORCE, &sbi.flags)) {
/* nothing */ /* nothing */
} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n"); printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n");
@ -320,7 +319,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
return -ENOMEM; return -ENOMEM;
sb->s_fs_info = sbi; sb->s_fs_info = sbi;
INIT_HLIST_HEAD(&sbi->rsrc_inodes); mutex_init(&sbi->alloc_mutex);
mutex_init(&sbi->vh_mutex);
hfsplus_fill_defaults(sbi); hfsplus_fill_defaults(sbi);
if (!hfsplus_parse_options(data, sbi)) { if (!hfsplus_parse_options(data, sbi)) {
printk(KERN_ERR "hfs: unable to parse mount options\n"); printk(KERN_ERR "hfs: unable to parse mount options\n");
@ -344,7 +344,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
err = -EINVAL; err = -EINVAL;
goto cleanup; goto cleanup;
} }
vhdr = HFSPLUS_SB(sb).s_vhdr; vhdr = sbi->s_vhdr;
/* Copy parts of the volume header into the superblock */ /* Copy parts of the volume header into the superblock */
sb->s_magic = HFSPLUS_VOLHEAD_SIG; sb->s_magic = HFSPLUS_VOLHEAD_SIG;
@ -353,18 +353,19 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
printk(KERN_ERR "hfs: wrong filesystem version\n"); printk(KERN_ERR "hfs: wrong filesystem version\n");
goto cleanup; goto cleanup;
} }
HFSPLUS_SB(sb).total_blocks = be32_to_cpu(vhdr->total_blocks); sbi->total_blocks = be32_to_cpu(vhdr->total_blocks);
HFSPLUS_SB(sb).free_blocks = be32_to_cpu(vhdr->free_blocks); sbi->free_blocks = be32_to_cpu(vhdr->free_blocks);
HFSPLUS_SB(sb).next_alloc = be32_to_cpu(vhdr->next_alloc); sbi->next_cnid = be32_to_cpu(vhdr->next_cnid);
HFSPLUS_SB(sb).next_cnid = be32_to_cpu(vhdr->next_cnid); sbi->file_count = be32_to_cpu(vhdr->file_count);
HFSPLUS_SB(sb).file_count = be32_to_cpu(vhdr->file_count); sbi->folder_count = be32_to_cpu(vhdr->folder_count);
HFSPLUS_SB(sb).folder_count = be32_to_cpu(vhdr->folder_count); sbi->data_clump_blocks =
HFSPLUS_SB(sb).data_clump_blocks = be32_to_cpu(vhdr->data_clump_sz) >> HFSPLUS_SB(sb).alloc_blksz_shift; be32_to_cpu(vhdr->data_clump_sz) >> sbi->alloc_blksz_shift;
if (!HFSPLUS_SB(sb).data_clump_blocks) if (!sbi->data_clump_blocks)
HFSPLUS_SB(sb).data_clump_blocks = 1; sbi->data_clump_blocks = 1;
HFSPLUS_SB(sb).rsrc_clump_blocks = be32_to_cpu(vhdr->rsrc_clump_sz) >> HFSPLUS_SB(sb).alloc_blksz_shift; sbi->rsrc_clump_blocks =
if (!HFSPLUS_SB(sb).rsrc_clump_blocks) be32_to_cpu(vhdr->rsrc_clump_sz) >> sbi->alloc_blksz_shift;
HFSPLUS_SB(sb).rsrc_clump_blocks = 1; if (!sbi->rsrc_clump_blocks)
sbi->rsrc_clump_blocks = 1;
/* Set up operations so we can load metadata */ /* Set up operations so we can load metadata */
sb->s_op = &hfsplus_sops; sb->s_op = &hfsplus_sops;
@ -374,7 +375,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, " printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, "
"running fsck.hfsplus is recommended. mounting read-only.\n"); "running fsck.hfsplus is recommended. mounting read-only.\n");
sb->s_flags |= MS_RDONLY; sb->s_flags |= MS_RDONLY;
} else if (sbi->flags & HFSPLUS_SB_FORCE) { } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
/* nothing */ /* nothing */
} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n"); printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n");
@ -384,16 +385,15 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
"use the force option at your own risk, mounting read-only.\n"); "use the force option at your own risk, mounting read-only.\n");
sb->s_flags |= MS_RDONLY; sb->s_flags |= MS_RDONLY;
} }
sbi->flags &= ~HFSPLUS_SB_FORCE;
/* Load metadata objects (B*Trees) */ /* Load metadata objects (B*Trees) */
HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
if (!HFSPLUS_SB(sb).ext_tree) { if (!sbi->ext_tree) {
printk(KERN_ERR "hfs: failed to load extents file\n"); printk(KERN_ERR "hfs: failed to load extents file\n");
goto cleanup; goto cleanup;
} }
HFSPLUS_SB(sb).cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID); sbi->cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID);
if (!HFSPLUS_SB(sb).cat_tree) { if (!sbi->cat_tree) {
printk(KERN_ERR "hfs: failed to load catalog file\n"); printk(KERN_ERR "hfs: failed to load catalog file\n");
goto cleanup; goto cleanup;
} }
@ -404,7 +404,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
err = PTR_ERR(inode); err = PTR_ERR(inode);
goto cleanup; goto cleanup;
} }
HFSPLUS_SB(sb).alloc_file = inode; sbi->alloc_file = inode;
/* Load the root directory */ /* Load the root directory */
root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID); root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
@ -423,7 +423,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
str.name = HFSP_HIDDENDIR_NAME; str.name = HFSP_HIDDENDIR_NAME;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); hfs_find_init(sbi->cat_tree, &fd);
hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
hfs_find_exit(&fd); hfs_find_exit(&fd);
@ -434,7 +434,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
err = PTR_ERR(inode); err = PTR_ERR(inode);
goto cleanup; goto cleanup;
} }
HFSPLUS_SB(sb).hidden_dir = inode; sbi->hidden_dir = inode;
} else } else
hfs_find_exit(&fd); hfs_find_exit(&fd);
@ -449,15 +449,19 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
be32_add_cpu(&vhdr->write_count, 1); be32_add_cpu(&vhdr->write_count, 1);
vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT); vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT); vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh); mark_buffer_dirty(sbi->s_vhbh);
sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); sync_dirty_buffer(sbi->s_vhbh);
if (!HFSPLUS_SB(sb).hidden_dir) { if (!sbi->hidden_dir) {
printk(KERN_DEBUG "hfs: create hidden dir...\n"); printk(KERN_DEBUG "hfs: create hidden dir...\n");
HFSPLUS_SB(sb).hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
hfsplus_create_cat(HFSPLUS_SB(sb).hidden_dir->i_ino, sb->s_root->d_inode, mutex_lock(&sbi->vh_mutex);
&str, HFSPLUS_SB(sb).hidden_dir); sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
mark_inode_dirty(HFSPLUS_SB(sb).hidden_dir); hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode,
&str, sbi->hidden_dir);
mutex_unlock(&sbi->vh_mutex);
mark_inode_dirty(sbi->hidden_dir);
} }
out: out:
unload_nls(sbi->nls); unload_nls(sbi->nls);
@ -486,7 +490,7 @@ static struct inode *hfsplus_alloc_inode(struct super_block *sb)
static void hfsplus_destroy_inode(struct inode *inode) static void hfsplus_destroy_inode(struct inode *inode)
{ {
kmem_cache_free(hfsplus_inode_cachep, &HFSPLUS_I(inode)); kmem_cache_free(hfsplus_inode_cachep, HFSPLUS_I(inode));
} }
#define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info) #define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info)

View File

@ -121,7 +121,7 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p) int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p)
{ {
const hfsplus_unichr *ip; const hfsplus_unichr *ip;
struct nls_table *nls = HFSPLUS_SB(sb).nls; struct nls_table *nls = HFSPLUS_SB(sb)->nls;
u8 *op; u8 *op;
u16 cc, c0, c1; u16 cc, c0, c1;
u16 *ce1, *ce2; u16 *ce1, *ce2;
@ -132,7 +132,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
ustrlen = be16_to_cpu(ustr->length); ustrlen = be16_to_cpu(ustr->length);
len = *len_p; len = *len_p;
ce1 = NULL; ce1 = NULL;
compose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); compose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
while (ustrlen > 0) { while (ustrlen > 0) {
c0 = be16_to_cpu(*ip++); c0 = be16_to_cpu(*ip++);
@ -246,7 +246,7 @@ out:
static inline int asc2unichar(struct super_block *sb, const char *astr, int len, static inline int asc2unichar(struct super_block *sb, const char *astr, int len,
wchar_t *uc) wchar_t *uc)
{ {
int size = HFSPLUS_SB(sb).nls->char2uni(astr, len, uc); int size = HFSPLUS_SB(sb)->nls->char2uni(astr, len, uc);
if (size <= 0) { if (size <= 0) {
*uc = '?'; *uc = '?';
size = 1; size = 1;
@ -293,7 +293,7 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
u16 *dstr, outlen = 0; u16 *dstr, outlen = 0;
wchar_t c; wchar_t c;
decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { while (outlen < HFSPLUS_MAX_STRLEN && len > 0) {
size = asc2unichar(sb, astr, len, &c); size = asc2unichar(sb, astr, len, &c);
@ -330,8 +330,8 @@ int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str)
wchar_t c; wchar_t c;
u16 c2; u16 c2;
casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD); casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
hash = init_name_hash(); hash = init_name_hash();
astr = str->name; astr = str->name;
len = str->len; len = str->len;
@ -373,8 +373,8 @@ int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *
u16 c1, c2; u16 c1, c2;
wchar_t c; wchar_t c;
casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD); casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
astr1 = s1->name; astr1 = s1->name;
len1 = s1->len; len1 = s1->len;
astr2 = s2->name; astr2 = s2->name;

View File

@ -65,8 +65,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
*start = 0; *start = 0;
*size = sb->s_bdev->bd_inode->i_size >> 9; *size = sb->s_bdev->bd_inode->i_size >> 9;
if (HFSPLUS_SB(sb).session >= 0) { if (HFSPLUS_SB(sb)->session >= 0) {
te.cdte_track = HFSPLUS_SB(sb).session; te.cdte_track = HFSPLUS_SB(sb)->session;
te.cdte_format = CDROM_LBA; te.cdte_format = CDROM_LBA;
res = ioctl_by_bdev(sb->s_bdev, CDROMREADTOCENTRY, (unsigned long)&te); res = ioctl_by_bdev(sb->s_bdev, CDROMREADTOCENTRY, (unsigned long)&te);
if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) { if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) {
@ -87,6 +87,7 @@ static int hfsplus_get_last_session(struct super_block *sb,
/* Takes in super block, returns true if good data read */ /* Takes in super block, returns true if good data read */
int hfsplus_read_wrapper(struct super_block *sb) int hfsplus_read_wrapper(struct super_block *sb)
{ {
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
struct buffer_head *bh; struct buffer_head *bh;
struct hfsplus_vh *vhdr; struct hfsplus_vh *vhdr;
struct hfsplus_wd wd; struct hfsplus_wd wd;
@ -122,7 +123,7 @@ int hfsplus_read_wrapper(struct super_block *sb)
if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
break; break;
if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) { if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) {
HFSPLUS_SB(sb).flags |= HFSPLUS_SB_HFSX; set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
break; break;
} }
brelse(bh); brelse(bh);
@ -143,11 +144,11 @@ int hfsplus_read_wrapper(struct super_block *sb)
if (blocksize < HFSPLUS_SECTOR_SIZE || if (blocksize < HFSPLUS_SECTOR_SIZE ||
((blocksize - 1) & blocksize)) ((blocksize - 1) & blocksize))
return -EINVAL; return -EINVAL;
HFSPLUS_SB(sb).alloc_blksz = blocksize; sbi->alloc_blksz = blocksize;
HFSPLUS_SB(sb).alloc_blksz_shift = 0; sbi->alloc_blksz_shift = 0;
while ((blocksize >>= 1) != 0) while ((blocksize >>= 1) != 0)
HFSPLUS_SB(sb).alloc_blksz_shift++; sbi->alloc_blksz_shift++;
blocksize = min(HFSPLUS_SB(sb).alloc_blksz, (u32)PAGE_SIZE); blocksize = min(sbi->alloc_blksz, (u32)PAGE_SIZE);
/* align block size to block offset */ /* align block size to block offset */
while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1)) while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1))
@ -158,23 +159,26 @@ int hfsplus_read_wrapper(struct super_block *sb)
return -EINVAL; return -EINVAL;
} }
HFSPLUS_SB(sb).blockoffset = part_start >> sbi->blockoffset =
(sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT); part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT);
HFSPLUS_SB(sb).sect_count = part_size; sbi->sect_count = part_size;
HFSPLUS_SB(sb).fs_shift = HFSPLUS_SB(sb).alloc_blksz_shift - sbi->fs_shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
sb->s_blocksize_bits;
bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr); bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
if (!bh) if (!bh)
return -EIO; return -EIO;
/* should still be the same... */ /* should still be the same... */
if (vhdr->signature != (HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX ? if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
cpu_to_be16(HFSPLUS_VOLHEAD_SIGX) : if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX))
cpu_to_be16(HFSPLUS_VOLHEAD_SIG)))
goto error; goto error;
HFSPLUS_SB(sb).s_vhbh = bh; } else {
HFSPLUS_SB(sb).s_vhdr = vhdr; if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
goto error;
}
sbi->s_vhbh = bh;
sbi->s_vhdr = vhdr;
return 0; return 0;
error: error: