aboutsummaryrefslogtreecommitdiff
path: root/fs/hfsplus
diff options
context:
space:
mode:
Diffstat (limited to 'fs/hfsplus')
-rw-r--r--fs/hfsplus/bfind.c3
-rw-r--r--fs/hfsplus/bnode.c11
-rw-r--r--fs/hfsplus/brec.c2
-rw-r--r--fs/hfsplus/btree.c37
-rw-r--r--fs/hfsplus/catalog.c44
-rw-r--r--fs/hfsplus/dir.c47
-rw-r--r--fs/hfsplus/extents.c6
-rw-r--r--fs/hfsplus/hfsplus_fs.h12
-rw-r--r--fs/hfsplus/hfsplus_raw.h13
-rw-r--r--fs/hfsplus/inode.c11
-rw-r--r--fs/hfsplus/options.c18
-rw-r--r--fs/hfsplus/super.c54
-rw-r--r--fs/hfsplus/unicode.c30
-rw-r--r--fs/hfsplus/wrapper.c17
14 files changed, 191 insertions, 114 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/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 0fa1ab6250b..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
@@ -149,6 +149,7 @@ struct hfsplus_sb_info {
#define HFSPLUS_SB_WRITEBACKUP 0x0001
#define HFSPLUS_SB_NODECOMPOSE 0x0002
#define HFSPLUS_SB_FORCE 0x0004
+#define HFSPLUS_SB_HFSX 0x0008
struct hfsplus_inode_info {
@@ -165,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 */
@@ -303,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 *);
@@ -312,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);
@@ -350,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 7acff6c5464..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;
}
@@ -434,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;
@@ -465,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/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 d791780def5..7843f792a4b 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -169,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) {
@@ -179,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;
@@ -240,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;
}
@@ -292,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;
}
@@ -302,7 +301,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
nls = sbi->nls;
sbi->nls = load_nls("utf8");
if (!sbi->nls) {
- printk("HFS+: unable to load nls for utf8\n");
+ printk(KERN_ERR "hfs: unable to load nls for utf8\n");
err = -EINVAL;
goto cleanup;
}
@@ -310,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);
@@ -341,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;
@@ -362,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;
}
@@ -384,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;
}
@@ -419,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);
@@ -499,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;