diff options
Diffstat (limited to 'fs/hfsplus')
-rw-r--r-- | fs/hfsplus/bfind.c | 3 | ||||
-rw-r--r-- | fs/hfsplus/bitmap.c | 8 | ||||
-rw-r--r-- | fs/hfsplus/bnode.c | 11 | ||||
-rw-r--r-- | fs/hfsplus/brec.c | 2 | ||||
-rw-r--r-- | fs/hfsplus/btree.c | 37 | ||||
-rw-r--r-- | fs/hfsplus/catalog.c | 44 | ||||
-rw-r--r-- | fs/hfsplus/dir.c | 47 | ||||
-rw-r--r-- | fs/hfsplus/extents.c | 6 | ||||
-rw-r--r-- | fs/hfsplus/hfsplus_fs.h | 15 | ||||
-rw-r--r-- | fs/hfsplus/hfsplus_raw.h | 13 | ||||
-rw-r--r-- | fs/hfsplus/inode.c | 25 | ||||
-rw-r--r-- | fs/hfsplus/ioctl.c | 1 | ||||
-rw-r--r-- | fs/hfsplus/options.c | 18 | ||||
-rw-r--r-- | fs/hfsplus/super.c | 75 | ||||
-rw-r--r-- | fs/hfsplus/unicode.c | 30 | ||||
-rw-r--r-- | fs/hfsplus/wrapper.c | 17 |
16 files changed, 199 insertions, 153 deletions
diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c index 257cdde0514..5007a41f1be 100644 --- a/fs/hfsplus/bfind.c +++ b/fs/hfsplus/bfind.c @@ -64,7 +64,6 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) else e = rec - 1; } while (b <= e); - //printk("%d: %d,%d,%d\n", bnode->this, b, e, rec); if (rec != e && e >= 0) { len = hfs_brec_lenoff(bnode, e, &off); keylen = hfs_brec_keylen(bnode, e); @@ -127,7 +126,7 @@ int hfs_brec_find(struct hfs_find_data *fd) return res; invalid: - printk("HFS+-fs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n", + printk(KERN_ERR "hfs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n", height, bnode->height, bnode->type, nidx, parent); res = -EIO; release: diff --git a/fs/hfsplus/bitmap.c b/fs/hfsplus/bitmap.c index c7d316455fa..9fb51632303 100644 --- a/fs/hfsplus/bitmap.c +++ b/fs/hfsplus/bitmap.c @@ -29,7 +29,7 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma return size; dprint(DBG_BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len); - down(&HFSPLUS_SB(sb).alloc_file->i_sem); + mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex); mapping = HFSPLUS_SB(sb).alloc_file->i_mapping; page = read_cache_page(mapping, offset / PAGE_CACHE_BITS, (filler_t *)mapping->a_ops->readpage, NULL); @@ -143,7 +143,7 @@ done: sb->s_dirt = 1; dprint(DBG_BITMAP, "-> %u,%u\n", start, *max); out: - up(&HFSPLUS_SB(sb).alloc_file->i_sem); + mutex_unlock(&HFSPLUS_SB(sb).alloc_file->i_mutex); return start; } @@ -164,7 +164,7 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count) if ((offset + count) > HFSPLUS_SB(sb).total_blocks) return -2; - down(&HFSPLUS_SB(sb).alloc_file->i_sem); + mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex); mapping = HFSPLUS_SB(sb).alloc_file->i_mapping; pnr = offset / PAGE_CACHE_BITS; page = read_cache_page(mapping, pnr, (filler_t *)mapping->a_ops->readpage, NULL); @@ -215,7 +215,7 @@ out: kunmap(page); HFSPLUS_SB(sb).free_blocks += len; sb->s_dirt = 1; - up(&HFSPLUS_SB(sb).alloc_file->i_sem); + mutex_unlock(&HFSPLUS_SB(sb).alloc_file->i_mutex); return 0; } diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 930cd9212de..8f07e8fbd03 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c @@ -358,7 +358,7 @@ void hfs_bnode_unlink(struct hfs_bnode *node) // move down? if (!node->prev && !node->next) { - printk("hfs_btree_del_level\n"); + printk(KERN_DEBUG "hfs_btree_del_level\n"); } if (!node->parent) { tree->root = 0; @@ -379,7 +379,7 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid) struct hfs_bnode *node; if (cnid >= tree->node_count) { - printk("HFS+-fs: 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; } @@ -402,7 +402,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) loff_t off; if (cnid >= tree->node_count) { - printk("HFS+-fs: 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; } @@ -576,8 +576,9 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) node = hfs_bnode_findhash(tree, num); spin_unlock(&tree->hash_lock); if (node) { - printk("new node %u already hashed?\n", num); - BUG(); + printk(KERN_CRIT "new node %u already hashed?\n", num); + WARN_ON(1); + return node; } node = __hfs_bnode_create(tree, num); if (!node) diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c index 0ccef2ab790..c88e5d72a40 100644 --- a/fs/hfsplus/brec.c +++ b/fs/hfsplus/brec.c @@ -360,7 +360,7 @@ again: end_off = hfs_bnode_read_u16(parent, end_rec_off); if (end_rec_off - end_off < diff) { - printk("splitting index node...\n"); + printk(KERN_DEBUG "hfs: splitting index node...\n"); fd->bnode = parent; new_node = hfs_bnode_split(fd); if (IS_ERR(new_node)) diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 44326aa2bd3..a67edfa34e9 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c @@ -31,17 +31,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) init_MUTEX(&tree->tree_lock); spin_lock_init(&tree->hash_lock); - /* Set the correct compare function */ tree->sb = sb; tree->cnid = id; - if (id == HFSPLUS_EXT_CNID) { - tree->keycmp = hfsplus_ext_cmp_key; - } else if (id == HFSPLUS_CAT_CNID) { - tree->keycmp = hfsplus_cat_cmp_key; - } else { - printk("HFS+-fs: unknown B*Tree requested\n"); - goto free_tree; - } tree->inode = iget(sb, id); if (!tree->inode) goto free_tree; @@ -64,6 +55,20 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) tree->max_key_len = be16_to_cpu(head->max_key_len); tree->depth = be16_to_cpu(head->depth); + /* Set the correct compare function */ + if (id == HFSPLUS_EXT_CNID) { + tree->keycmp = hfsplus_ext_cmp_key; + } else if (id == HFSPLUS_CAT_CNID) { + if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && + (head->key_type == HFSPLUS_KEY_BINARY)) + tree->keycmp = hfsplus_cat_bin_cmp_key; + else + tree->keycmp = hfsplus_cat_case_cmp_key; + } else { + printk(KERN_ERR "hfs: unknown B*Tree requested\n"); + goto fail_page; + } + size = tree->node_size; if (!size || size & (size - 1)) goto fail_page; @@ -99,7 +104,7 @@ void hfs_btree_close(struct hfs_btree *tree) while ((node = tree->node_hash[i])) { tree->node_hash[i] = node->next_hash; if (atomic_read(&node->refcnt)) - printk("HFS+: node %d:%d still has %d user(s)!\n", + printk(KERN_CRIT "hfs: node %d:%d still has %d user(s)!\n", node->tree->cnid, node->this, atomic_read(&node->refcnt)); hfs_bnode_free(node); tree->node_hash_cnt--; @@ -223,10 +228,6 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) tree->free_nodes--; mark_inode_dirty(tree->inode); hfs_bnode_put(node); - if (!idx) { - printk("unexpected idx %u (%u)\n", idx, node->this); - BUG(); - } return hfs_bnode_create(tree, idx); } } @@ -242,7 +243,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) kunmap(*pagep); nidx = node->next; if (!nidx) { - printk("create new bmap node...\n"); + printk(KERN_DEBUG "hfs: create new bmap node...\n"); next_node = hfs_bmap_new_bmap(node, idx); } else next_node = hfs_bnode_find(tree, nidx); @@ -284,7 +285,7 @@ void hfs_bmap_free(struct hfs_bnode *node) hfs_bnode_put(node); if (!i) { /* panic */; - printk("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; } node = hfs_bnode_find(tree, i); @@ -292,7 +293,7 @@ void hfs_bmap_free(struct hfs_bnode *node) return; if (node->type != HFS_NODE_MAP) { /* panic */; - printk("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); return; } @@ -305,7 +306,7 @@ void hfs_bmap_free(struct hfs_bnode *node) m = 1 << (~nidx & 7); byte = data[off]; if (!(byte & m)) { - printk("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); hfs_bnode_put(node); return; diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 94712790c8b..f2d7c49ce75 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c @@ -13,7 +13,8 @@ #include "hfsplus_fs.h" #include "hfsplus_raw.h" -int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) +int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1, + const hfsplus_btree_key *k2) { __be32 k1p, k2p; @@ -22,7 +23,20 @@ int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) if (k1p != k2p) return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; - return hfsplus_unistrcmp(&k1->cat.name, &k2->cat.name); + return hfsplus_strcasecmp(&k1->cat.name, &k2->cat.name); +} + +int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, + const hfsplus_btree_key *k2) +{ + __be32 k1p, k2p; + + k1p = k1->cat.parent; + k2p = k2->cat.parent; + if (k1p != k2p) + return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; + + return hfsplus_strcmp(&k1->cat.name, &k2->cat.name); } void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, @@ -80,8 +94,11 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i memset(folder, 0, sizeof(*folder)); folder->type = cpu_to_be16(HFSPLUS_FOLDER); folder->id = cpu_to_be32(inode->i_ino); - folder->create_date = folder->content_mod_date = - folder->attribute_mod_date = folder->access_date = hfsp_now2mt(); + HFSPLUS_I(inode).create_date = + folder->create_date = + folder->content_mod_date = + folder->attribute_mod_date = + folder->access_date = hfsp_now2mt(); hfsplus_set_perms(inode, &folder->permissions); if (inode == HFSPLUS_SB(inode->i_sb).hidden_dir) /* invisible and namelocked */ @@ -95,18 +112,27 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i file->type = cpu_to_be16(HFSPLUS_FILE); file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS); file->id = cpu_to_be32(cnid); - file->create_date = file->content_mod_date = - file->attribute_mod_date = file->access_date = hfsp_now2mt(); + HFSPLUS_I(inode).create_date = + file->create_date = + file->content_mod_date = + file->attribute_mod_date = + file->access_date = hfsp_now2mt(); if (cnid == inode->i_ino) { hfsplus_set_perms(inode, &file->permissions); - file->user_info.fdType = cpu_to_be32(HFSPLUS_SB(inode->i_sb).type); - file->user_info.fdCreator = cpu_to_be32(HFSPLUS_SB(inode->i_sb).creator); + if (S_ISLNK(inode->i_mode)) { + file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE); + file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR); + } else { + file->user_info.fdType = cpu_to_be32(HFSPLUS_SB(inode->i_sb).type); + file->user_info.fdCreator = cpu_to_be32(HFSPLUS_SB(inode->i_sb).creator); + } if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); } else { file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE); file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR); file->user_info.fdFlags = cpu_to_be16(0x100); + file->create_date = HFSPLUS_I(HFSPLUS_SB(inode->i_sb).hidden_dir).create_date; file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode).dev); } return sizeof(*file); @@ -139,7 +165,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid, type = be16_to_cpu(tmp.type); if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) { - printk("HFS+-fs: Found bad thread record in catalog\n"); + printk(KERN_ERR "hfs: found bad thread record in catalog\n"); return -EIO; } diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 50c8f44b6c6..01a6fe3a395 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -66,25 +66,32 @@ again: } cnid = be32_to_cpu(entry.file.id); if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) && - entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR)) { + entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) && + (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb).hidden_dir).create_date || + entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode).create_date) && + HFSPLUS_SB(sb).hidden_dir) { struct qstr str; char name[32]; if (dentry->d_fsdata) { - err = -ENOENT; - inode = NULL; - goto out; + /* + * We found a link pointing to another link, + * so ignore it and treat it as regular file. + */ + cnid = (unsigned long)dentry->d_fsdata; + linkid = 0; + } else { + dentry->d_fsdata = (void *)(unsigned long)cnid; + linkid = be32_to_cpu(entry.file.permissions.dev); + str.len = sprintf(name, "iNode%d", linkid); + str.name = name; + hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str); + goto again; } - dentry->d_fsdata = (void *)(unsigned long)cnid; - linkid = be32_to_cpu(entry.file.permissions.dev); - str.len = sprintf(name, "iNode%d", linkid); - str.name = name; - hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str); - goto again; } else if (!dentry->d_fsdata) dentry->d_fsdata = (void *)(unsigned long)cnid; } else { - printk("HFS+-fs: Illegal catalog entry type in lookup\n"); + printk(KERN_ERR "hfs: invalid catalog entry type in lookup\n"); err = -EIO; goto fail; } @@ -132,12 +139,12 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) case 1: hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) { - printk("HFS+-fs: bad catalog folder thread\n"); + printk(KERN_ERR "hfs: bad catalog folder thread\n"); err = -EIO; goto out; } if (fd.entrylength < HFSPLUS_MIN_THREAD_SZ) { - printk("HFS+-fs: truncated catalog thread\n"); + printk(KERN_ERR "hfs: truncated catalog thread\n"); err = -EIO; goto out; } @@ -156,7 +163,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) for (;;) { if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) { - printk("HFS+-fs: walked past end of dir\n"); + printk(KERN_ERR "hfs: walked past end of dir\n"); err = -EIO; goto out; } @@ -168,7 +175,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) goto out; if (type == HFSPLUS_FOLDER) { if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) { - printk("HFS+-fs: small dir entry\n"); + printk(KERN_ERR "hfs: small dir entry\n"); err = -EIO; goto out; } @@ -180,7 +187,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) break; } else if (type == HFSPLUS_FILE) { if (fd.entrylength < sizeof(struct hfsplus_cat_file)) { - printk("HFS+-fs: small file entry\n"); + printk(KERN_ERR "hfs: small file entry\n"); err = -EIO; goto out; } @@ -188,7 +195,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) be32_to_cpu(entry.file.id), DT_REG)) break; } else { - printk("HFS+-fs: bad catalog entry type\n"); + printk(KERN_ERR "hfs: bad catalog entry type\n"); err = -EIO; goto out; } @@ -330,7 +337,8 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) if (res) return res; - inode->i_nlink--; + if (inode->i_nlink > 0) + inode->i_nlink--; hfsplus_delete_inode(inode); if (inode->i_ino != cnid && !inode->i_nlink) { if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { @@ -339,7 +347,8 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) hfsplus_delete_inode(inode); } else inode->i_flags |= S_DEAD; - } + } else + inode->i_nlink = 0; inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index e3ff56a0301..1a7480089e8 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c @@ -16,7 +16,8 @@ #include "hfsplus_raw.h" /* Compare two extents keys, returns 0 on same, pos/neg for difference */ -int hfsplus_ext_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) +int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, + const hfsplus_btree_key *k2) { __be32 k1id, k2id; __be32 k1s, k2s; @@ -349,10 +350,9 @@ int hfsplus_file_extend(struct inode *inode) if (HFSPLUS_SB(sb).alloc_file->i_size * 8 < HFSPLUS_SB(sb).total_blocks - HFSPLUS_SB(sb).free_blocks + 8) { // extend alloc file - printk("extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8, + printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8, HFSPLUS_SB(sb).total_blocks, HFSPLUS_SB(sb).free_blocks); return -ENOSPC; - //BUG(); } down(&HFSPLUS_I(inode).extents_lock); diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index df16fcbff3f..7ae393637a0 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -36,7 +36,7 @@ #define HFSPLUS_TYPE_DATA 0x00 #define HFSPLUS_TYPE_RSRC 0xFF -typedef int (*btree_keycmp)(hfsplus_btree_key *, hfsplus_btree_key *); +typedef int (*btree_keycmp)(const hfsplus_btree_key *, const hfsplus_btree_key *); #define NODE_HASH_SIZE 256 @@ -143,15 +143,13 @@ struct hfsplus_sb_info { unsigned long flags; - atomic_t inode_cnt; - u32 last_inode_cnt; - struct hlist_head rsrc_inodes; }; #define HFSPLUS_SB_WRITEBACKUP 0x0001 #define HFSPLUS_SB_NODECOMPOSE 0x0002 #define HFSPLUS_SB_FORCE 0x0004 +#define HFSPLUS_SB_HFSX 0x0008 struct hfsplus_inode_info { @@ -168,6 +166,7 @@ struct hfsplus_inode_info { struct inode *rsrc_inode; unsigned long flags; + __be32 create_date; /* Device number in hfsplus_permissions in catalog */ u32 dev; /* BSD system and user file flags */ @@ -306,7 +305,8 @@ int hfs_brec_read(struct hfs_find_data *, void *, int); int hfs_brec_goto(struct hfs_find_data *, int); /* catalog.c */ -int hfsplus_cat_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *); +int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); +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_create_cat(u32, struct inode *, struct qstr *, struct inode *); @@ -315,7 +315,7 @@ int hfsplus_rename_cat(u32, struct inode *, struct qstr *, struct inode *, struct qstr *); /* extents.c */ -int hfsplus_ext_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *); +int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); void hfsplus_ext_write_extent(struct inode *); 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); @@ -353,7 +353,8 @@ extern u16 hfsplus_decompose_table[]; extern u16 hfsplus_compose_table[]; /* unicode.c */ -int hfsplus_unistrcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); +int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); +int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index b4fbed63321..49205531a50 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h @@ -22,8 +22,10 @@ #define HFSPLUS_SECTOR_SHIFT 9 #define HFSPLUS_VOLHEAD_SECTOR 2 #define HFSPLUS_VOLHEAD_SIG 0x482b +#define HFSPLUS_VOLHEAD_SIGX 0x4858 #define HFSPLUS_SUPER_MAGIC 0x482b -#define HFSPLUS_CURRENT_VERSION 4 +#define HFSPLUS_MIN_VERSION 4 +#define HFSPLUS_CURRENT_VERSION 5 #define HFSP_WRAP_MAGIC 0x4244 #define HFSP_WRAP_ATTRIB_SLOCK 0x8000 @@ -41,6 +43,9 @@ #define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */ #define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */ +#define HFSP_SYMLINK_TYPE 0x736c6e6b /* 'slnk' */ +#define HFSP_SYMLINK_CREATOR 0x72686170 /* 'rhap' */ + #define HFSP_MOUNT_VERSION 0x482b4c78 /* 'H+Lx' */ /* Structures used on disk */ @@ -161,7 +166,7 @@ struct hfs_btree_header_rec { u16 reserved1; __be32 clump_size; u8 btree_type; - u8 reserved2; + u8 key_type; __be32 attributes; u32 reserved3[16]; } __packed; @@ -186,6 +191,10 @@ struct hfs_btree_header_rec { #define HFSPLUS_EXCH_CNID 15 /* ExchangeFiles temp id */ #define HFSPLUS_FIRSTUSER_CNID 16 /* first available user id */ +/* btree key type */ +#define HFSPLUS_KEY_CASEFOLDING 0xCF /* case-insensitive */ +#define HFSPLUS_KEY_BINARY 0xBC /* case-sensitive */ + /* HFS+ catalog entry key */ struct hfsplus_cat_key { __be16 key_len; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index fc98583cf04..12ed2b7d046 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -18,13 +18,11 @@ static int hfsplus_readpage(struct file *file, struct page *page) { - //printk("readpage: %lu\n", page->index); return block_read_full_page(page, hfsplus_get_block); } static int hfsplus_writepage(struct page *page, struct writeback_control *wbc) { - //printk("writepage: %lu\n", page->index); return block_write_full_page(page, hfsplus_get_block, wbc); } @@ -92,7 +90,6 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) } while (--i && nidx < tree->node_count); spin_unlock(&tree->hash_lock); } - //printk("releasepage: %lu,%x = %d\n", page->index, mask, res); return res ? try_to_free_buffers(page) : 0; } @@ -182,11 +179,6 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent igrab(dir); hlist_add_head(&inode->i_hash, &HFSPLUS_SB(sb).rsrc_inodes); mark_inode_dirty(inode); - { - void hfsplus_inode_check(struct super_block *sb); - atomic_inc(&HFSPLUS_SB(sb).inode_cnt); - hfsplus_inode_check(sb); - } out: d_add(dentry, inode); return NULL; @@ -276,13 +268,13 @@ static int hfsplus_file_release(struct inode *inode, struct file *file) if (atomic_read(&file->f_count) != 0) return 0; if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) { - down(&inode->i_sem); + mutex_lock(&inode->i_mutex); hfsplus_file_truncate(inode); if (inode->i_flags & S_DEAD) { hfsplus_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL); hfsplus_delete_inode(inode); } - up(&inode->i_sem); + mutex_unlock(&inode->i_mutex); } return 0; } @@ -317,11 +309,6 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode) if (!inode) return NULL; - { - void hfsplus_inode_check(struct super_block *sb); - atomic_inc(&HFSPLUS_SB(sb).inode_cnt); - hfsplus_inode_check(sb); - } inode->i_ino = HFSPLUS_SB(sb).next_cnid++; inode->i_mode = mode; inode->i_uid = current->fsuid; @@ -444,7 +431,8 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) inode->i_size = 2 + be32_to_cpu(folder->valence); inode->i_atime = hfsp_mt2ut(folder->access_date); inode->i_mtime = hfsp_mt2ut(folder->content_mod_date); - inode->i_ctime = inode->i_mtime; + inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date); + HFSPLUS_I(inode).create_date = folder->create_date; HFSPLUS_I(inode).fs_blocks = 0; inode->i_op = &hfsplus_dir_inode_operations; inode->i_fop = &hfsplus_dir_operations; @@ -475,9 +463,10 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) } inode->i_atime = hfsp_mt2ut(file->access_date); inode->i_mtime = hfsp_mt2ut(file->content_mod_date); - inode->i_ctime = inode->i_mtime; + inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date); + HFSPLUS_I(inode).create_date = file->create_date; } else { - printk("HFS+-fs: bad catalog entry used to create inode\n"); + printk(KERN_ERR "hfs: bad catalog entry used to create inode\n"); res = -EIO; } return res; diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index e07aa096e07..13cf848ac83 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c @@ -12,6 +12,7 @@ * hfsplus ioctls */ +#include <linux/capability.h> #include <linux/fs.h> #include <linux/sched.h> #include <linux/xattr.h> diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c index 935dafba007..dc64fac0083 100644 --- a/fs/hfsplus/options.c +++ b/fs/hfsplus/options.c @@ -83,58 +83,58 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi) switch (token) { case opt_creator: if (match_fourchar(&args[0], &sbi->creator)) { - printk("HFS+-fs: creator requires a 4 character value\n"); + printk(KERN_ERR "hfs: creator requires a 4 character value\n"); return 0; } break; case opt_type: if (match_fourchar(&args[0], &sbi->type)) { - printk("HFS+-fs: type requires a 4 character value\n"); + printk(KERN_ERR "hfs: type requires a 4 character value\n"); return 0; } break; case opt_umask: if (match_octal(&args[0], &tmp)) { - printk("HFS+-fs: umask requires a value\n"); + printk(KERN_ERR "hfs: umask requires a value\n"); return 0; } sbi->umask = (umode_t)tmp; break; case opt_uid: if (match_int(&args[0], &tmp)) { - printk("HFS+-fs: uid requires an argument\n"); + printk(KERN_ERR "hfs: uid requires an argument\n"); return 0; } sbi->uid = (uid_t)tmp; break; case opt_gid: if (match_int(&args[0], &tmp)) { - printk("HFS+-fs: gid requires an argument\n"); + printk(KERN_ERR "hfs: gid requires an argument\n"); return 0; } sbi->gid = (gid_t)tmp; break; case opt_part: if (match_int(&args[0], &sbi->part)) { - printk("HFS+-fs: part requires an argument\n"); + printk(KERN_ERR "hfs: part requires an argument\n"); return 0; } break; case opt_session: if (match_int(&args[0], &sbi->session)) { - printk("HFS+-fs: session requires an argument\n"); + printk(KERN_ERR "hfs: session requires an argument\n"); return 0; } break; case opt_nls: if (sbi->nls) { - printk("HFS+-fs: unable to change nls mapping\n"); + printk(KERN_ERR "hfs: unable to change nls mapping\n"); return 0; } p = match_strdup(&args[0]); sbi->nls = load_nls(p); if (!sbi->nls) { - printk("HFS+-fs: unable to load nls mapping \"%s\"\n", p); + printk(KERN_ERR "hfs: unable to load nls mapping \"%s\"\n", p); kfree(p); return 0; } diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 8093351bd7c..7843f792a4b 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -22,29 +22,12 @@ static void hfsplus_destroy_inode(struct inode *inode); #include "hfsplus_fs.h" -void hfsplus_inode_check(struct super_block *sb) -{ -#if 0 - u32 cnt = atomic_read(&HFSPLUS_SB(sb).inode_cnt); - u32 last_cnt = HFSPLUS_SB(sb).last_inode_cnt; - - if (cnt <= (last_cnt / 2) || - cnt >= (last_cnt * 2)) { - HFSPLUS_SB(sb).last_inode_cnt = cnt; - printk("inode_check: %u,%u,%u\n", cnt, last_cnt, - HFSPLUS_SB(sb).cat_tree ? HFSPLUS_SB(sb).cat_tree->node_hash_cnt : 0); - } -#endif -} - static void hfsplus_read_inode(struct inode *inode) { struct hfs_find_data fd; struct hfsplus_vh *vhdr; int err; - atomic_inc(&HFSPLUS_SB(inode->i_sb).inode_cnt); - hfsplus_inode_check(inode->i_sb); INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); init_MUTEX(&HFSPLUS_I(inode).extents_lock); HFSPLUS_I(inode).flags = 0; @@ -155,12 +138,10 @@ static int hfsplus_write_inode(struct inode *inode, int unused) static void hfsplus_clear_inode(struct inode *inode) { dprint(DBG_INODE, "hfsplus_clear_inode: %lu\n", inode->i_ino); - atomic_dec(&HFSPLUS_SB(inode->i_sb).inode_cnt); if (HFSPLUS_IS_RSRC(inode)) { HFSPLUS_I(HFSPLUS_I(inode).rsrc_inode).rsrc_inode = NULL; iput(HFSPLUS_I(inode).rsrc_inode); } - hfsplus_inode_check(inode->i_sb); } static void hfsplus_write_super(struct super_block *sb) @@ -188,7 +169,7 @@ static void hfsplus_write_super(struct super_block *sb) block = HFSPLUS_SB(sb).blockoffset; block += (HFSPLUS_SB(sb).sect_count - 2) >> (sb->s_blocksize_bits - 9); offset = ((HFSPLUS_SB(sb).sect_count - 2) << 9) & (sb->s_blocksize - 1); - printk("backup: %u,%u,%u,%u\n", HFSPLUS_SB(sb).blockoffset, + printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n", HFSPLUS_SB(sb).blockoffset, HFSPLUS_SB(sb).sect_count, block, offset); bh = sb_bread(sb, block); if (bh) { @@ -198,7 +179,7 @@ static void hfsplus_write_super(struct super_block *sb) mark_buffer_dirty(bh); brelse(bh); } else - printk("backup not found!\n"); + printk(KERN_WARNING "hfs: backup not found!\n"); } } HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP; @@ -259,18 +240,18 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data) return -EINVAL; if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { - printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " + printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, " "running fsck.hfsplus is recommended. leaving read-only.\n"); sb->s_flags |= MS_RDONLY; *flags |= MS_RDONLY; } else if (sbi.flags & HFSPLUS_SB_FORCE) { /* nothing */ } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { - printk("HFS+-fs: Filesystem is marked locked, leaving read-only.\n"); + printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n"); sb->s_flags |= MS_RDONLY; *flags |= MS_RDONLY; } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { - printk("HFS+-fs: Filesystem is marked journaled, leaving read-only.\n"); + printk(KERN_WARNING "hfs: filesystem is marked journaled, leaving read-only.\n"); sb->s_flags |= MS_RDONLY; *flags |= MS_RDONLY; } @@ -311,8 +292,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) INIT_HLIST_HEAD(&sbi->rsrc_inodes); hfsplus_fill_defaults(sbi); if (!hfsplus_parse_options(data, sbi)) { - if (!silent) - printk("HFS+-fs: unable to parse mount options\n"); + printk(KERN_ERR "hfs: unable to parse mount options\n"); err = -EINVAL; goto cleanup; } @@ -320,8 +300,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) /* temporarily use utf8 to correctly find the hidden dir below */ nls = sbi->nls; sbi->nls = load_nls("utf8"); - if (!nls) { - printk("HFS+: unable to load nls for utf8\n"); + if (!sbi->nls) { + printk(KERN_ERR "hfs: unable to load nls for utf8\n"); err = -EINVAL; goto cleanup; } @@ -329,17 +309,17 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) /* Grab the volume header */ if (hfsplus_read_wrapper(sb)) { if (!silent) - printk("HFS+-fs: unable to find HFS+ superblock\n"); + printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n"); err = -EINVAL; goto cleanup; } vhdr = HFSPLUS_SB(sb).s_vhdr; /* Copy parts of the volume header into the superblock */ - sb->s_magic = be16_to_cpu(vhdr->signature); - if (be16_to_cpu(vhdr->version) != HFSPLUS_CURRENT_VERSION) { - if (!silent) - printk("HFS+-fs: wrong filesystem version\n"); + sb->s_magic = HFSPLUS_VOLHEAD_SIG; + if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION || + be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) { + printk(KERN_ERR "hfs: wrong filesystem version\n"); goto cleanup; } HFSPLUS_SB(sb).total_blocks = be32_to_cpu(vhdr->total_blocks); @@ -360,20 +340,17 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) sb->s_maxbytes = MAX_LFS_FILESIZE; if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { - if (!silent) - printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " - "running fsck.hfsplus is recommended. mounting read-only.\n"); + printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, " + "running fsck.hfsplus is recommended. mounting read-only.\n"); sb->s_flags |= MS_RDONLY; } else if (sbi->flags & HFSPLUS_SB_FORCE) { /* nothing */ } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { - if (!silent) - printk("HFS+-fs: 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; } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { - if (!silent) - printk("HFS+-fs: write access to a jounaled filesystem is not supported, " - "use the force option at your own risk, mounting read-only.\n"); + printk(KERN_WARNING "hfs: write access to a jounaled filesystem is not supported, " + "use the force option at your own risk, mounting read-only.\n"); sb->s_flags |= MS_RDONLY; } sbi->flags &= ~HFSPLUS_SB_FORCE; @@ -381,21 +358,18 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) /* Load metadata objects (B*Trees) */ HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); if (!HFSPLUS_SB(sb).ext_tree) { - if (!silent) - printk("HFS+-fs: failed to load extents file\n"); + printk(KERN_ERR "hfs: failed to load extents file\n"); goto cleanup; } HFSPLUS_SB(sb).cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID); if (!HFSPLUS_SB(sb).cat_tree) { - if (!silent) - printk("HFS+-fs: failed to load catalog file\n"); + printk(KERN_ERR "hfs: failed to load catalog file\n"); goto cleanup; } HFSPLUS_SB(sb).alloc_file = iget(sb, HFSPLUS_ALLOC_CNID); if (!HFSPLUS_SB(sb).alloc_file) { - if (!silent) - printk("HFS+-fs: failed to load allocation file\n"); + printk(KERN_ERR "hfs: failed to load allocation file\n"); goto cleanup; } @@ -403,8 +377,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) root = iget(sb, HFSPLUS_ROOT_CNID); sb->s_root = d_alloc_root(root); if (!sb->s_root) { - if (!silent) - printk("HFS+-fs: failed to load root directory\n"); + printk(KERN_ERR "hfs: failed to load root directory\n"); iput(root); goto cleanup; } @@ -438,7 +411,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); if (!HFSPLUS_SB(sb).hidden_dir) { - printk("HFS+: create hidden dir...\n"); + printk(KERN_DEBUG "hfs: create hidden dir...\n"); HFSPLUS_SB(sb).hidden_dir = hfsplus_new_inode(sb, S_IFDIR); hfsplus_create_cat(HFSPLUS_SB(sb).hidden_dir->i_ino, sb->s_root->d_inode, &str, HFSPLUS_SB(sb).hidden_dir); @@ -518,7 +491,7 @@ static void __exit exit_hfsplus_fs(void) { unregister_filesystem(&hfsplus_fs_type); if (kmem_cache_destroy(hfsplus_inode_cachep)) - printk(KERN_INFO "hfsplus_inode_cache: not all structures were freed\n"); + printk(KERN_ERR "hfsplus_inode_cache: not all structures were freed\n"); } module_init(init_hfsplus_fs) diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index 060c69048c3..689c8bd721f 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c @@ -28,7 +28,8 @@ static inline u16 case_fold(u16 c) } /* Compare unicode strings, return values like normal strcmp */ -int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unistr *s2) +int hfsplus_strcasecmp(const struct hfsplus_unistr *s1, + const struct hfsplus_unistr *s2) { u16 len1, len2, c1, c2; const hfsplus_unichr *p1, *p2; @@ -59,6 +60,33 @@ int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unis } } +/* Compare names as a sequence of 16-bit unsigned integers */ +int hfsplus_strcmp(const struct hfsplus_unistr *s1, + const struct hfsplus_unistr *s2) +{ + u16 len1, len2, c1, c2; + const hfsplus_unichr *p1, *p2; + int len; + + len1 = be16_to_cpu(s1->length); + len2 = be16_to_cpu(s2->length); + p1 = s1->unicode; + p2 = s2->unicode; + + for (len = min(len1, len2); len > 0; len--) { + c1 = be16_to_cpu(*p1); + c2 = be16_to_cpu(*p2); + if (c1 != c2) + return c1 < c2 ? -1 : 1; + p1++; + p2++; + } + + return len1 < len2 ? -1 : + len1 > len2 ? 1 : 0; +} + + #define Hangul_SBase 0xac00 #define Hangul_LBase 0x1100 #define Hangul_VBase 0x1161 diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index 95455e83923..72cab78f050 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c @@ -28,8 +28,11 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) { u32 extent; u16 attrib; + __be16 sig; - if (be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG)) != HFSPLUS_VOLHEAD_SIG) + sig = *(__be16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG); + if (sig != cpu_to_be16(HFSPLUS_VOLHEAD_SIG) && + sig != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) return 0; attrib = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ATTRIB)); @@ -70,7 +73,7 @@ static int hfsplus_get_last_session(struct super_block *sb, *start = (sector_t)te.cdte_addr.lba << 2; return 0; } - printk(KERN_ERR "HFS: Invalid session number or type of track\n"); + printk(KERN_ERR "hfs: invalid session number or type of track\n"); return -EINVAL; } ms_info.addr_format = CDROM_LBA; @@ -114,6 +117,10 @@ int hfsplus_read_wrapper(struct super_block *sb) } if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) break; + if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) { + HFSPLUS_SB(sb).flags |= HFSPLUS_SB_HFSX; + break; + } brelse(bh); /* check for a partition block @@ -143,7 +150,7 @@ int hfsplus_read_wrapper(struct super_block *sb) blocksize >>= 1; if (sb_set_blocksize(sb, blocksize) != blocksize) { - printk("HFS+: unable to blocksize to %u!\n", blocksize); + printk(KERN_ERR "hfs: unable to set blocksize to %u!\n", blocksize); return -EINVAL; } @@ -158,7 +165,9 @@ int hfsplus_read_wrapper(struct super_block *sb) return -EIO; /* should still be the same... */ - if (be16_to_cpu(vhdr->signature) != HFSPLUS_VOLHEAD_SIG) + if (vhdr->signature != (HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX ? + cpu_to_be16(HFSPLUS_VOLHEAD_SIGX) : + cpu_to_be16(HFSPLUS_VOLHEAD_SIG))) goto error; HFSPLUS_SB(sb).s_vhbh = bh; HFSPLUS_SB(sb).s_vhdr = vhdr; |