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: hfsplus: %L-to-%ll, macro correction, and remove unneeded braces hfsplus: spaces/indentation clean-up hfsplus: C99 comments clean-up hfsplus: over 80 character lines clean-up hfsplus: fix an artifact in ioctl flag checking hfsplus: flush disk caches in sync and fsync hfsplus: optimize fsync hfsplus: split up inode flags hfsplus: write up fsync for directories hfsplus: simplify fsync hfsplus: avoid useless work in hfsplus_sync_fs hfsplus: make sure sync writes out all metadata hfsplus: use raw bio access for partition tables hfsplus: use raw bio access for the volume headers hfsplus: always use hfsplus_sync_fs to write the volume header hfsplus: silence a few debug printks hfsplus: fix option parsing during remount Fix up conflicts due to VFS changes in fs/hfsplus/{hfsplus_fs.h,unicode.c}
This commit is contained in:
commit
0c21e3aaf6
@ -22,7 +22,8 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
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));
|
||||||
mutex_lock(&tree->tree_lock);
|
mutex_lock(&tree->tree_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -31,7 +32,8 @@ 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));
|
||||||
mutex_unlock(&fd->tree->tree_lock);
|
mutex_unlock(&fd->tree->tree_lock);
|
||||||
fd->tree = NULL;
|
fd->tree = NULL;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
|
|
||||||
#define PAGE_CACHE_BITS (PAGE_CACHE_SIZE * 8)
|
#define PAGE_CACHE_BITS (PAGE_CACHE_SIZE * 8)
|
||||||
|
|
||||||
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 hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
|
||||||
struct page *page;
|
struct page *page;
|
||||||
|
@ -42,7 +42,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
|
|||||||
u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
|
u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
|
||||||
{
|
{
|
||||||
__be16 data;
|
__be16 data;
|
||||||
// optimize later...
|
/* TODO: optimize later... */
|
||||||
hfs_bnode_read(node, &data, off, 2);
|
hfs_bnode_read(node, &data, off, 2);
|
||||||
return be16_to_cpu(data);
|
return be16_to_cpu(data);
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
|
|||||||
u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
|
u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
|
||||||
{
|
{
|
||||||
u8 data;
|
u8 data;
|
||||||
// optimize later...
|
/* TODO: optimize later... */
|
||||||
hfs_bnode_read(node, &data, off, 1);
|
hfs_bnode_read(node, &data, off, 1);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
|
|||||||
void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data)
|
void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data)
|
||||||
{
|
{
|
||||||
__be16 v = cpu_to_be16(data);
|
__be16 v = cpu_to_be16(data);
|
||||||
// optimize later...
|
/* TODO: optimize later... */
|
||||||
hfs_bnode_write(node, &v, off, 2);
|
hfs_bnode_write(node, &v, off, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +212,8 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
|
|||||||
dst_page--;
|
dst_page--;
|
||||||
}
|
}
|
||||||
src -= len;
|
src -= len;
|
||||||
memmove(kmap(*dst_page) + src, kmap(*src_page) + src, len);
|
memmove(kmap(*dst_page) + src,
|
||||||
|
kmap(*src_page) + src, len);
|
||||||
kunmap(*src_page);
|
kunmap(*src_page);
|
||||||
set_page_dirty(*dst_page);
|
set_page_dirty(*dst_page);
|
||||||
kunmap(*dst_page);
|
kunmap(*dst_page);
|
||||||
@ -250,14 +251,16 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
|
|||||||
|
|
||||||
if (src == dst) {
|
if (src == dst) {
|
||||||
l = min(len, (int)PAGE_CACHE_SIZE - src);
|
l = min(len, (int)PAGE_CACHE_SIZE - src);
|
||||||
memmove(kmap(*dst_page) + src, kmap(*src_page) + src, l);
|
memmove(kmap(*dst_page) + src,
|
||||||
|
kmap(*src_page) + src, l);
|
||||||
kunmap(*src_page);
|
kunmap(*src_page);
|
||||||
set_page_dirty(*dst_page);
|
set_page_dirty(*dst_page);
|
||||||
kunmap(*dst_page);
|
kunmap(*dst_page);
|
||||||
|
|
||||||
while ((len -= l) != 0) {
|
while ((len -= l) != 0) {
|
||||||
l = min(len, (int)PAGE_CACHE_SIZE);
|
l = min(len, (int)PAGE_CACHE_SIZE);
|
||||||
memmove(kmap(*++dst_page), kmap(*++src_page), l);
|
memmove(kmap(*++dst_page),
|
||||||
|
kmap(*++src_page), l);
|
||||||
kunmap(*src_page);
|
kunmap(*src_page);
|
||||||
set_page_dirty(*dst_page);
|
set_page_dirty(*dst_page);
|
||||||
kunmap(*dst_page);
|
kunmap(*dst_page);
|
||||||
@ -268,7 +271,8 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
|
|||||||
do {
|
do {
|
||||||
src_ptr = kmap(*src_page) + src;
|
src_ptr = kmap(*src_page) + src;
|
||||||
dst_ptr = kmap(*dst_page) + dst;
|
dst_ptr = kmap(*dst_page) + dst;
|
||||||
if (PAGE_CACHE_SIZE - src < PAGE_CACHE_SIZE - dst) {
|
if (PAGE_CACHE_SIZE - src <
|
||||||
|
PAGE_CACHE_SIZE - dst) {
|
||||||
l = PAGE_CACHE_SIZE - src;
|
l = PAGE_CACHE_SIZE - src;
|
||||||
src = 0;
|
src = 0;
|
||||||
dst += l;
|
dst += l;
|
||||||
@ -340,7 +344,8 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
|
|||||||
return;
|
return;
|
||||||
tmp->next = node->next;
|
tmp->next = node->next;
|
||||||
cnid = cpu_to_be32(tmp->next);
|
cnid = cpu_to_be32(tmp->next);
|
||||||
hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
|
hfs_bnode_write(tmp, &cnid,
|
||||||
|
offsetof(struct hfs_bnode_desc, next), 4);
|
||||||
hfs_bnode_put(tmp);
|
hfs_bnode_put(tmp);
|
||||||
} else if (node->type == HFS_NODE_LEAF)
|
} else if (node->type == HFS_NODE_LEAF)
|
||||||
tree->leaf_head = node->next;
|
tree->leaf_head = node->next;
|
||||||
@ -351,15 +356,15 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
|
|||||||
return;
|
return;
|
||||||
tmp->prev = node->prev;
|
tmp->prev = node->prev;
|
||||||
cnid = cpu_to_be32(tmp->prev);
|
cnid = cpu_to_be32(tmp->prev);
|
||||||
hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, prev), 4);
|
hfs_bnode_write(tmp, &cnid,
|
||||||
|
offsetof(struct hfs_bnode_desc, prev), 4);
|
||||||
hfs_bnode_put(tmp);
|
hfs_bnode_put(tmp);
|
||||||
} else if (node->type == HFS_NODE_LEAF)
|
} else if (node->type == HFS_NODE_LEAF)
|
||||||
tree->leaf_tail = node->prev;
|
tree->leaf_tail = node->prev;
|
||||||
|
|
||||||
// move down?
|
/* move down? */
|
||||||
if (!node->prev && !node->next) {
|
if (!node->prev && !node->next)
|
||||||
printk(KERN_DEBUG "hfs_btree_del_level\n");
|
dprint(DBG_BNODE_MOD, "hfs_btree_del_level\n");
|
||||||
}
|
|
||||||
if (!node->parent) {
|
if (!node->parent) {
|
||||||
tree->root = 0;
|
tree->root = 0;
|
||||||
tree->depth = 0;
|
tree->depth = 0;
|
||||||
@ -379,16 +384,16 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid)
|
|||||||
struct hfs_bnode *node;
|
struct hfs_bnode *node;
|
||||||
|
|
||||||
if (cnid >= tree->node_count) {
|
if (cnid >= tree->node_count) {
|
||||||
printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid);
|
printk(KERN_ERR "hfs: request for non-existent node "
|
||||||
|
"%d in B*Tree\n",
|
||||||
|
cnid);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (node = tree->node_hash[hfs_bnode_hash(cnid)];
|
for (node = tree->node_hash[hfs_bnode_hash(cnid)];
|
||||||
node; node = node->next_hash) {
|
node; node = node->next_hash)
|
||||||
if (node->this == cnid) {
|
if (node->this == cnid)
|
||||||
return node;
|
return node;
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,7 +407,9 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
|
|||||||
loff_t off;
|
loff_t off;
|
||||||
|
|
||||||
if (cnid >= tree->node_count) {
|
if (cnid >= tree->node_count) {
|
||||||
printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid);
|
printk(KERN_ERR "hfs: request for non-existent node "
|
||||||
|
"%d in B*Tree\n",
|
||||||
|
cnid);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,7 +436,8 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
|
|||||||
} else {
|
} else {
|
||||||
spin_unlock(&tree->hash_lock);
|
spin_unlock(&tree->hash_lock);
|
||||||
kfree(node);
|
kfree(node);
|
||||||
wait_event(node2->lock_wq, !test_bit(HFS_BNODE_NEW, &node2->flags));
|
wait_event(node2->lock_wq,
|
||||||
|
!test_bit(HFS_BNODE_NEW, &node2->flags));
|
||||||
return node2;
|
return node2;
|
||||||
}
|
}
|
||||||
spin_unlock(&tree->hash_lock);
|
spin_unlock(&tree->hash_lock);
|
||||||
@ -483,7 +491,8 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
|
|||||||
if (node) {
|
if (node) {
|
||||||
hfs_bnode_get(node);
|
hfs_bnode_get(node);
|
||||||
spin_unlock(&tree->hash_lock);
|
spin_unlock(&tree->hash_lock);
|
||||||
wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags));
|
wait_event(node->lock_wq,
|
||||||
|
!test_bit(HFS_BNODE_NEW, &node->flags));
|
||||||
if (test_bit(HFS_BNODE_ERROR, &node->flags))
|
if (test_bit(HFS_BNODE_ERROR, &node->flags))
|
||||||
goto node_error;
|
goto node_error;
|
||||||
return node;
|
return node;
|
||||||
@ -497,7 +506,8 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
|
|||||||
if (!test_bit(HFS_BNODE_NEW, &node->flags))
|
if (!test_bit(HFS_BNODE_NEW, &node->flags))
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) + node->page_offset);
|
desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) +
|
||||||
|
node->page_offset);
|
||||||
node->prev = be32_to_cpu(desc->prev);
|
node->prev = be32_to_cpu(desc->prev);
|
||||||
node->next = be32_to_cpu(desc->next);
|
node->next = be32_to_cpu(desc->next);
|
||||||
node->num_recs = be16_to_cpu(desc->num_recs);
|
node->num_recs = be16_to_cpu(desc->num_recs);
|
||||||
@ -556,11 +566,13 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
|
|||||||
|
|
||||||
void hfs_bnode_free(struct hfs_bnode *node)
|
void hfs_bnode_free(struct hfs_bnode *node)
|
||||||
{
|
{
|
||||||
//int i;
|
#if 0
|
||||||
|
int i;
|
||||||
|
|
||||||
//for (i = 0; i < node->tree->pages_per_bnode; i++)
|
for (i = 0; i < node->tree->pages_per_bnode; i++)
|
||||||
// if (node->page[i])
|
if (node->page[i])
|
||||||
// page_cache_release(node->page[i]);
|
page_cache_release(node->page[i]);
|
||||||
|
#endif
|
||||||
kfree(node);
|
kfree(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,7 +619,8 @@ void hfs_bnode_get(struct hfs_bnode *node)
|
|||||||
if (node) {
|
if (node) {
|
||||||
atomic_inc(&node->refcnt);
|
atomic_inc(&node->refcnt);
|
||||||
dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
|
dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
|
||||||
node->tree->cnid, node->this, atomic_read(&node->refcnt));
|
node->tree->cnid, node->this,
|
||||||
|
atomic_read(&node->refcnt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,7 +632,8 @@ void hfs_bnode_put(struct hfs_bnode *node)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
|
dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
|
||||||
node->tree->cnid, node->this, atomic_read(&node->refcnt));
|
node->tree->cnid, node->this,
|
||||||
|
atomic_read(&node->refcnt));
|
||||||
BUG_ON(!atomic_read(&node->refcnt));
|
BUG_ON(!atomic_read(&node->refcnt));
|
||||||
if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
|
if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
|
||||||
return;
|
return;
|
||||||
|
@ -39,7 +39,8 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
|
|||||||
!(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
|
!(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
|
||||||
retval = node->tree->max_key_len + 2;
|
retval = node->tree->max_key_len + 2;
|
||||||
} else {
|
} else {
|
||||||
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;
|
||||||
|
|
||||||
@ -84,7 +85,8 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
|
|||||||
end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
|
end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
|
||||||
end_off = hfs_bnode_read_u16(node, end_rec_off);
|
end_off = hfs_bnode_read_u16(node, end_rec_off);
|
||||||
end_rec_off -= 2;
|
end_rec_off -= 2;
|
||||||
dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", rec, size, end_off, end_rec_off);
|
dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
|
||||||
|
rec, size, end_off, end_rec_off);
|
||||||
if (size > end_rec_off - end_off) {
|
if (size > end_rec_off - end_off) {
|
||||||
if (new_node)
|
if (new_node)
|
||||||
panic("not enough room!\n");
|
panic("not enough room!\n");
|
||||||
@ -99,7 +101,9 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
|
|||||||
}
|
}
|
||||||
node->num_recs++;
|
node->num_recs++;
|
||||||
/* write new last offset */
|
/* write new last offset */
|
||||||
hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
|
hfs_bnode_write_u16(node,
|
||||||
|
offsetof(struct hfs_bnode_desc, num_recs),
|
||||||
|
node->num_recs);
|
||||||
hfs_bnode_write_u16(node, end_rec_off, end_off + size);
|
hfs_bnode_write_u16(node, end_rec_off, end_off + size);
|
||||||
data_off = end_off;
|
data_off = end_off;
|
||||||
data_rec_off = end_rec_off + 2;
|
data_rec_off = end_rec_off + 2;
|
||||||
@ -151,7 +155,8 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
|
|||||||
if (tree->attributes & HFS_TREE_VARIDXKEYS)
|
if (tree->attributes & HFS_TREE_VARIDXKEYS)
|
||||||
key_len = be16_to_cpu(fd->search_key->key_len) + 2;
|
key_len = be16_to_cpu(fd->search_key->key_len) + 2;
|
||||||
else {
|
else {
|
||||||
fd->search_key->key_len = cpu_to_be16(tree->max_key_len);
|
fd->search_key->key_len =
|
||||||
|
cpu_to_be16(tree->max_key_len);
|
||||||
key_len = tree->max_key_len + 2;
|
key_len = tree->max_key_len + 2;
|
||||||
}
|
}
|
||||||
goto again;
|
goto again;
|
||||||
@ -180,7 +185,8 @@ int hfs_brec_remove(struct hfs_find_data *fd)
|
|||||||
mark_inode_dirty(tree->inode);
|
mark_inode_dirty(tree->inode);
|
||||||
}
|
}
|
||||||
hfs_bnode_dump(node);
|
hfs_bnode_dump(node);
|
||||||
dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n", fd->record, fd->keylength + fd->entrylength);
|
dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n",
|
||||||
|
fd->record, fd->keylength + fd->entrylength);
|
||||||
if (!--node->num_recs) {
|
if (!--node->num_recs) {
|
||||||
hfs_bnode_unlink(node);
|
hfs_bnode_unlink(node);
|
||||||
if (!node->parent)
|
if (!node->parent)
|
||||||
@ -194,7 +200,9 @@ int hfs_brec_remove(struct hfs_find_data *fd)
|
|||||||
__hfs_brec_find(node, fd);
|
__hfs_brec_find(node, fd);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
|
hfs_bnode_write_u16(node,
|
||||||
|
offsetof(struct hfs_bnode_desc, num_recs),
|
||||||
|
node->num_recs);
|
||||||
|
|
||||||
if (rec_off == end_off)
|
if (rec_off == end_off)
|
||||||
goto skip;
|
goto skip;
|
||||||
@ -364,7 +372,8 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd)
|
|||||||
newkeylen = hfs_bnode_read_u16(node, 14) + 2;
|
newkeylen = hfs_bnode_read_u16(node, 14) + 2;
|
||||||
else
|
else
|
||||||
fd->keylength = newkeylen = tree->max_key_len + 2;
|
fd->keylength = newkeylen = tree->max_key_len + 2;
|
||||||
dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n", rec, fd->keylength, newkeylen);
|
dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n",
|
||||||
|
rec, fd->keylength, newkeylen);
|
||||||
|
|
||||||
rec_off = tree->node_size - (rec + 2) * 2;
|
rec_off = tree->node_size - (rec + 2) * 2;
|
||||||
end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
|
end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
|
||||||
@ -375,7 +384,7 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd)
|
|||||||
end_off = hfs_bnode_read_u16(parent, end_rec_off);
|
end_off = hfs_bnode_read_u16(parent, end_rec_off);
|
||||||
if (end_rec_off - end_off < diff) {
|
if (end_rec_off - end_off < diff) {
|
||||||
|
|
||||||
printk(KERN_DEBUG "hfs: splitting index node...\n");
|
dprint(DBG_BNODE_MOD, "hfs: splitting index node.\n");
|
||||||
fd->bnode = parent;
|
fd->bnode = parent;
|
||||||
new_node = hfs_bnode_split(fd);
|
new_node = hfs_bnode_split(fd);
|
||||||
if (IS_ERR(new_node))
|
if (IS_ERR(new_node))
|
||||||
@ -383,7 +392,8 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd)
|
|||||||
parent = fd->bnode;
|
parent = fd->bnode;
|
||||||
rec = fd->record;
|
rec = fd->record;
|
||||||
rec_off = tree->node_size - (rec + 2) * 2;
|
rec_off = tree->node_size - (rec + 2) * 2;
|
||||||
end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
|
end_rec_off = tree->node_size -
|
||||||
|
(parent->num_recs + 1) * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
|
|||||||
goto free_inode;
|
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));
|
||||||
tree->root = be32_to_cpu(head->root);
|
tree->root = be32_to_cpu(head->root);
|
||||||
tree->leaf_count = be32_to_cpu(head->leaf_count);
|
tree->leaf_count = be32_to_cpu(head->leaf_count);
|
||||||
tree->leaf_head = be32_to_cpu(head->leaf_head);
|
tree->leaf_head = be32_to_cpu(head->leaf_head);
|
||||||
@ -115,7 +116,9 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
|
|||||||
|
|
||||||
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;
|
||||||
|
|
||||||
kunmap(page);
|
kunmap(page);
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
@ -144,8 +147,10 @@ void hfs_btree_close(struct hfs_btree *tree)
|
|||||||
while ((node = tree->node_hash[i])) {
|
while ((node = tree->node_hash[i])) {
|
||||||
tree->node_hash[i] = node->next_hash;
|
tree->node_hash[i] = node->next_hash;
|
||||||
if (atomic_read(&node->refcnt))
|
if (atomic_read(&node->refcnt))
|
||||||
printk(KERN_CRIT "hfs: node %d:%d still has %d user(s)!\n",
|
printk(KERN_CRIT "hfs: node %d:%d "
|
||||||
node->tree->cnid, node->this, atomic_read(&node->refcnt));
|
"still has %d user(s)!\n",
|
||||||
|
node->tree->cnid, node->this,
|
||||||
|
atomic_read(&node->refcnt));
|
||||||
hfs_bnode_free(node);
|
hfs_bnode_free(node);
|
||||||
tree->node_hash_cnt--;
|
tree->node_hash_cnt--;
|
||||||
}
|
}
|
||||||
@ -166,7 +171,8 @@ void hfs_btree_write(struct hfs_btree *tree)
|
|||||||
return;
|
return;
|
||||||
/* Load the header */
|
/* Load the header */
|
||||||
page = node->page[0];
|
page = node->page[0];
|
||||||
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));
|
||||||
|
|
||||||
head->root = cpu_to_be32(tree->root);
|
head->root = cpu_to_be32(tree->root);
|
||||||
head->leaf_count = cpu_to_be32(tree->leaf_count);
|
head->leaf_count = cpu_to_be32(tree->leaf_count);
|
||||||
@ -272,7 +278,8 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
|
|||||||
tree->free_nodes--;
|
tree->free_nodes--;
|
||||||
mark_inode_dirty(tree->inode);
|
mark_inode_dirty(tree->inode);
|
||||||
hfs_bnode_put(node);
|
hfs_bnode_put(node);
|
||||||
return hfs_bnode_create(tree, idx);
|
return hfs_bnode_create(tree,
|
||||||
|
idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,7 +294,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
|
|||||||
kunmap(*pagep);
|
kunmap(*pagep);
|
||||||
nidx = node->next;
|
nidx = node->next;
|
||||||
if (!nidx) {
|
if (!nidx) {
|
||||||
printk(KERN_DEBUG "hfs: create new bmap node...\n");
|
dprint(DBG_BNODE_MOD, "hfs: create new bmap node.\n");
|
||||||
next_node = hfs_bmap_new_bmap(node, idx);
|
next_node = hfs_bmap_new_bmap(node, idx);
|
||||||
} else
|
} else
|
||||||
next_node = hfs_bnode_find(tree, nidx);
|
next_node = hfs_bnode_find(tree, nidx);
|
||||||
@ -329,7 +336,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
|
|||||||
hfs_bnode_put(node);
|
hfs_bnode_put(node);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
/* panic */;
|
/* panic */;
|
||||||
printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this);
|
printk(KERN_CRIT "hfs: unable to free bnode %u. "
|
||||||
|
"bmap not found!\n",
|
||||||
|
node->this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
node = hfs_bnode_find(tree, i);
|
node = hfs_bnode_find(tree, i);
|
||||||
@ -337,7 +346,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
|
|||||||
return;
|
return;
|
||||||
if (node->type != HFS_NODE_MAP) {
|
if (node->type != HFS_NODE_MAP) {
|
||||||
/* panic */;
|
/* panic */;
|
||||||
printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type);
|
printk(KERN_CRIT "hfs: invalid bmap found! "
|
||||||
|
"(%u,%d)\n",
|
||||||
|
node->this, node->type);
|
||||||
hfs_bnode_put(node);
|
hfs_bnode_put(node);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -350,7 +361,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
|
|||||||
m = 1 << (~nidx & 7);
|
m = 1 << (~nidx & 7);
|
||||||
byte = data[off];
|
byte = data[off];
|
||||||
if (!(byte & m)) {
|
if (!(byte & m)) {
|
||||||
printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type);
|
printk(KERN_CRIT "hfs: trying to free free bnode "
|
||||||
|
"%u(%d)\n",
|
||||||
|
node->this, node->type);
|
||||||
kunmap(page);
|
kunmap(page);
|
||||||
hfs_bnode_put(node);
|
hfs_bnode_put(node);
|
||||||
return;
|
return;
|
||||||
|
@ -91,7 +91,8 @@ void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms)
|
|||||||
perms->dev = 0;
|
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);
|
struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
|
||||||
|
|
||||||
@ -128,20 +129,32 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
|
|||||||
if (cnid == inode->i_ino) {
|
if (cnid == inode->i_ino) {
|
||||||
hfsplus_cat_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 =
|
||||||
file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR);
|
cpu_to_be32(HFSP_SYMLINK_TYPE);
|
||||||
|
file->user_info.fdCreator =
|
||||||
|
cpu_to_be32(HFSP_SYMLINK_CREATOR);
|
||||||
} else {
|
} else {
|
||||||
file->user_info.fdType = cpu_to_be32(sbi->type);
|
file->user_info.fdType =
|
||||||
file->user_info.fdCreator = cpu_to_be32(sbi->creator);
|
cpu_to_be32(sbi->type);
|
||||||
|
file->user_info.fdCreator =
|
||||||
|
cpu_to_be32(sbi->creator);
|
||||||
}
|
}
|
||||||
if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
|
if (HFSPLUS_FLG_IMMUTABLE &
|
||||||
file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
|
(file->permissions.rootflags |
|
||||||
|
file->permissions.userflags))
|
||||||
|
file->flags |=
|
||||||
|
cpu_to_be16(HFSPLUS_FILE_LOCKED);
|
||||||
} else {
|
} else {
|
||||||
file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE);
|
file->user_info.fdType =
|
||||||
file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR);
|
cpu_to_be32(HFSP_HARDLINK_TYPE);
|
||||||
file->user_info.fdFlags = cpu_to_be16(0x100);
|
file->user_info.fdCreator =
|
||||||
file->create_date = HFSPLUS_I(sbi->hidden_dir)->create_date;
|
cpu_to_be32(HFSP_HFSPLUS_CREATOR);
|
||||||
file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode)->linkid);
|
file->user_info.fdFlags =
|
||||||
|
cpu_to_be16(0x100);
|
||||||
|
file->create_date =
|
||||||
|
HFSPLUS_I(sbi->hidden_dir)->create_date;
|
||||||
|
file->permissions.dev =
|
||||||
|
cpu_to_be32(HFSPLUS_I(inode)->linkid);
|
||||||
}
|
}
|
||||||
return sizeof(*file);
|
return sizeof(*file);
|
||||||
}
|
}
|
||||||
@ -182,12 +195,14 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
hfsplus_cat_build_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID),
|
hfsplus_cat_build_key_uni(fd->search_key,
|
||||||
&tmp.thread.nodeName);
|
be32_to_cpu(tmp.thread.parentID),
|
||||||
|
&tmp.thread.nodeName);
|
||||||
return hfs_brec_find(fd);
|
return hfs_brec_find(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 super_block *sb = dir->i_sb;
|
||||||
struct hfs_find_data fd;
|
struct hfs_find_data fd;
|
||||||
@ -195,13 +210,15 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
|
|||||||
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);
|
||||||
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) ?
|
||||||
HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD,
|
HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD,
|
||||||
dir->i_ino, str);
|
dir->i_ino, str);
|
||||||
err = hfs_brec_find(&fd);
|
err = hfs_brec_find(&fd);
|
||||||
if (err != -ENOENT) {
|
if (err != -ENOENT) {
|
||||||
if (!err)
|
if (!err)
|
||||||
@ -227,7 +244,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
|
|||||||
|
|
||||||
dir->i_size++;
|
dir->i_size++;
|
||||||
dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
|
dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
|
||||||
mark_inode_dirty(dir);
|
hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
|
||||||
|
|
||||||
hfs_find_exit(&fd);
|
hfs_find_exit(&fd);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -249,7 +267,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
|
|||||||
int err, off;
|
int err, off;
|
||||||
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);
|
||||||
hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
|
hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
|
||||||
|
|
||||||
if (!str) {
|
if (!str) {
|
||||||
@ -260,11 +279,15 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
|
|||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
off = fd.entryoffset + offsetof(struct hfsplus_cat_thread, nodeName);
|
off = fd.entryoffset +
|
||||||
|
offsetof(struct hfsplus_cat_thread, nodeName);
|
||||||
fd.search_key->cat.parent = cpu_to_be32(dir->i_ino);
|
fd.search_key->cat.parent = cpu_to_be32(dir->i_ino);
|
||||||
hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.length, off, 2);
|
hfs_bnode_read(fd.bnode,
|
||||||
|
&fd.search_key->cat.name.length, off, 2);
|
||||||
len = be16_to_cpu(fd.search_key->cat.name.length) * 2;
|
len = be16_to_cpu(fd.search_key->cat.name.length) * 2;
|
||||||
hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.unicode, off + 2, len);
|
hfs_bnode_read(fd.bnode,
|
||||||
|
&fd.search_key->cat.name.unicode,
|
||||||
|
off + 2, len);
|
||||||
fd.search_key->key_len = cpu_to_be16(6 + len);
|
fd.search_key->key_len = cpu_to_be16(6 + len);
|
||||||
} else
|
} else
|
||||||
hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
|
hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
|
||||||
@ -281,7 +304,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
|
|||||||
hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA);
|
hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
off = fd.entryoffset + offsetof(struct hfsplus_cat_file, rsrc_fork);
|
off = fd.entryoffset +
|
||||||
|
offsetof(struct hfsplus_cat_file, rsrc_fork);
|
||||||
hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork));
|
hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork));
|
||||||
hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC);
|
hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC);
|
||||||
}
|
}
|
||||||
@ -308,7 +332,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
|
|||||||
|
|
||||||
dir->i_size--;
|
dir->i_size--;
|
||||||
dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
|
dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
|
||||||
mark_inode_dirty(dir);
|
hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
|
||||||
out:
|
out:
|
||||||
hfs_find_exit(&fd);
|
hfs_find_exit(&fd);
|
||||||
|
|
||||||
@ -325,7 +349,8 @@ int hfsplus_rename_cat(u32 cnid,
|
|||||||
int entry_size, type;
|
int entry_size, type;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
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);
|
||||||
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;
|
||||||
@ -353,7 +378,6 @@ int hfsplus_rename_cat(u32 cnid,
|
|||||||
goto out;
|
goto out;
|
||||||
dst_dir->i_size++;
|
dst_dir->i_size++;
|
||||||
dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
|
dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
|
||||||
mark_inode_dirty(dst_dir);
|
|
||||||
|
|
||||||
/* finally remove the old entry */
|
/* finally remove the old entry */
|
||||||
hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
|
hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
|
||||||
@ -365,7 +389,6 @@ int hfsplus_rename_cat(u32 cnid,
|
|||||||
goto out;
|
goto out;
|
||||||
src_dir->i_size--;
|
src_dir->i_size--;
|
||||||
src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
|
src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
|
||||||
mark_inode_dirty(src_dir);
|
|
||||||
|
|
||||||
/* remove old thread entry */
|
/* remove old thread entry */
|
||||||
hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL);
|
hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL);
|
||||||
@ -379,7 +402,8 @@ int hfsplus_rename_cat(u32 cnid,
|
|||||||
|
|
||||||
/* create new thread entry */
|
/* create new thread entry */
|
||||||
hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
|
hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
|
||||||
entry_size = hfsplus_fill_cat_thread(sb, &entry, type, dst_dir->i_ino, dst_name);
|
entry_size = hfsplus_fill_cat_thread(sb, &entry, type,
|
||||||
|
dst_dir->i_ino, dst_name);
|
||||||
err = hfs_brec_find(&dst_fd);
|
err = hfs_brec_find(&dst_fd);
|
||||||
if (err != -ENOENT) {
|
if (err != -ENOENT) {
|
||||||
if (!err)
|
if (!err)
|
||||||
@ -387,6 +411,9 @@ int hfsplus_rename_cat(u32 cnid,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
err = hfs_brec_insert(&dst_fd, &entry, entry_size);
|
err = hfs_brec_insert(&dst_fd, &entry, entry_size);
|
||||||
|
|
||||||
|
hfsplus_mark_inode_dirty(dst_dir, HFSPLUS_I_CAT_DIRTY);
|
||||||
|
hfsplus_mark_inode_dirty(src_dir, HFSPLUS_I_CAT_DIRTY);
|
||||||
out:
|
out:
|
||||||
hfs_bnode_put(dst_fd.bnode);
|
hfs_bnode_put(dst_fd.bnode);
|
||||||
hfs_find_exit(&src_fd);
|
hfs_find_exit(&src_fd);
|
||||||
|
@ -66,11 +66,17 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
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 ==
|
||||||
entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
|
cpu_to_be32(HFSP_HARDLINK_TYPE) &&
|
||||||
(entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->create_date ||
|
entry.file.user_info.fdCreator ==
|
||||||
entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode)->create_date) &&
|
cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
|
||||||
HFSPLUS_SB(sb)->hidden_dir) {
|
(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) &&
|
||||||
|
HFSPLUS_SB(sb)->hidden_dir) {
|
||||||
struct qstr str;
|
struct qstr str;
|
||||||
char name[32];
|
char name[32];
|
||||||
|
|
||||||
@ -83,11 +89,13 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
|
|||||||
linkid = 0;
|
linkid = 0;
|
||||||
} else {
|
} else {
|
||||||
dentry->d_fsdata = (void *)(unsigned long)cnid;
|
dentry->d_fsdata = (void *)(unsigned long)cnid;
|
||||||
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_cat_build_key(sb, fd.search_key,
|
||||||
HFSPLUS_SB(sb)->hidden_dir->i_ino, &str);
|
HFSPLUS_SB(sb)->hidden_dir->i_ino,
|
||||||
|
&str);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
} else if (!dentry->d_fsdata)
|
} else if (!dentry->d_fsdata)
|
||||||
@ -139,7 +147,8 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||||||
filp->f_pos++;
|
filp->f_pos++;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 1:
|
case 1:
|
||||||
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
|
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
|
||||||
|
fd.entrylength);
|
||||||
if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) {
|
if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) {
|
||||||
printk(KERN_ERR "hfs: bad catalog folder thread\n");
|
printk(KERN_ERR "hfs: bad catalog folder thread\n");
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
@ -169,14 +178,16 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
|
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
|
||||||
|
fd.entrylength);
|
||||||
type = be16_to_cpu(entry.type);
|
type = be16_to_cpu(entry.type);
|
||||||
len = HFSPLUS_MAX_STRLEN;
|
len = HFSPLUS_MAX_STRLEN;
|
||||||
err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len);
|
err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
if (type == HFSPLUS_FOLDER) {
|
if (type == HFSPLUS_FOLDER) {
|
||||||
if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) {
|
if (fd.entrylength <
|
||||||
|
sizeof(struct hfsplus_cat_folder)) {
|
||||||
printk(KERN_ERR "hfs: small dir entry\n");
|
printk(KERN_ERR "hfs: small dir entry\n");
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
@ -202,7 +213,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
next:
|
next:
|
||||||
filp->f_pos++;
|
filp->f_pos++;
|
||||||
if (filp->f_pos >= inode->i_size)
|
if (filp->f_pos >= inode->i_size)
|
||||||
goto out;
|
goto out;
|
||||||
@ -273,7 +284,8 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
|
|||||||
HFSPLUS_I(inode)->linkid = id;
|
HFSPLUS_I(inode)->linkid = id;
|
||||||
cnid = sbi->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? */
|
||||||
goto out;
|
goto out;
|
||||||
@ -485,6 +497,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const struct file_operations hfsplus_dir_operations = {
|
const struct file_operations hfsplus_dir_operations = {
|
||||||
|
.fsync = hfsplus_file_fsync,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.readdir = hfsplus_readdir,
|
.readdir = hfsplus_readdir,
|
||||||
.unlocked_ioctl = hfsplus_ioctl,
|
.unlocked_ioctl = hfsplus_ioctl,
|
||||||
|
@ -83,7 +83,8 @@ static u32 hfsplus_ext_lastblock(struct hfsplus_extent *ext)
|
|||||||
return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count);
|
return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
|
||||||
int res;
|
int res;
|
||||||
@ -95,24 +96,32 @@ static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data
|
|||||||
HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
|
HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
|
||||||
|
|
||||||
res = hfs_brec_find(fd);
|
res = hfs_brec_find(fd);
|
||||||
if (hip->flags & HFSPLUS_FLG_EXT_NEW) {
|
if (hip->extent_state & HFSPLUS_EXT_NEW) {
|
||||||
if (res != -ENOENT)
|
if (res != -ENOENT)
|
||||||
return;
|
return;
|
||||||
hfs_brec_insert(fd, hip->cached_extents,
|
hfs_brec_insert(fd, hip->cached_extents,
|
||||||
sizeof(hfsplus_extent_rec));
|
sizeof(hfsplus_extent_rec));
|
||||||
hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
|
hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
|
||||||
} else {
|
} else {
|
||||||
if (res)
|
if (res)
|
||||||
return;
|
return;
|
||||||
hfs_bnode_write(fd->bnode, hip->cached_extents,
|
hfs_bnode_write(fd->bnode, hip->cached_extents,
|
||||||
fd->entryoffset, fd->entrylength);
|
fd->entryoffset, fd->entrylength);
|
||||||
hip->flags &= ~HFSPLUS_FLG_EXT_DIRTY;
|
hip->extent_state &= ~HFSPLUS_EXT_DIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can't just use hfsplus_mark_inode_dirty here, because we
|
||||||
|
* also get called from hfsplus_write_inode, which should not
|
||||||
|
* redirty the inode. Instead the callers have to be careful
|
||||||
|
* to explicily mark the inode dirty, too.
|
||||||
|
*/
|
||||||
|
set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hfsplus_ext_write_extent_locked(struct inode *inode)
|
static void hfsplus_ext_write_extent_locked(struct inode *inode)
|
||||||
{
|
{
|
||||||
if (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_EXT_DIRTY) {
|
if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) {
|
||||||
struct hfs_find_data fd;
|
struct hfs_find_data fd;
|
||||||
|
|
||||||
hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
|
hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
|
||||||
@ -144,18 +153,20 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
if (fd->entrylength != sizeof(hfsplus_extent_rec))
|
if (fd->entrylength != sizeof(hfsplus_extent_rec))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfsplus_extent_rec));
|
hfs_bnode_read(fd->bnode, extent, fd->entryoffset,
|
||||||
|
sizeof(hfsplus_extent_rec));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
WARN_ON(!mutex_is_locked(&hip->extents_lock));
|
WARN_ON(!mutex_is_locked(&hip->extents_lock));
|
||||||
|
|
||||||
if (hip->flags & HFSPLUS_FLG_EXT_DIRTY)
|
if (hip->extent_state & HFSPLUS_EXT_DIRTY)
|
||||||
__hfsplus_ext_write_extent(inode, fd);
|
__hfsplus_ext_write_extent(inode, fd);
|
||||||
|
|
||||||
res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino,
|
res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino,
|
||||||
@ -164,10 +175,11 @@ static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct in
|
|||||||
HFSPLUS_TYPE_DATA);
|
HFSPLUS_TYPE_DATA);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
hip->cached_start = be32_to_cpu(fd->key->ext.start_block);
|
hip->cached_start = be32_to_cpu(fd->key->ext.start_block);
|
||||||
hip->cached_blocks = hfsplus_ext_block_count(hip->cached_extents);
|
hip->cached_blocks =
|
||||||
|
hfsplus_ext_block_count(hip->cached_extents);
|
||||||
} else {
|
} else {
|
||||||
hip->cached_start = hip->cached_blocks = 0;
|
hip->cached_start = hip->cached_blocks = 0;
|
||||||
hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
|
hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -197,6 +209,7 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
|
|||||||
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
|
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
|
||||||
int res = -EIO;
|
int res = -EIO;
|
||||||
u32 ablock, dblock, mask;
|
u32 ablock, dblock, mask;
|
||||||
|
int was_dirty = 0;
|
||||||
int shift;
|
int shift;
|
||||||
|
|
||||||
/* Convert inode block to disk allocation block */
|
/* Convert inode block to disk allocation block */
|
||||||
@ -223,27 +236,37 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
mutex_lock(&hip->extents_lock);
|
mutex_lock(&hip->extents_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hfsplus_ext_read_extent will write out a cached extent into
|
||||||
|
* the extents btree. In that case we may have to mark the inode
|
||||||
|
* dirty even for a pure read of an extent here.
|
||||||
|
*/
|
||||||
|
was_dirty = (hip->extent_state & HFSPLUS_EXT_DIRTY);
|
||||||
res = hfsplus_ext_read_extent(inode, ablock);
|
res = hfsplus_ext_read_extent(inode, ablock);
|
||||||
if (!res) {
|
if (res) {
|
||||||
dblock = hfsplus_ext_find_block(hip->cached_extents,
|
|
||||||
ablock - hip->cached_start);
|
|
||||||
} else {
|
|
||||||
mutex_unlock(&hip->extents_lock);
|
mutex_unlock(&hip->extents_lock);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
dblock = hfsplus_ext_find_block(hip->cached_extents,
|
||||||
|
ablock - hip->cached_start);
|
||||||
mutex_unlock(&hip->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 << sbi->fs_shift) - 1;
|
mask = (1 << sbi->fs_shift) - 1;
|
||||||
map_bh(bh_result, sb, (dblock << sbi->fs_shift) + sbi->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);
|
||||||
hip->phys_size += sb->s_blocksize;
|
hip->phys_size += sb->s_blocksize;
|
||||||
hip->fs_blocks++;
|
hip->fs_blocks++;
|
||||||
inode_add_bytes(inode, sb->s_blocksize);
|
inode_add_bytes(inode, sb->s_blocksize);
|
||||||
mark_inode_dirty(inode);
|
|
||||||
}
|
}
|
||||||
|
if (create || was_dirty)
|
||||||
|
mark_inode_dirty(inode);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +349,8 @@ static int hfsplus_free_extents(struct super_block *sb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw *fork, int type)
|
int hfsplus_free_fork(struct super_block *sb, u32 cnid,
|
||||||
|
struct hfsplus_fork_raw *fork, int type)
|
||||||
{
|
{
|
||||||
struct hfs_find_data fd;
|
struct hfs_find_data fd;
|
||||||
hfsplus_extent_rec ext_entry;
|
hfsplus_extent_rec ext_entry;
|
||||||
@ -373,12 +397,13 @@ int hfsplus_file_extend(struct inode *inode)
|
|||||||
u32 start, len, goal;
|
u32 start, len, goal;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (sbi->alloc_file->i_size * 8 <
|
if (sbi->total_blocks - sbi->free_blocks + 8 >
|
||||||
sbi->total_blocks - sbi->free_blocks + 8) {
|
sbi->alloc_file->i_size * 8) {
|
||||||
// extend alloc file
|
/* extend alloc file */
|
||||||
printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n",
|
printk(KERN_ERR "hfs: extend alloc file! "
|
||||||
sbi->alloc_file->i_size * 8,
|
"(%llu,%u,%u)\n",
|
||||||
sbi->total_blocks, sbi->free_blocks);
|
sbi->alloc_file->i_size * 8,
|
||||||
|
sbi->total_blocks, sbi->free_blocks);
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,7 +454,7 @@ int hfsplus_file_extend(struct inode *inode)
|
|||||||
start, len);
|
start, len);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
hfsplus_dump_extent(hip->cached_extents);
|
hfsplus_dump_extent(hip->cached_extents);
|
||||||
hip->flags |= HFSPLUS_FLG_EXT_DIRTY;
|
hip->extent_state |= HFSPLUS_EXT_DIRTY;
|
||||||
hip->cached_blocks += len;
|
hip->cached_blocks += len;
|
||||||
} else if (res == -ENOSPC)
|
} else if (res == -ENOSPC)
|
||||||
goto insert_extent;
|
goto insert_extent;
|
||||||
@ -438,7 +463,7 @@ int hfsplus_file_extend(struct inode *inode)
|
|||||||
mutex_unlock(&hip->extents_lock);
|
mutex_unlock(&hip->extents_lock);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
hip->alloc_blocks += len;
|
hip->alloc_blocks += len;
|
||||||
mark_inode_dirty(inode);
|
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
@ -450,7 +475,7 @@ int hfsplus_file_extend(struct inode *inode)
|
|||||||
hip->cached_extents[0].start_block = cpu_to_be32(start);
|
hip->cached_extents[0].start_block = cpu_to_be32(start);
|
||||||
hip->cached_extents[0].block_count = cpu_to_be32(len);
|
hip->cached_extents[0].block_count = cpu_to_be32(len);
|
||||||
hfsplus_dump_extent(hip->cached_extents);
|
hfsplus_dump_extent(hip->cached_extents);
|
||||||
hip->flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW;
|
hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW;
|
||||||
hip->cached_start = hip->alloc_blocks;
|
hip->cached_start = hip->alloc_blocks;
|
||||||
hip->cached_blocks = len;
|
hip->cached_blocks = len;
|
||||||
|
|
||||||
@ -466,8 +491,9 @@ void hfsplus_file_truncate(struct inode *inode)
|
|||||||
u32 alloc_cnt, blk_cnt, start;
|
u32 alloc_cnt, blk_cnt, start;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n",
|
dprint(DBG_INODE, "truncate: %lu, %llu -> %llu\n",
|
||||||
inode->i_ino, (long long)hip->phys_size, inode->i_size);
|
inode->i_ino, (long long)hip->phys_size,
|
||||||
|
inode->i_size);
|
||||||
|
|
||||||
if (inode->i_size > hip->phys_size) {
|
if (inode->i_size > hip->phys_size) {
|
||||||
struct address_space *mapping = inode->i_mapping;
|
struct address_space *mapping = inode->i_mapping;
|
||||||
@ -481,7 +507,8 @@ void hfsplus_file_truncate(struct inode *inode)
|
|||||||
&page, &fsdata);
|
&page, &fsdata);
|
||||||
if (res)
|
if (res)
|
||||||
return;
|
return;
|
||||||
res = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata);
|
res = pagecache_write_end(NULL, mapping, size,
|
||||||
|
0, 0, page, fsdata);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return;
|
return;
|
||||||
mark_inode_dirty(inode);
|
mark_inode_dirty(inode);
|
||||||
@ -513,12 +540,12 @@ void hfsplus_file_truncate(struct inode *inode)
|
|||||||
alloc_cnt - start, alloc_cnt - blk_cnt);
|
alloc_cnt - start, alloc_cnt - blk_cnt);
|
||||||
hfsplus_dump_extent(hip->cached_extents);
|
hfsplus_dump_extent(hip->cached_extents);
|
||||||
if (blk_cnt > start) {
|
if (blk_cnt > start) {
|
||||||
hip->flags |= HFSPLUS_FLG_EXT_DIRTY;
|
hip->extent_state |= HFSPLUS_EXT_DIRTY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
alloc_cnt = start;
|
alloc_cnt = start;
|
||||||
hip->cached_start = hip->cached_blocks = 0;
|
hip->cached_start = hip->cached_blocks = 0;
|
||||||
hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
|
hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
|
||||||
hfs_brec_remove(&fd);
|
hfs_brec_remove(&fd);
|
||||||
}
|
}
|
||||||
hfs_find_exit(&fd);
|
hfs_find_exit(&fd);
|
||||||
@ -527,7 +554,8 @@ void hfsplus_file_truncate(struct inode *inode)
|
|||||||
hip->alloc_blocks = blk_cnt;
|
hip->alloc_blocks = blk_cnt;
|
||||||
out:
|
out:
|
||||||
hip->phys_size = inode->i_size;
|
hip->phys_size = inode->i_size;
|
||||||
hip->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, hip->fs_blocks << sb->s_blocksize_bits);
|
inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
|
||||||
mark_inode_dirty(inode);
|
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,16 @@
|
|||||||
#define DBG_EXTENT 0x00000020
|
#define DBG_EXTENT 0x00000020
|
||||||
#define DBG_BITMAP 0x00000040
|
#define DBG_BITMAP 0x00000040
|
||||||
|
|
||||||
//#define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
|
#if 0
|
||||||
//#define DBG_MASK (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
|
#define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
|
||||||
//#define DBG_MASK (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
|
#define DBG_MASK (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
|
||||||
|
#define DBG_MASK (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
|
||||||
|
#endif
|
||||||
#define DBG_MASK (0)
|
#define DBG_MASK (0)
|
||||||
|
|
||||||
#define dprint(flg, fmt, args...) \
|
#define dprint(flg, fmt, args...) \
|
||||||
if (flg & DBG_MASK) printk(fmt , ## args)
|
if (flg & DBG_MASK) \
|
||||||
|
printk(fmt , ## args)
|
||||||
|
|
||||||
/* Runtime config options */
|
/* Runtime config options */
|
||||||
#define HFSPLUS_DEF_CR_TYPE 0x3F3F3F3F /* '????' */
|
#define HFSPLUS_DEF_CR_TYPE 0x3F3F3F3F /* '????' */
|
||||||
@ -37,7 +40,8 @@
|
|||||||
#define HFSPLUS_TYPE_DATA 0x00
|
#define HFSPLUS_TYPE_DATA 0x00
|
||||||
#define HFSPLUS_TYPE_RSRC 0xFF
|
#define HFSPLUS_TYPE_RSRC 0xFF
|
||||||
|
|
||||||
typedef int (*btree_keycmp)(const hfsplus_btree_key *, const hfsplus_btree_key *);
|
typedef int (*btree_keycmp)(const hfsplus_btree_key *,
|
||||||
|
const hfsplus_btree_key *);
|
||||||
|
|
||||||
#define NODE_HASH_SIZE 256
|
#define NODE_HASH_SIZE 256
|
||||||
|
|
||||||
@ -61,7 +65,6 @@ struct hfs_btree {
|
|||||||
unsigned int max_key_len;
|
unsigned int max_key_len;
|
||||||
unsigned int depth;
|
unsigned int depth;
|
||||||
|
|
||||||
//unsigned int map1_size, map_size;
|
|
||||||
struct mutex tree_lock;
|
struct mutex tree_lock;
|
||||||
|
|
||||||
unsigned int pages_per_bnode;
|
unsigned int pages_per_bnode;
|
||||||
@ -107,8 +110,8 @@ struct hfsplus_vh;
|
|||||||
struct hfs_btree;
|
struct hfs_btree;
|
||||||
|
|
||||||
struct hfsplus_sb_info {
|
struct hfsplus_sb_info {
|
||||||
struct buffer_head *s_vhbh;
|
|
||||||
struct hfsplus_vh *s_vhdr;
|
struct hfsplus_vh *s_vhdr;
|
||||||
|
struct hfsplus_vh *s_backup_vhdr;
|
||||||
struct hfs_btree *ext_tree;
|
struct hfs_btree *ext_tree;
|
||||||
struct hfs_btree *cat_tree;
|
struct hfs_btree *cat_tree;
|
||||||
struct hfs_btree *attr_tree;
|
struct hfs_btree *attr_tree;
|
||||||
@ -118,7 +121,8 @@ struct hfsplus_sb_info {
|
|||||||
|
|
||||||
/* Runtime variables */
|
/* Runtime variables */
|
||||||
u32 blockoffset;
|
u32 blockoffset;
|
||||||
u32 sect_count;
|
sector_t part_start;
|
||||||
|
sector_t sect_count;
|
||||||
int fs_shift;
|
int fs_shift;
|
||||||
|
|
||||||
/* immutable data from the volume header */
|
/* immutable data from the volume header */
|
||||||
@ -155,6 +159,12 @@ struct hfsplus_sb_info {
|
|||||||
#define HFSPLUS_SB_FORCE 2
|
#define HFSPLUS_SB_FORCE 2
|
||||||
#define HFSPLUS_SB_HFSX 3
|
#define HFSPLUS_SB_HFSX 3
|
||||||
#define HFSPLUS_SB_CASEFOLD 4
|
#define HFSPLUS_SB_CASEFOLD 4
|
||||||
|
#define HFSPLUS_SB_NOBARRIER 5
|
||||||
|
|
||||||
|
static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
|
||||||
|
{
|
||||||
|
return sb->s_fs_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct hfsplus_inode_info {
|
struct hfsplus_inode_info {
|
||||||
@ -170,7 +180,7 @@ struct hfsplus_inode_info {
|
|||||||
u32 cached_blocks;
|
u32 cached_blocks;
|
||||||
hfsplus_extent_rec first_extents;
|
hfsplus_extent_rec first_extents;
|
||||||
hfsplus_extent_rec cached_extents;
|
hfsplus_extent_rec cached_extents;
|
||||||
unsigned long flags;
|
unsigned int extent_state;
|
||||||
struct mutex extents_lock;
|
struct mutex extents_lock;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -184,6 +194,11 @@ struct hfsplus_inode_info {
|
|||||||
*/
|
*/
|
||||||
u32 linkid;
|
u32 linkid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Accessed using atomic bitops.
|
||||||
|
*/
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Protected by i_mutex.
|
* Protected by i_mutex.
|
||||||
*/
|
*/
|
||||||
@ -195,12 +210,34 @@ struct hfsplus_inode_info {
|
|||||||
struct inode vfs_inode;
|
struct inode vfs_inode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HFSPLUS_FLG_RSRC 0x0001
|
#define HFSPLUS_EXT_DIRTY 0x0001
|
||||||
#define HFSPLUS_FLG_EXT_DIRTY 0x0002
|
#define HFSPLUS_EXT_NEW 0x0002
|
||||||
#define HFSPLUS_FLG_EXT_NEW 0x0004
|
|
||||||
|
|
||||||
#define HFSPLUS_IS_DATA(inode) (!(HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC))
|
#define HFSPLUS_I_RSRC 0 /* represents a resource fork */
|
||||||
#define HFSPLUS_IS_RSRC(inode) (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC)
|
#define HFSPLUS_I_CAT_DIRTY 1 /* has changes in the catalog tree */
|
||||||
|
#define HFSPLUS_I_EXT_DIRTY 2 /* has changes in the extent tree */
|
||||||
|
#define HFSPLUS_I_ALLOC_DIRTY 3 /* has changes in the allocation file */
|
||||||
|
|
||||||
|
#define HFSPLUS_IS_RSRC(inode) \
|
||||||
|
test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags)
|
||||||
|
|
||||||
|
static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
|
||||||
|
{
|
||||||
|
return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark an inode dirty, and also mark the btree in which the
|
||||||
|
* specific type of metadata is stored.
|
||||||
|
* For data or metadata that gets written back by into the catalog btree
|
||||||
|
* by hfsplus_write_inode a plain mark_inode_dirty call is enough.
|
||||||
|
*/
|
||||||
|
static inline void hfsplus_mark_inode_dirty(struct inode *inode,
|
||||||
|
unsigned int flag)
|
||||||
|
{
|
||||||
|
set_bit(flag, &HFSPLUS_I(inode)->flags);
|
||||||
|
mark_inode_dirty(inode);
|
||||||
|
}
|
||||||
|
|
||||||
struct hfs_find_data {
|
struct hfs_find_data {
|
||||||
/* filled by caller */
|
/* filled by caller */
|
||||||
@ -318,9 +355,12 @@ int hfs_brec_read(struct hfs_find_data *, void *, int);
|
|||||||
int hfs_brec_goto(struct hfs_find_data *, int);
|
int hfs_brec_goto(struct hfs_find_data *, int);
|
||||||
|
|
||||||
/* catalog.c */
|
/* catalog.c */
|
||||||
int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
|
int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *,
|
||||||
int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
|
const hfsplus_btree_key *);
|
||||||
void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *);
|
int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *,
|
||||||
|
const hfsplus_btree_key *);
|
||||||
|
void hfsplus_cat_build_key(struct super_block *sb,
|
||||||
|
hfsplus_btree_key *, u32, struct qstr *);
|
||||||
int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *);
|
int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *);
|
||||||
int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *);
|
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 *);
|
||||||
@ -336,7 +376,8 @@ extern const struct file_operations hfsplus_dir_operations;
|
|||||||
int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
|
int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
|
||||||
void hfsplus_ext_write_extent(struct inode *);
|
void hfsplus_ext_write_extent(struct inode *);
|
||||||
int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int);
|
int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int);
|
||||||
int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int);
|
int hfsplus_free_fork(struct super_block *, u32,
|
||||||
|
struct hfsplus_fork_raw *, int);
|
||||||
int hfsplus_file_extend(struct inode *);
|
int hfsplus_file_extend(struct inode *);
|
||||||
void hfsplus_file_truncate(struct inode *);
|
void hfsplus_file_truncate(struct inode *);
|
||||||
|
|
||||||
@ -351,6 +392,7 @@ int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *);
|
|||||||
int hfsplus_cat_write_inode(struct inode *);
|
int hfsplus_cat_write_inode(struct inode *);
|
||||||
struct inode *hfsplus_new_inode(struct super_block *, int);
|
struct inode *hfsplus_new_inode(struct super_block *, int);
|
||||||
void hfsplus_delete_inode(struct inode *);
|
void hfsplus_delete_inode(struct inode *);
|
||||||
|
int hfsplus_file_fsync(struct file *file, int datasync);
|
||||||
|
|
||||||
/* ioctl.c */
|
/* ioctl.c */
|
||||||
long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
|
long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
|
||||||
@ -362,6 +404,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
|||||||
|
|
||||||
/* options.c */
|
/* options.c */
|
||||||
int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
|
int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
|
||||||
|
int hfsplus_parse_options_remount(char *input, int *force);
|
||||||
void hfsplus_fill_defaults(struct hfsplus_sb_info *);
|
void hfsplus_fill_defaults(struct hfsplus_sb_info *);
|
||||||
int hfsplus_show_options(struct seq_file *, struct vfsmount *);
|
int hfsplus_show_options(struct seq_file *, struct vfsmount *);
|
||||||
|
|
||||||
@ -375,12 +418,16 @@ extern u16 hfsplus_decompose_table[];
|
|||||||
extern u16 hfsplus_compose_table[];
|
extern u16 hfsplus_compose_table[];
|
||||||
|
|
||||||
/* unicode.c */
|
/* unicode.c */
|
||||||
int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
|
int hfsplus_strcasecmp(const struct hfsplus_unistr *,
|
||||||
int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
|
const struct hfsplus_unistr *);
|
||||||
int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *);
|
int hfsplus_strcmp(const struct hfsplus_unistr *,
|
||||||
int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
|
const struct hfsplus_unistr *);
|
||||||
int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
|
int hfsplus_uni2asc(struct super_block *,
|
||||||
struct qstr *str);
|
const struct hfsplus_unistr *, char *, int *);
|
||||||
|
int hfsplus_asc2uni(struct super_block *,
|
||||||
|
struct hfsplus_unistr *, const char *, int);
|
||||||
|
int hfsplus_hash_dentry(const struct dentry *dentry,
|
||||||
|
const struct inode *inode, struct qstr *str);
|
||||||
int hfsplus_compare_dentry(const struct dentry *parent,
|
int hfsplus_compare_dentry(const struct dentry *parent,
|
||||||
const struct inode *pinode,
|
const struct inode *pinode,
|
||||||
const struct dentry *dentry, const struct inode *inode,
|
const struct dentry *dentry, const struct inode *inode,
|
||||||
@ -388,36 +435,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
|
|||||||
|
|
||||||
/* wrapper.c */
|
/* wrapper.c */
|
||||||
int hfsplus_read_wrapper(struct super_block *);
|
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 *);
|
||||||
|
int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
|
||||||
/* access macros */
|
void *data, int rw);
|
||||||
static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
|
|
||||||
{
|
|
||||||
return sb->s_fs_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
|
|
||||||
{
|
|
||||||
return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define sb_bread512(sb, sec, data) ({ \
|
|
||||||
struct buffer_head *__bh; \
|
|
||||||
sector_t __block; \
|
|
||||||
loff_t __start; \
|
|
||||||
int __offset; \
|
|
||||||
\
|
|
||||||
__start = (loff_t)(sec) << HFSPLUS_SECTOR_SHIFT;\
|
|
||||||
__block = __start >> (sb)->s_blocksize_bits; \
|
|
||||||
__offset = __start & ((sb)->s_blocksize - 1); \
|
|
||||||
__bh = sb_bread((sb), __block); \
|
|
||||||
if (likely(__bh != NULL)) \
|
|
||||||
data = (void *)(__bh->b_data + __offset);\
|
|
||||||
else \
|
|
||||||
data = NULL; \
|
|
||||||
__bh; \
|
|
||||||
})
|
|
||||||
|
|
||||||
/* time macros */
|
/* time macros */
|
||||||
#define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U)
|
#define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U)
|
||||||
|
@ -36,7 +36,8 @@
|
|||||||
#define HFSP_WRAPOFF_EMBEDSIG 0x7C
|
#define HFSP_WRAPOFF_EMBEDSIG 0x7C
|
||||||
#define HFSP_WRAPOFF_EMBEDEXT 0x7E
|
#define HFSP_WRAPOFF_EMBEDEXT 0x7E
|
||||||
|
|
||||||
#define HFSP_HIDDENDIR_NAME "\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80HFS+ Private Data"
|
#define HFSP_HIDDENDIR_NAME \
|
||||||
|
"\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80HFS+ Private Data"
|
||||||
|
|
||||||
#define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */
|
#define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */
|
||||||
#define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */
|
#define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
* Inode handling routines
|
* Inode handling routines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/blkdev.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
@ -77,7 +78,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
|
|||||||
if (!tree)
|
if (!tree)
|
||||||
return 0;
|
return 0;
|
||||||
if (tree->node_size >= PAGE_CACHE_SIZE) {
|
if (tree->node_size >= PAGE_CACHE_SIZE) {
|
||||||
nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT);
|
nidx = page->index >>
|
||||||
|
(tree->node_size_shift - PAGE_CACHE_SHIFT);
|
||||||
spin_lock(&tree->hash_lock);
|
spin_lock(&tree->hash_lock);
|
||||||
node = hfs_bnode_findhash(tree, nidx);
|
node = hfs_bnode_findhash(tree, nidx);
|
||||||
if (!node)
|
if (!node)
|
||||||
@ -90,7 +92,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
|
|||||||
}
|
}
|
||||||
spin_unlock(&tree->hash_lock);
|
spin_unlock(&tree->hash_lock);
|
||||||
} else {
|
} else {
|
||||||
nidx = page->index << (PAGE_CACHE_SHIFT - tree->node_size_shift);
|
nidx = page->index <<
|
||||||
|
(PAGE_CACHE_SHIFT - tree->node_size_shift);
|
||||||
i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
|
i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
|
||||||
spin_lock(&tree->hash_lock);
|
spin_lock(&tree->hash_lock);
|
||||||
do {
|
do {
|
||||||
@ -166,8 +169,8 @@ const struct dentry_operations hfsplus_dentry_operations = {
|
|||||||
.d_compare = hfsplus_compare_dentry,
|
.d_compare = hfsplus_compare_dentry,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry,
|
static struct dentry *hfsplus_file_lookup(struct inode *dir,
|
||||||
struct nameidata *nd)
|
struct dentry *dentry, struct nameidata *nd)
|
||||||
{
|
{
|
||||||
struct hfs_find_data fd;
|
struct hfs_find_data fd;
|
||||||
struct super_block *sb = dir->i_sb;
|
struct super_block *sb = dir->i_sb;
|
||||||
@ -190,7 +193,9 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
|
|||||||
inode->i_ino = dir->i_ino;
|
inode->i_ino = dir->i_ino;
|
||||||
INIT_LIST_HEAD(&hip->open_dir_list);
|
INIT_LIST_HEAD(&hip->open_dir_list);
|
||||||
mutex_init(&hip->extents_lock);
|
mutex_init(&hip->extents_lock);
|
||||||
hip->flags = HFSPLUS_FLG_RSRC;
|
hip->extent_state = 0;
|
||||||
|
hip->flags = 0;
|
||||||
|
set_bit(HFSPLUS_I_RSRC, &hip->flags);
|
||||||
|
|
||||||
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);
|
||||||
@ -219,7 +224,8 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
|
struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
|
||||||
u16 mode;
|
u16 mode;
|
||||||
@ -302,29 +308,41 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hfsplus_file_fsync(struct file *filp, int datasync)
|
int hfsplus_file_fsync(struct file *file, int datasync)
|
||||||
{
|
{
|
||||||
struct inode *inode = filp->f_mapping->host;
|
struct inode *inode = file->f_mapping->host;
|
||||||
struct super_block * sb;
|
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
|
||||||
int ret, err;
|
struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
|
||||||
|
int error = 0, error2;
|
||||||
|
|
||||||
/* sync the inode to buffers */
|
/*
|
||||||
ret = write_inode_now(inode, 0);
|
* Sync inode metadata into the catalog and extent trees.
|
||||||
|
*/
|
||||||
|
sync_inode_metadata(inode, 1);
|
||||||
|
|
||||||
/* sync the superblock to buffers */
|
/*
|
||||||
sb = inode->i_sb;
|
* And explicitly write out the btrees.
|
||||||
if (sb->s_dirt) {
|
*/
|
||||||
if (!(sb->s_flags & MS_RDONLY))
|
if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags))
|
||||||
hfsplus_sync_fs(sb, 1);
|
error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
|
||||||
else
|
|
||||||
sb->s_dirt = 0;
|
if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) {
|
||||||
|
error2 =
|
||||||
|
filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
|
||||||
|
if (!error)
|
||||||
|
error = error2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .. finally sync the buffers to disk */
|
if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) {
|
||||||
err = sync_blockdev(sb->s_bdev);
|
error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
|
||||||
if (!ret)
|
if (!error)
|
||||||
ret = err;
|
error = error2;
|
||||||
return ret;
|
}
|
||||||
|
|
||||||
|
if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
|
||||||
|
blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct inode_operations hfsplus_file_inode_operations = {
|
static const struct inode_operations hfsplus_file_inode_operations = {
|
||||||
@ -337,7 +355,7 @@ static const struct inode_operations hfsplus_file_inode_operations = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations hfsplus_file_operations = {
|
static const struct file_operations hfsplus_file_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = do_sync_read,
|
.read = do_sync_read,
|
||||||
.aio_read = generic_file_aio_read,
|
.aio_read = generic_file_aio_read,
|
||||||
.write = do_sync_write,
|
.write = do_sync_write,
|
||||||
@ -370,6 +388,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
|
|||||||
INIT_LIST_HEAD(&hip->open_dir_list);
|
INIT_LIST_HEAD(&hip->open_dir_list);
|
||||||
mutex_init(&hip->extents_lock);
|
mutex_init(&hip->extents_lock);
|
||||||
atomic_set(&hip->opencnt, 0);
|
atomic_set(&hip->opencnt, 0);
|
||||||
|
hip->extent_state = 0;
|
||||||
hip->flags = 0;
|
hip->flags = 0;
|
||||||
memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
|
memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
|
||||||
memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
|
memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
|
||||||
@ -457,7 +476,8 @@ void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
||||||
@ -499,13 +519,14 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
|
|||||||
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_read_fork(inode, HFSPLUS_IS_DATA(inode) ?
|
hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ?
|
||||||
&file->data_fork : &file->rsrc_fork);
|
&file->rsrc_fork : &file->data_fork);
|
||||||
hfsplus_get_perms(inode, &file->permissions, 0);
|
hfsplus_get_perms(inode, &file->permissions, 0);
|
||||||
inode->i_nlink = 1;
|
inode->i_nlink = 1;
|
||||||
if (S_ISREG(inode->i_mode)) {
|
if (S_ISREG(inode->i_mode)) {
|
||||||
if (file->permissions.dev)
|
if (file->permissions.dev)
|
||||||
inode->i_nlink = be32_to_cpu(file->permissions.dev);
|
inode->i_nlink =
|
||||||
|
be32_to_cpu(file->permissions.dev);
|
||||||
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;
|
||||||
@ -578,7 +599,9 @@ int hfsplus_cat_write_inode(struct inode *inode)
|
|||||||
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);
|
||||||
hfsplus_cat_set_perms(inode, &file->permissions);
|
hfsplus_cat_set_perms(inode, &file->permissions);
|
||||||
if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
|
if (HFSPLUS_FLG_IMMUTABLE &
|
||||||
|
(file->permissions.rootflags |
|
||||||
|
file->permissions.userflags))
|
||||||
file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
|
file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
|
||||||
else
|
else
|
||||||
file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
|
file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
|
||||||
@ -588,6 +611,8 @@ int hfsplus_cat_write_inode(struct inode *inode)
|
|||||||
hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
|
hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
|
||||||
sizeof(struct hfsplus_cat_file));
|
sizeof(struct hfsplus_cat_file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
|
||||||
out:
|
out:
|
||||||
hfs_find_exit(&fd);
|
hfs_find_exit(&fd);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -28,7 +28,7 @@ static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
|
|||||||
|
|
||||||
if (inode->i_flags & S_IMMUTABLE)
|
if (inode->i_flags & S_IMMUTABLE)
|
||||||
flags |= FS_IMMUTABLE_FL;
|
flags |= FS_IMMUTABLE_FL;
|
||||||
if (inode->i_flags |= S_APPEND)
|
if (inode->i_flags & S_APPEND)
|
||||||
flags |= FS_APPEND_FL;
|
flags |= FS_APPEND_FL;
|
||||||
if (hip->userflags & HFSPLUS_FLG_NODUMP)
|
if (hip->userflags & HFSPLUS_FLG_NODUMP)
|
||||||
flags |= FS_NODUMP_FL;
|
flags |= FS_NODUMP_FL;
|
||||||
@ -147,9 +147,11 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
|
|||||||
res = -ERANGE;
|
res = -ERANGE;
|
||||||
} else
|
} else
|
||||||
res = -EOPNOTSUPP;
|
res = -EOPNOTSUPP;
|
||||||
if (!res)
|
if (!res) {
|
||||||
hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
|
hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
|
||||||
sizeof(struct hfsplus_cat_file));
|
sizeof(struct hfsplus_cat_file));
|
||||||
|
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
hfs_find_exit(&fd);
|
hfs_find_exit(&fd);
|
||||||
return res;
|
return res;
|
||||||
|
@ -23,6 +23,7 @@ enum {
|
|||||||
opt_umask, opt_uid, opt_gid,
|
opt_umask, opt_uid, opt_gid,
|
||||||
opt_part, opt_session, opt_nls,
|
opt_part, opt_session, opt_nls,
|
||||||
opt_nodecompose, opt_decompose,
|
opt_nodecompose, opt_decompose,
|
||||||
|
opt_barrier, opt_nobarrier,
|
||||||
opt_force, opt_err
|
opt_force, opt_err
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,6 +38,8 @@ static const match_table_t tokens = {
|
|||||||
{ opt_nls, "nls=%s" },
|
{ opt_nls, "nls=%s" },
|
||||||
{ opt_decompose, "decompose" },
|
{ opt_decompose, "decompose" },
|
||||||
{ opt_nodecompose, "nodecompose" },
|
{ opt_nodecompose, "nodecompose" },
|
||||||
|
{ opt_barrier, "barrier" },
|
||||||
|
{ opt_nobarrier, "nobarrier" },
|
||||||
{ opt_force, "force" },
|
{ opt_force, "force" },
|
||||||
{ opt_err, NULL }
|
{ opt_err, NULL }
|
||||||
};
|
};
|
||||||
@ -65,6 +68,32 @@ static inline int match_fourchar(substring_t *arg, u32 *result)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hfsplus_parse_options_remount(char *input, int *force)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
substring_t args[MAX_OPT_ARGS];
|
||||||
|
int token;
|
||||||
|
|
||||||
|
if (!input)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while ((p = strsep(&input, ",")) != NULL) {
|
||||||
|
if (!*p)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
token = match_token(p, tokens, args);
|
||||||
|
switch (token) {
|
||||||
|
case opt_force:
|
||||||
|
*force = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse options from mount. Returns 0 on failure */
|
/* Parse options from mount. Returns 0 on failure */
|
||||||
/* input is the options passed to mount() as a string */
|
/* input is the options passed to mount() as a string */
|
||||||
int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
|
int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
|
||||||
@ -136,7 +165,9 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
|
|||||||
if (p)
|
if (p)
|
||||||
sbi->nls = load_nls(p);
|
sbi->nls = load_nls(p);
|
||||||
if (!sbi->nls) {
|
if (!sbi->nls) {
|
||||||
printk(KERN_ERR "hfs: unable to load nls mapping \"%s\"\n", p);
|
printk(KERN_ERR "hfs: unable to load "
|
||||||
|
"nls mapping \"%s\"\n",
|
||||||
|
p);
|
||||||
kfree(p);
|
kfree(p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -148,6 +179,12 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
|
|||||||
case opt_nodecompose:
|
case opt_nodecompose:
|
||||||
set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
|
set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
|
||||||
break;
|
break;
|
||||||
|
case opt_barrier:
|
||||||
|
clear_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags);
|
||||||
|
break;
|
||||||
|
case opt_nobarrier:
|
||||||
|
set_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags);
|
||||||
|
break;
|
||||||
case opt_force:
|
case opt_force:
|
||||||
set_bit(HFSPLUS_SB_FORCE, &sbi->flags);
|
set_bit(HFSPLUS_SB_FORCE, &sbi->flags);
|
||||||
break;
|
break;
|
||||||
@ -177,7 +214,8 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
|
|||||||
seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator);
|
seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator);
|
||||||
if (sbi->type != HFSPLUS_DEF_CR_TYPE)
|
if (sbi->type != HFSPLUS_DEF_CR_TYPE)
|
||||||
seq_printf(seq, ",type=%.4s", (char *)&sbi->type);
|
seq_printf(seq, ",type=%.4s", (char *)&sbi->type);
|
||||||
seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, sbi->uid, sbi->gid);
|
seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask,
|
||||||
|
sbi->uid, sbi->gid);
|
||||||
if (sbi->part >= 0)
|
if (sbi->part >= 0)
|
||||||
seq_printf(seq, ",part=%u", sbi->part);
|
seq_printf(seq, ",part=%u", sbi->part);
|
||||||
if (sbi->session >= 0)
|
if (sbi->session >= 0)
|
||||||
@ -186,5 +224,7 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
|
|||||||
seq_printf(seq, ",nls=%s", sbi->nls->charset);
|
seq_printf(seq, ",nls=%s", sbi->nls->charset);
|
||||||
if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags))
|
if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags))
|
||||||
seq_printf(seq, ",nodecompose");
|
seq_printf(seq, ",nodecompose");
|
||||||
|
if (test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
|
||||||
|
seq_printf(seq, ",nobarrier");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
* linux/fs/hfsplus/part_tbl.c
|
* linux/fs/hfsplus/part_tbl.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 1996-1997 Paul H. Hargrove
|
* Copyright (C) 1996-1997 Paul H. Hargrove
|
||||||
* This file may be distributed under the terms of the GNU General Public License.
|
* This file may be distributed under the terms of
|
||||||
|
* the GNU General Public License.
|
||||||
*
|
*
|
||||||
* Original code to handle the new style Mac partition table based on
|
* Original code to handle the new style Mac partition table based on
|
||||||
* a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
|
* a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
|
||||||
@ -13,6 +14,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/slab.h>
|
||||||
#include "hfsplus_fs.h"
|
#include "hfsplus_fs.h"
|
||||||
|
|
||||||
/* offsets to various blocks */
|
/* offsets to various blocks */
|
||||||
@ -58,77 +60,94 @@ struct new_pmap {
|
|||||||
*/
|
*/
|
||||||
struct old_pmap {
|
struct old_pmap {
|
||||||
__be16 pdSig; /* Signature bytes */
|
__be16 pdSig; /* Signature bytes */
|
||||||
struct old_pmap_entry {
|
struct old_pmap_entry {
|
||||||
__be32 pdStart;
|
__be32 pdStart;
|
||||||
__be32 pdSize;
|
__be32 pdSize;
|
||||||
__be32 pdFSID;
|
__be32 pdFSID;
|
||||||
} pdEntry[42];
|
} pdEntry[42];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
/*
|
static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm,
|
||||||
* hfs_part_find()
|
sector_t *part_start, sector_t *part_size)
|
||||||
*
|
|
||||||
* Parse the partition map looking for the
|
|
||||||
* start and length of the 'part'th HFS partition.
|
|
||||||
*/
|
|
||||||
int hfs_part_find(struct super_block *sb,
|
|
||||||
sector_t *part_start, sector_t *part_size)
|
|
||||||
{
|
{
|
||||||
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
|
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
|
||||||
struct buffer_head *bh;
|
int i;
|
||||||
__be16 *data;
|
|
||||||
int i, size, res;
|
|
||||||
|
|
||||||
res = -ENOENT;
|
for (i = 0; i < 42; i++) {
|
||||||
bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK, data);
|
struct old_pmap_entry *p = &pm->pdEntry[i];
|
||||||
if (!bh)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
switch (be16_to_cpu(*data)) {
|
if (p->pdStart && p->pdSize &&
|
||||||
case HFS_OLD_PMAP_MAGIC:
|
p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
|
||||||
{
|
(sbi->part < 0 || sbi->part == i)) {
|
||||||
struct old_pmap *pm;
|
*part_start += be32_to_cpu(p->pdStart);
|
||||||
struct old_pmap_entry *p;
|
*part_size = be32_to_cpu(p->pdSize);
|
||||||
|
return 0;
|
||||||
pm = (struct old_pmap *)bh->b_data;
|
|
||||||
p = pm->pdEntry;
|
|
||||||
size = 42;
|
|
||||||
for (i = 0; i < size; p++, i++) {
|
|
||||||
if (p->pdStart && p->pdSize &&
|
|
||||||
p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
|
|
||||||
(sbi->part < 0 || sbi->part == i)) {
|
|
||||||
*part_start += be32_to_cpu(p->pdStart);
|
|
||||||
*part_size = be32_to_cpu(p->pdSize);
|
|
||||||
res = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HFS_NEW_PMAP_MAGIC:
|
|
||||||
{
|
|
||||||
struct new_pmap *pm;
|
|
||||||
|
|
||||||
pm = (struct new_pmap *)bh->b_data;
|
|
||||||
size = be32_to_cpu(pm->pmMapBlkCnt);
|
|
||||||
for (i = 0; i < size;) {
|
|
||||||
if (!memcmp(pm->pmPartType,"Apple_HFS", 9) &&
|
|
||||||
(sbi->part < 0 || sbi->part == i)) {
|
|
||||||
*part_start += be32_to_cpu(pm->pmPyPartStart);
|
|
||||||
*part_size = be32_to_cpu(pm->pmPartBlkCnt);
|
|
||||||
res = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
brelse(bh);
|
|
||||||
bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK + ++i, pm);
|
|
||||||
if (!bh)
|
|
||||||
return -EIO;
|
|
||||||
if (pm->pmSig != cpu_to_be16(HFS_NEW_PMAP_MAGIC))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
brelse(bh);
|
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm,
|
||||||
|
sector_t *part_start, sector_t *part_size)
|
||||||
|
{
|
||||||
|
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
|
||||||
|
int size = be32_to_cpu(pm->pmMapBlkCnt);
|
||||||
|
int res;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (!memcmp(pm->pmPartType, "Apple_HFS", 9) &&
|
||||||
|
(sbi->part < 0 || sbi->part == i)) {
|
||||||
|
*part_start += be32_to_cpu(pm->pmPyPartStart);
|
||||||
|
*part_size = be32_to_cpu(pm->pmPartBlkCnt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++i >= size)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
res = hfsplus_submit_bio(sb->s_bdev,
|
||||||
|
*part_start + HFS_PMAP_BLK + i,
|
||||||
|
pm, READ);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
} while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC));
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the partition map looking for the start and length of a
|
||||||
|
* HFS/HFS+ partition.
|
||||||
|
*/
|
||||||
|
int hfs_part_find(struct super_block *sb,
|
||||||
|
sector_t *part_start, sector_t *part_size)
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK,
|
||||||
|
data, READ);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
switch (be16_to_cpu(*((__be16 *)data))) {
|
||||||
|
case HFS_OLD_PMAP_MAGIC:
|
||||||
|
res = hfs_parse_old_pmap(sb, data, part_start, part_size);
|
||||||
|
break;
|
||||||
|
case HFS_NEW_PMAP_MAGIC:
|
||||||
|
res = hfs_parse_new_pmap(sb, data, part_start, part_size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = -ENOENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(data);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
|
#include <linux/blkdev.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/vfs.h>
|
#include <linux/vfs.h>
|
||||||
@ -66,6 +67,7 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
|
|||||||
INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
|
INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
|
||||||
mutex_init(&HFSPLUS_I(inode)->extents_lock);
|
mutex_init(&HFSPLUS_I(inode)->extents_lock);
|
||||||
HFSPLUS_I(inode)->flags = 0;
|
HFSPLUS_I(inode)->flags = 0;
|
||||||
|
HFSPLUS_I(inode)->extent_state = 0;
|
||||||
HFSPLUS_I(inode)->rsrc_inode = NULL;
|
HFSPLUS_I(inode)->rsrc_inode = NULL;
|
||||||
atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
|
atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
|
||||||
|
|
||||||
@ -157,45 +159,65 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
|
|||||||
{
|
{
|
||||||
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
|
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
|
||||||
struct hfsplus_vh *vhdr = sbi->s_vhdr;
|
struct hfsplus_vh *vhdr = sbi->s_vhdr;
|
||||||
|
int write_backup = 0;
|
||||||
|
int error, error2;
|
||||||
|
|
||||||
|
if (!wait)
|
||||||
|
return 0;
|
||||||
|
|
||||||
dprint(DBG_SUPER, "hfsplus_write_super\n");
|
dprint(DBG_SUPER, "hfsplus_write_super\n");
|
||||||
|
|
||||||
mutex_lock(&sbi->vh_mutex);
|
|
||||||
mutex_lock(&sbi->alloc_mutex);
|
|
||||||
sb->s_dirt = 0;
|
sb->s_dirt = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Explicitly write out the special metadata inodes.
|
||||||
|
*
|
||||||
|
* While these special inodes are marked as hashed and written
|
||||||
|
* out peridocically by the flusher threads we redirty them
|
||||||
|
* during writeout of normal inodes, and thus the life lock
|
||||||
|
* prevents us from getting the latest state to disk.
|
||||||
|
*/
|
||||||
|
error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
|
||||||
|
error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
|
||||||
|
if (!error)
|
||||||
|
error = error2;
|
||||||
|
error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
|
||||||
|
if (!error)
|
||||||
|
error = error2;
|
||||||
|
|
||||||
|
mutex_lock(&sbi->vh_mutex);
|
||||||
|
mutex_lock(&sbi->alloc_mutex);
|
||||||
vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
|
vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
|
||||||
vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
|
vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
|
||||||
vhdr->folder_count = cpu_to_be32(sbi->folder_count);
|
vhdr->folder_count = cpu_to_be32(sbi->folder_count);
|
||||||
vhdr->file_count = cpu_to_be32(sbi->file_count);
|
vhdr->file_count = cpu_to_be32(sbi->file_count);
|
||||||
|
|
||||||
mark_buffer_dirty(sbi->s_vhbh);
|
|
||||||
if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
|
if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
|
||||||
if (sbi->sect_count) {
|
memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr));
|
||||||
struct buffer_head *bh;
|
write_backup = 1;
|
||||||
u32 block, offset;
|
|
||||||
|
|
||||||
block = sbi->blockoffset;
|
|
||||||
block += (sbi->sect_count - 2) >> (sb->s_blocksize_bits - 9);
|
|
||||||
offset = ((sbi->sect_count - 2) << 9) & (sb->s_blocksize - 1);
|
|
||||||
printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n",
|
|
||||||
sbi->blockoffset, sbi->sect_count,
|
|
||||||
block, offset);
|
|
||||||
bh = sb_bread(sb, block);
|
|
||||||
if (bh) {
|
|
||||||
vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
|
|
||||||
if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) {
|
|
||||||
memcpy(vhdr, sbi->s_vhdr, sizeof(*vhdr));
|
|
||||||
mark_buffer_dirty(bh);
|
|
||||||
brelse(bh);
|
|
||||||
} else
|
|
||||||
printk(KERN_WARNING "hfs: backup not found!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error2 = hfsplus_submit_bio(sb->s_bdev,
|
||||||
|
sbi->part_start + HFSPLUS_VOLHEAD_SECTOR,
|
||||||
|
sbi->s_vhdr, WRITE_SYNC);
|
||||||
|
if (!error)
|
||||||
|
error = error2;
|
||||||
|
if (!write_backup)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
error2 = hfsplus_submit_bio(sb->s_bdev,
|
||||||
|
sbi->part_start + sbi->sect_count - 2,
|
||||||
|
sbi->s_backup_vhdr, WRITE_SYNC);
|
||||||
|
if (!error)
|
||||||
|
error2 = error;
|
||||||
|
out:
|
||||||
mutex_unlock(&sbi->alloc_mutex);
|
mutex_unlock(&sbi->alloc_mutex);
|
||||||
mutex_unlock(&sbi->vh_mutex);
|
mutex_unlock(&sbi->vh_mutex);
|
||||||
return 0;
|
|
||||||
|
if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
|
||||||
|
blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL);
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hfsplus_write_super(struct super_block *sb)
|
static void hfsplus_write_super(struct super_block *sb)
|
||||||
@ -215,23 +237,22 @@ static void hfsplus_put_super(struct super_block *sb)
|
|||||||
if (!sb->s_fs_info)
|
if (!sb->s_fs_info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sb->s_dirt)
|
|
||||||
hfsplus_write_super(sb);
|
|
||||||
if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
|
if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
|
||||||
struct hfsplus_vh *vhdr = sbi->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(sbi->s_vhbh);
|
|
||||||
sync_dirty_buffer(sbi->s_vhbh);
|
hfsplus_sync_fs(sb, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
hfs_btree_close(sbi->cat_tree);
|
hfs_btree_close(sbi->cat_tree);
|
||||||
hfs_btree_close(sbi->ext_tree);
|
hfs_btree_close(sbi->ext_tree);
|
||||||
iput(sbi->alloc_file);
|
iput(sbi->alloc_file);
|
||||||
iput(sbi->hidden_dir);
|
iput(sbi->hidden_dir);
|
||||||
brelse(sbi->s_vhbh);
|
kfree(sbi->s_vhdr);
|
||||||
|
kfree(sbi->s_backup_vhdr);
|
||||||
unload_nls(sbi->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;
|
||||||
@ -263,26 +284,31 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
|
|||||||
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;
|
int force = 0;
|
||||||
|
|
||||||
memset(&sbi, 0, sizeof(struct hfsplus_sb_info));
|
if (!hfsplus_parse_options_remount(data, &force))
|
||||||
sbi.nls = HFSPLUS_SB(sb)->nls;
|
|
||||||
if (!hfsplus_parse_options(data, &sbi))
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
|
if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
|
||||||
printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, "
|
printk(KERN_WARNING "hfs: filesystem was "
|
||||||
"running fsck.hfsplus is recommended. leaving read-only.\n");
|
"not cleanly unmounted, "
|
||||||
|
"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 (test_bit(HFSPLUS_SB_FORCE, &sbi.flags)) {
|
} else if (force) {
|
||||||
/* nothing */
|
/* nothing */
|
||||||
} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
|
} else if (vhdr->attributes &
|
||||||
printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n");
|
cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
|
||||||
|
printk(KERN_WARNING "hfs: filesystem is marked locked, "
|
||||||
|
"leaving read-only.\n");
|
||||||
sb->s_flags |= MS_RDONLY;
|
sb->s_flags |= MS_RDONLY;
|
||||||
*flags |= MS_RDONLY;
|
*flags |= MS_RDONLY;
|
||||||
} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
|
} else if (vhdr->attributes &
|
||||||
printk(KERN_WARNING "hfs: filesystem is marked journaled, leaving read-only.\n");
|
cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
|
||||||
|
printk(KERN_WARNING "hfs: filesystem is "
|
||||||
|
"marked journaled, "
|
||||||
|
"leaving read-only.\n");
|
||||||
sb->s_flags |= MS_RDONLY;
|
sb->s_flags |= MS_RDONLY;
|
||||||
*flags |= MS_RDONLY;
|
*flags |= MS_RDONLY;
|
||||||
}
|
}
|
||||||
@ -372,17 +398,22 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||||
|
|
||||||
if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
|
if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
|
||||||
printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, "
|
printk(KERN_WARNING "hfs: Filesystem was "
|
||||||
"running fsck.hfsplus is recommended. mounting read-only.\n");
|
"not cleanly unmounted, "
|
||||||
|
"running fsck.hfsplus is recommended. "
|
||||||
|
"mounting read-only.\n");
|
||||||
sb->s_flags |= MS_RDONLY;
|
sb->s_flags |= MS_RDONLY;
|
||||||
} else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
|
} 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");
|
||||||
sb->s_flags |= MS_RDONLY;
|
sb->s_flags |= MS_RDONLY;
|
||||||
} else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) && !(sb->s_flags & MS_RDONLY)) {
|
} else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) &&
|
||||||
printk(KERN_WARNING "hfs: write access to a journaled filesystem is not supported, "
|
!(sb->s_flags & MS_RDONLY)) {
|
||||||
"use the force option at your own risk, mounting read-only.\n");
|
printk(KERN_WARNING "hfs: write access to "
|
||||||
|
"a journaled filesystem is not supported, "
|
||||||
|
"use the force option at your own risk, "
|
||||||
|
"mounting read-only.\n");
|
||||||
sb->s_flags |= MS_RDONLY;
|
sb->s_flags |= MS_RDONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,19 +480,16 @@ 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(sbi->s_vhbh);
|
hfsplus_sync_fs(sb, 1);
|
||||||
sync_dirty_buffer(sbi->s_vhbh);
|
|
||||||
|
|
||||||
if (!sbi->hidden_dir) {
|
if (!sbi->hidden_dir) {
|
||||||
printk(KERN_DEBUG "hfs: create hidden dir...\n");
|
|
||||||
|
|
||||||
mutex_lock(&sbi->vh_mutex);
|
mutex_lock(&sbi->vh_mutex);
|
||||||
sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
|
sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
|
||||||
hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode,
|
hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode,
|
||||||
&str, sbi->hidden_dir);
|
&str, sbi->hidden_dir);
|
||||||
mutex_unlock(&sbi->vh_mutex);
|
mutex_unlock(&sbi->vh_mutex);
|
||||||
|
|
||||||
mark_inode_dirty(sbi->hidden_dir);
|
hfsplus_mark_inode_dirty(sbi->hidden_dir, HFSPLUS_I_CAT_DIRTY);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
unload_nls(sbi->nls);
|
unload_nls(sbi->nls);
|
||||||
|
@ -17,14 +17,14 @@
|
|||||||
/* Returns folded char, or 0 if ignorable */
|
/* Returns folded char, or 0 if ignorable */
|
||||||
static inline u16 case_fold(u16 c)
|
static inline u16 case_fold(u16 c)
|
||||||
{
|
{
|
||||||
u16 tmp;
|
u16 tmp;
|
||||||
|
|
||||||
tmp = hfsplus_case_fold_table[c >> 8];
|
tmp = hfsplus_case_fold_table[c >> 8];
|
||||||
if (tmp)
|
if (tmp)
|
||||||
tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
|
tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
|
||||||
else
|
else
|
||||||
tmp = c;
|
tmp = c;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compare unicode strings, return values like normal strcmp */
|
/* Compare unicode strings, return values like normal strcmp */
|
||||||
@ -118,7 +118,9 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@ -171,7 +173,8 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
|
|||||||
goto same;
|
goto same;
|
||||||
c1 = be16_to_cpu(*ip);
|
c1 = be16_to_cpu(*ip);
|
||||||
if (likely(compose))
|
if (likely(compose))
|
||||||
ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c1);
|
ce1 = hfsplus_compose_lookup(
|
||||||
|
hfsplus_compose_table, c1);
|
||||||
if (ce1)
|
if (ce1)
|
||||||
break;
|
break;
|
||||||
switch (c0) {
|
switch (c0) {
|
||||||
@ -199,7 +202,8 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
|
|||||||
if (ce2) {
|
if (ce2) {
|
||||||
i = 1;
|
i = 1;
|
||||||
while (i < ustrlen) {
|
while (i < ustrlen) {
|
||||||
ce1 = hfsplus_compose_lookup(ce2, be16_to_cpu(ip[i]));
|
ce1 = hfsplus_compose_lookup(ce2,
|
||||||
|
be16_to_cpu(ip[i]));
|
||||||
if (!ce1)
|
if (!ce1)
|
||||||
break;
|
break;
|
||||||
i++;
|
i++;
|
||||||
@ -211,7 +215,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
same:
|
same:
|
||||||
switch (c0) {
|
switch (c0) {
|
||||||
case 0:
|
case 0:
|
||||||
cc = 0x2400;
|
cc = 0x2400;
|
||||||
@ -222,7 +226,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
|
|||||||
default:
|
default:
|
||||||
cc = c0;
|
cc = c0;
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
res = nls->uni2char(cc, op, len);
|
res = nls->uni2char(cc, op, len);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
if (res == -ENAMETOOLONG)
|
if (res == -ENAMETOOLONG)
|
||||||
@ -392,7 +396,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
|
|||||||
astr1 += size;
|
astr1 += size;
|
||||||
len1 -= size;
|
len1 -= size;
|
||||||
|
|
||||||
if (!decompose || !(dstr1 = decompose_unichar(c, &dsize1))) {
|
if (decompose)
|
||||||
|
dstr1 = decompose_unichar(c, &dsize1);
|
||||||
|
if (!decompose || !dstr1) {
|
||||||
c1 = c;
|
c1 = c;
|
||||||
dstr1 = &c1;
|
dstr1 = &c1;
|
||||||
dsize1 = 1;
|
dsize1 = 1;
|
||||||
@ -404,7 +410,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
|
|||||||
astr2 += size;
|
astr2 += size;
|
||||||
len2 -= size;
|
len2 -= size;
|
||||||
|
|
||||||
if (!decompose || !(dstr2 = decompose_unichar(c, &dsize2))) {
|
if (decompose)
|
||||||
|
dstr2 = decompose_unichar(c, &dsize2);
|
||||||
|
if (!decompose || !dstr2) {
|
||||||
c2 = c;
|
c2 = c;
|
||||||
dstr2 = &c2;
|
dstr2 = &c2;
|
||||||
dsize2 = 1;
|
dsize2 = 1;
|
||||||
|
@ -24,6 +24,40 @@ struct hfsplus_wd {
|
|||||||
u16 embed_count;
|
u16 embed_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void hfsplus_end_io_sync(struct bio *bio, int err)
|
||||||
|
{
|
||||||
|
if (err)
|
||||||
|
clear_bit(BIO_UPTODATE, &bio->bi_flags);
|
||||||
|
complete(bio->bi_private);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
|
||||||
|
void *data, int rw)
|
||||||
|
{
|
||||||
|
DECLARE_COMPLETION_ONSTACK(wait);
|
||||||
|
struct bio *bio;
|
||||||
|
|
||||||
|
bio = bio_alloc(GFP_NOIO, 1);
|
||||||
|
bio->bi_sector = sector;
|
||||||
|
bio->bi_bdev = bdev;
|
||||||
|
bio->bi_end_io = hfsplus_end_io_sync;
|
||||||
|
bio->bi_private = &wait;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We always submit one sector at a time, so bio_add_page must not fail.
|
||||||
|
*/
|
||||||
|
if (bio_add_page(bio, virt_to_page(data), HFSPLUS_SECTOR_SIZE,
|
||||||
|
offset_in_page(data)) != HFSPLUS_SECTOR_SIZE)
|
||||||
|
BUG();
|
||||||
|
|
||||||
|
submit_bio(rw, bio);
|
||||||
|
wait_for_completion(&wait);
|
||||||
|
|
||||||
|
if (!bio_flagged(bio, BIO_UPTODATE))
|
||||||
|
return -EIO;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
|
static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
|
||||||
{
|
{
|
||||||
u32 extent;
|
u32 extent;
|
||||||
@ -40,12 +74,14 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
|
|||||||
!(attrib & HFSP_WRAP_ATTRIB_SPARED))
|
!(attrib & HFSP_WRAP_ATTRIB_SPARED))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
wd->ablk_size = be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE));
|
wd->ablk_size =
|
||||||
|
be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE));
|
||||||
if (wd->ablk_size < HFSPLUS_SECTOR_SIZE)
|
if (wd->ablk_size < HFSPLUS_SECTOR_SIZE)
|
||||||
return 0;
|
return 0;
|
||||||
if (wd->ablk_size % HFSPLUS_SECTOR_SIZE)
|
if (wd->ablk_size % HFSPLUS_SECTOR_SIZE)
|
||||||
return 0;
|
return 0;
|
||||||
wd->ablk_start = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
|
wd->ablk_start =
|
||||||
|
be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
|
||||||
|
|
||||||
extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT);
|
extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT);
|
||||||
wd->embed_start = (extent >> 16) & 0xFFFF;
|
wd->embed_start = (extent >> 16) & 0xFFFF;
|
||||||
@ -68,7 +104,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
|
|||||||
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) {
|
||||||
*start = (sector_t)te.cdte_addr.lba << 2;
|
*start = (sector_t)te.cdte_addr.lba << 2;
|
||||||
return 0;
|
return 0;
|
||||||
@ -77,7 +114,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
ms_info.addr_format = CDROM_LBA;
|
ms_info.addr_format = CDROM_LBA;
|
||||||
res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION, (unsigned long)&ms_info);
|
res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION,
|
||||||
|
(unsigned long)&ms_info);
|
||||||
if (!res && ms_info.xa_flag)
|
if (!res && ms_info.xa_flag)
|
||||||
*start = (sector_t)ms_info.addr.lba << 2;
|
*start = (sector_t)ms_info.addr.lba << 2;
|
||||||
return 0;
|
return 0;
|
||||||
@ -88,100 +126,112 @@ static int hfsplus_get_last_session(struct super_block *sb,
|
|||||||
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 hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
|
||||||
struct buffer_head *bh;
|
|
||||||
struct hfsplus_vh *vhdr;
|
|
||||||
struct hfsplus_wd wd;
|
struct hfsplus_wd wd;
|
||||||
sector_t part_start, part_size;
|
sector_t part_start, part_size;
|
||||||
u32 blocksize;
|
u32 blocksize;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
error = -EINVAL;
|
||||||
blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE);
|
blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE);
|
||||||
if (!blocksize)
|
if (!blocksize)
|
||||||
return -EINVAL;
|
goto out;
|
||||||
|
|
||||||
if (hfsplus_get_last_session(sb, &part_start, &part_size))
|
if (hfsplus_get_last_session(sb, &part_start, &part_size))
|
||||||
return -EINVAL;
|
goto out;
|
||||||
if ((u64)part_start + part_size > 0x100000000ULL) {
|
if ((u64)part_start + part_size > 0x100000000ULL) {
|
||||||
pr_err("hfs: volumes larger than 2TB are not supported yet\n");
|
pr_err("hfs: volumes larger than 2TB are not supported yet\n");
|
||||||
return -EINVAL;
|
goto out;
|
||||||
}
|
}
|
||||||
while (1) {
|
|
||||||
bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
|
|
||||||
if (!bh)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
if (vhdr->signature == cpu_to_be16(HFSP_WRAP_MAGIC)) {
|
error = -ENOMEM;
|
||||||
if (!hfsplus_read_mdb(vhdr, &wd))
|
sbi->s_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
|
||||||
goto error;
|
if (!sbi->s_vhdr)
|
||||||
wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
|
goto out;
|
||||||
part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
|
sbi->s_backup_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
|
||||||
part_size = wd.embed_count * wd.ablk_size;
|
if (!sbi->s_backup_vhdr)
|
||||||
brelse(bh);
|
goto out_free_vhdr;
|
||||||
bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
|
|
||||||
if (!bh)
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
|
|
||||||
break;
|
|
||||||
if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) {
|
|
||||||
set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
brelse(bh);
|
|
||||||
|
|
||||||
/* check for a partition block
|
reread:
|
||||||
|
error = hfsplus_submit_bio(sb->s_bdev,
|
||||||
|
part_start + HFSPLUS_VOLHEAD_SECTOR,
|
||||||
|
sbi->s_vhdr, READ);
|
||||||
|
if (error)
|
||||||
|
goto out_free_backup_vhdr;
|
||||||
|
|
||||||
|
error = -EINVAL;
|
||||||
|
switch (sbi->s_vhdr->signature) {
|
||||||
|
case cpu_to_be16(HFSPLUS_VOLHEAD_SIGX):
|
||||||
|
set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
|
||||||
|
/*FALLTHRU*/
|
||||||
|
case cpu_to_be16(HFSPLUS_VOLHEAD_SIG):
|
||||||
|
break;
|
||||||
|
case cpu_to_be16(HFSP_WRAP_MAGIC):
|
||||||
|
if (!hfsplus_read_mdb(sbi->s_vhdr, &wd))
|
||||||
|
goto out;
|
||||||
|
wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
|
||||||
|
part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
|
||||||
|
part_size = wd.embed_count * wd.ablk_size;
|
||||||
|
goto reread;
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* Check for a partition block.
|
||||||
|
*
|
||||||
* (should do this only for cdrom/loop though)
|
* (should do this only for cdrom/loop though)
|
||||||
*/
|
*/
|
||||||
if (hfs_part_find(sb, &part_start, &part_size))
|
if (hfs_part_find(sb, &part_start, &part_size))
|
||||||
return -EINVAL;
|
goto out;
|
||||||
|
goto reread;
|
||||||
}
|
}
|
||||||
|
|
||||||
blocksize = be32_to_cpu(vhdr->blocksize);
|
error = hfsplus_submit_bio(sb->s_bdev,
|
||||||
brelse(bh);
|
part_start + part_size - 2,
|
||||||
|
sbi->s_backup_vhdr, READ);
|
||||||
|
if (error)
|
||||||
|
goto out_free_backup_vhdr;
|
||||||
|
|
||||||
/* block size must be at least as large as a sector
|
error = -EINVAL;
|
||||||
* and a multiple of 2
|
if (sbi->s_backup_vhdr->signature != sbi->s_vhdr->signature) {
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"hfs: invalid secondary volume header\n");
|
||||||
|
goto out_free_backup_vhdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
blocksize = be32_to_cpu(sbi->s_vhdr->blocksize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Block size must be at least as large as a sector and a multiple of 2.
|
||||||
*/
|
*/
|
||||||
if (blocksize < HFSPLUS_SECTOR_SIZE ||
|
if (blocksize < HFSPLUS_SECTOR_SIZE || ((blocksize - 1) & blocksize))
|
||||||
((blocksize - 1) & blocksize))
|
goto out_free_backup_vhdr;
|
||||||
return -EINVAL;
|
|
||||||
sbi->alloc_blksz = blocksize;
|
sbi->alloc_blksz = blocksize;
|
||||||
sbi->alloc_blksz_shift = 0;
|
sbi->alloc_blksz_shift = 0;
|
||||||
while ((blocksize >>= 1) != 0)
|
while ((blocksize >>= 1) != 0)
|
||||||
sbi->alloc_blksz_shift++;
|
sbi->alloc_blksz_shift++;
|
||||||
blocksize = min(sbi->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))
|
||||||
blocksize >>= 1;
|
blocksize >>= 1;
|
||||||
|
|
||||||
if (sb_set_blocksize(sb, blocksize) != blocksize) {
|
if (sb_set_blocksize(sb, blocksize) != blocksize) {
|
||||||
printk(KERN_ERR "hfs: unable to set blocksize to %u!\n", blocksize);
|
printk(KERN_ERR "hfs: unable to set blocksize to %u!\n",
|
||||||
return -EINVAL;
|
blocksize);
|
||||||
|
goto out_free_backup_vhdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
sbi->blockoffset =
|
sbi->blockoffset =
|
||||||
part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT);
|
part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT);
|
||||||
|
sbi->part_start = part_start;
|
||||||
sbi->sect_count = part_size;
|
sbi->sect_count = part_size;
|
||||||
sbi->fs_shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
|
sbi->fs_shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
|
||||||
|
|
||||||
bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
|
|
||||||
if (!bh)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
/* should still be the same... */
|
|
||||||
if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
|
|
||||||
if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX))
|
|
||||||
goto error;
|
|
||||||
} else {
|
|
||||||
if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
sbi->s_vhbh = bh;
|
|
||||||
sbi->s_vhdr = vhdr;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
|
||||||
brelse(bh);
|
out_free_backup_vhdr:
|
||||||
return -EINVAL;
|
kfree(sbi->s_backup_vhdr);
|
||||||
|
out_free_vhdr:
|
||||||
|
kfree(sbi->s_vhdr);
|
||||||
|
out:
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user