diff options
author | David Elliott <elliott@stcnet.com> | 2006-01-18 20:43:08 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-18 22:20:23 -0500 |
commit | 2179d372d9f8b5fc5c189c89bc6a565a42151b23 (patch) | |
tree | 2b09f55702890e7edbae9b9e396bfe958f53608a /fs | |
parent | 7cf3cc3036cb7b1147350bf7c3f1ab98c160eb7b (diff) |
[PATCH] hfs: add HFSX support
Add support for HFSX, which allows for case-sensitive filenames.
Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/hfsplus/btree.c | 23 | ||||
-rw-r--r-- | fs/hfsplus/catalog.c | 18 | ||||
-rw-r--r-- | fs/hfsplus/extents.c | 3 | ||||
-rw-r--r-- | fs/hfsplus/hfsplus_fs.h | 11 | ||||
-rw-r--r-- | fs/hfsplus/hfsplus_raw.h | 10 | ||||
-rw-r--r-- | fs/hfsplus/super.c | 5 | ||||
-rw-r--r-- | fs/hfsplus/unicode.c | 30 | ||||
-rw-r--r-- | fs/hfsplus/wrapper.c | 13 |
8 files changed, 90 insertions, 23 deletions
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 671290663838..a67edfa34e9e 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) | |||
31 | 31 | ||
32 | init_MUTEX(&tree->tree_lock); | 32 | init_MUTEX(&tree->tree_lock); |
33 | spin_lock_init(&tree->hash_lock); | 33 | spin_lock_init(&tree->hash_lock); |
34 | /* Set the correct compare function */ | ||
35 | tree->sb = sb; | 34 | tree->sb = sb; |
36 | tree->cnid = id; | 35 | tree->cnid = id; |
37 | if (id == HFSPLUS_EXT_CNID) { | ||
38 | tree->keycmp = hfsplus_ext_cmp_key; | ||
39 | } else if (id == HFSPLUS_CAT_CNID) { | ||
40 | tree->keycmp = hfsplus_cat_cmp_key; | ||
41 | } else { | ||
42 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | ||
43 | goto free_tree; | ||
44 | } | ||
45 | tree->inode = iget(sb, id); | 36 | tree->inode = iget(sb, id); |
46 | if (!tree->inode) | 37 | if (!tree->inode) |
47 | goto free_tree; | 38 | goto free_tree; |
@@ -64,6 +55,20 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
64 | tree->max_key_len = be16_to_cpu(head->max_key_len); | 55 | tree->max_key_len = be16_to_cpu(head->max_key_len); |
65 | tree->depth = be16_to_cpu(head->depth); | 56 | tree->depth = be16_to_cpu(head->depth); |
66 | 57 | ||
58 | /* Set the correct compare function */ | ||
59 | if (id == HFSPLUS_EXT_CNID) { | ||
60 | tree->keycmp = hfsplus_ext_cmp_key; | ||
61 | } else if (id == HFSPLUS_CAT_CNID) { | ||
62 | if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && | ||
63 | (head->key_type == HFSPLUS_KEY_BINARY)) | ||
64 | tree->keycmp = hfsplus_cat_bin_cmp_key; | ||
65 | else | ||
66 | tree->keycmp = hfsplus_cat_case_cmp_key; | ||
67 | } else { | ||
68 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | ||
69 | goto fail_page; | ||
70 | } | ||
71 | |||
67 | size = tree->node_size; | 72 | size = tree->node_size; |
68 | if (!size || size & (size - 1)) | 73 | if (!size || size & (size - 1)) |
69 | goto fail_page; | 74 | goto fail_page; |
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 074451f1d95f..662d176856d8 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c | |||
@@ -13,7 +13,8 @@ | |||
13 | #include "hfsplus_fs.h" | 13 | #include "hfsplus_fs.h" |
14 | #include "hfsplus_raw.h" | 14 | #include "hfsplus_raw.h" |
15 | 15 | ||
16 | int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | 16 | int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1, |
17 | const hfsplus_btree_key *k2) | ||
17 | { | 18 | { |
18 | __be32 k1p, k2p; | 19 | __be32 k1p, k2p; |
19 | 20 | ||
@@ -22,7 +23,20 @@ int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | |||
22 | if (k1p != k2p) | 23 | if (k1p != k2p) |
23 | return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; | 24 | return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; |
24 | 25 | ||
25 | return hfsplus_unistrcmp(&k1->cat.name, &k2->cat.name); | 26 | return hfsplus_strcasecmp(&k1->cat.name, &k2->cat.name); |
27 | } | ||
28 | |||
29 | int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, | ||
30 | const hfsplus_btree_key *k2) | ||
31 | { | ||
32 | __be32 k1p, k2p; | ||
33 | |||
34 | k1p = k1->cat.parent; | ||
35 | k2p = k2->cat.parent; | ||
36 | if (k1p != k2p) | ||
37 | return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; | ||
38 | |||
39 | return hfsplus_strcmp(&k1->cat.name, &k2->cat.name); | ||
26 | } | 40 | } |
27 | 41 | ||
28 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, | 42 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, |
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index c95559f69bcb..1a7480089e82 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c | |||
@@ -16,7 +16,8 @@ | |||
16 | #include "hfsplus_raw.h" | 16 | #include "hfsplus_raw.h" |
17 | 17 | ||
18 | /* Compare two extents keys, returns 0 on same, pos/neg for difference */ | 18 | /* Compare two extents keys, returns 0 on same, pos/neg for difference */ |
19 | int hfsplus_ext_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | 19 | int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, |
20 | const hfsplus_btree_key *k2) | ||
20 | { | 21 | { |
21 | __be32 k1id, k2id; | 22 | __be32 k1id, k2id; |
22 | __be32 k1s, k2s; | 23 | __be32 k1s, k2s; |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 0fa1ab6250bf..4608171f45d3 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
@@ -36,7 +36,7 @@ | |||
36 | #define HFSPLUS_TYPE_DATA 0x00 | 36 | #define HFSPLUS_TYPE_DATA 0x00 |
37 | #define HFSPLUS_TYPE_RSRC 0xFF | 37 | #define HFSPLUS_TYPE_RSRC 0xFF |
38 | 38 | ||
39 | typedef int (*btree_keycmp)(hfsplus_btree_key *, hfsplus_btree_key *); | 39 | typedef int (*btree_keycmp)(const hfsplus_btree_key *, const hfsplus_btree_key *); |
40 | 40 | ||
41 | #define NODE_HASH_SIZE 256 | 41 | #define NODE_HASH_SIZE 256 |
42 | 42 | ||
@@ -149,6 +149,7 @@ struct hfsplus_sb_info { | |||
149 | #define HFSPLUS_SB_WRITEBACKUP 0x0001 | 149 | #define HFSPLUS_SB_WRITEBACKUP 0x0001 |
150 | #define HFSPLUS_SB_NODECOMPOSE 0x0002 | 150 | #define HFSPLUS_SB_NODECOMPOSE 0x0002 |
151 | #define HFSPLUS_SB_FORCE 0x0004 | 151 | #define HFSPLUS_SB_FORCE 0x0004 |
152 | #define HFSPLUS_SB_HFSX 0x0008 | ||
152 | 153 | ||
153 | 154 | ||
154 | struct hfsplus_inode_info { | 155 | struct hfsplus_inode_info { |
@@ -303,7 +304,8 @@ int hfs_brec_read(struct hfs_find_data *, void *, int); | |||
303 | int hfs_brec_goto(struct hfs_find_data *, int); | 304 | int hfs_brec_goto(struct hfs_find_data *, int); |
304 | 305 | ||
305 | /* catalog.c */ | 306 | /* catalog.c */ |
306 | int hfsplus_cat_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *); | 307 | int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); |
308 | int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); | ||
307 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *); | 309 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *); |
308 | int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); | 310 | int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); |
309 | int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); | 311 | int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); |
@@ -312,7 +314,7 @@ int hfsplus_rename_cat(u32, struct inode *, struct qstr *, | |||
312 | struct inode *, struct qstr *); | 314 | struct inode *, struct qstr *); |
313 | 315 | ||
314 | /* extents.c */ | 316 | /* extents.c */ |
315 | int hfsplus_ext_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *); | 317 | int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); |
316 | void hfsplus_ext_write_extent(struct inode *); | 318 | void hfsplus_ext_write_extent(struct inode *); |
317 | int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); | 319 | int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); |
318 | int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int); | 320 | int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int); |
@@ -350,7 +352,8 @@ extern u16 hfsplus_decompose_table[]; | |||
350 | extern u16 hfsplus_compose_table[]; | 352 | extern u16 hfsplus_compose_table[]; |
351 | 353 | ||
352 | /* unicode.c */ | 354 | /* unicode.c */ |
353 | int hfsplus_unistrcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | 355 | int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); |
356 | int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | ||
354 | int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); | 357 | int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); |
355 | int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); | 358 | int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); |
356 | 359 | ||
diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index b4fbed633219..ccc47966dc54 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h | |||
@@ -22,8 +22,10 @@ | |||
22 | #define HFSPLUS_SECTOR_SHIFT 9 | 22 | #define HFSPLUS_SECTOR_SHIFT 9 |
23 | #define HFSPLUS_VOLHEAD_SECTOR 2 | 23 | #define HFSPLUS_VOLHEAD_SECTOR 2 |
24 | #define HFSPLUS_VOLHEAD_SIG 0x482b | 24 | #define HFSPLUS_VOLHEAD_SIG 0x482b |
25 | #define HFSPLUS_VOLHEAD_SIGX 0x4858 | ||
25 | #define HFSPLUS_SUPER_MAGIC 0x482b | 26 | #define HFSPLUS_SUPER_MAGIC 0x482b |
26 | #define HFSPLUS_CURRENT_VERSION 4 | 27 | #define HFSPLUS_MIN_VERSION 4 |
28 | #define HFSPLUS_CURRENT_VERSION 5 | ||
27 | 29 | ||
28 | #define HFSP_WRAP_MAGIC 0x4244 | 30 | #define HFSP_WRAP_MAGIC 0x4244 |
29 | #define HFSP_WRAP_ATTRIB_SLOCK 0x8000 | 31 | #define HFSP_WRAP_ATTRIB_SLOCK 0x8000 |
@@ -161,7 +163,7 @@ struct hfs_btree_header_rec { | |||
161 | u16 reserved1; | 163 | u16 reserved1; |
162 | __be32 clump_size; | 164 | __be32 clump_size; |
163 | u8 btree_type; | 165 | u8 btree_type; |
164 | u8 reserved2; | 166 | u8 key_type; |
165 | __be32 attributes; | 167 | __be32 attributes; |
166 | u32 reserved3[16]; | 168 | u32 reserved3[16]; |
167 | } __packed; | 169 | } __packed; |
@@ -186,6 +188,10 @@ struct hfs_btree_header_rec { | |||
186 | #define HFSPLUS_EXCH_CNID 15 /* ExchangeFiles temp id */ | 188 | #define HFSPLUS_EXCH_CNID 15 /* ExchangeFiles temp id */ |
187 | #define HFSPLUS_FIRSTUSER_CNID 16 /* first available user id */ | 189 | #define HFSPLUS_FIRSTUSER_CNID 16 /* first available user id */ |
188 | 190 | ||
191 | /* btree key type */ | ||
192 | #define HFSPLUS_KEY_CASEFOLDING 0xCF /* case-insensitive */ | ||
193 | #define HFSPLUS_KEY_BINARY 0xBC /* case-sensitive */ | ||
194 | |||
189 | /* HFS+ catalog entry key */ | 195 | /* HFS+ catalog entry key */ |
190 | struct hfsplus_cat_key { | 196 | struct hfsplus_cat_key { |
191 | __be16 key_len; | 197 | __be16 key_len; |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index b712d34d458d..7843f792a4b7 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
@@ -316,8 +316,9 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
316 | vhdr = HFSPLUS_SB(sb).s_vhdr; | 316 | vhdr = HFSPLUS_SB(sb).s_vhdr; |
317 | 317 | ||
318 | /* Copy parts of the volume header into the superblock */ | 318 | /* Copy parts of the volume header into the superblock */ |
319 | sb->s_magic = be16_to_cpu(vhdr->signature); | 319 | sb->s_magic = HFSPLUS_VOLHEAD_SIG; |
320 | if (be16_to_cpu(vhdr->version) != HFSPLUS_CURRENT_VERSION) { | 320 | if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION || |
321 | be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) { | ||
321 | printk(KERN_ERR "hfs: wrong filesystem version\n"); | 322 | printk(KERN_ERR "hfs: wrong filesystem version\n"); |
322 | goto cleanup; | 323 | goto cleanup; |
323 | } | 324 | } |
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index 060c69048c3d..689c8bd721fb 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c | |||
@@ -28,7 +28,8 @@ static inline u16 case_fold(u16 c) | |||
28 | } | 28 | } |
29 | 29 | ||
30 | /* Compare unicode strings, return values like normal strcmp */ | 30 | /* Compare unicode strings, return values like normal strcmp */ |
31 | int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unistr *s2) | 31 | int hfsplus_strcasecmp(const struct hfsplus_unistr *s1, |
32 | const struct hfsplus_unistr *s2) | ||
32 | { | 33 | { |
33 | u16 len1, len2, c1, c2; | 34 | u16 len1, len2, c1, c2; |
34 | const hfsplus_unichr *p1, *p2; | 35 | const hfsplus_unichr *p1, *p2; |
@@ -59,6 +60,33 @@ int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unis | |||
59 | } | 60 | } |
60 | } | 61 | } |
61 | 62 | ||
63 | /* Compare names as a sequence of 16-bit unsigned integers */ | ||
64 | int hfsplus_strcmp(const struct hfsplus_unistr *s1, | ||
65 | const struct hfsplus_unistr *s2) | ||
66 | { | ||
67 | u16 len1, len2, c1, c2; | ||
68 | const hfsplus_unichr *p1, *p2; | ||
69 | int len; | ||
70 | |||
71 | len1 = be16_to_cpu(s1->length); | ||
72 | len2 = be16_to_cpu(s2->length); | ||
73 | p1 = s1->unicode; | ||
74 | p2 = s2->unicode; | ||
75 | |||
76 | for (len = min(len1, len2); len > 0; len--) { | ||
77 | c1 = be16_to_cpu(*p1); | ||
78 | c2 = be16_to_cpu(*p2); | ||
79 | if (c1 != c2) | ||
80 | return c1 < c2 ? -1 : 1; | ||
81 | p1++; | ||
82 | p2++; | ||
83 | } | ||
84 | |||
85 | return len1 < len2 ? -1 : | ||
86 | len1 > len2 ? 1 : 0; | ||
87 | } | ||
88 | |||
89 | |||
62 | #define Hangul_SBase 0xac00 | 90 | #define Hangul_SBase 0xac00 |
63 | #define Hangul_LBase 0x1100 | 91 | #define Hangul_LBase 0x1100 |
64 | #define Hangul_VBase 0x1161 | 92 | #define Hangul_VBase 0x1161 |
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index 6b2dc3a061a8..72cab78f0509 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) | |||
28 | { | 28 | { |
29 | u32 extent; | 29 | u32 extent; |
30 | u16 attrib; | 30 | u16 attrib; |
31 | __be16 sig; | ||
31 | 32 | ||
32 | if (be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG)) != HFSPLUS_VOLHEAD_SIG) | 33 | sig = *(__be16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG); |
34 | if (sig != cpu_to_be16(HFSPLUS_VOLHEAD_SIG) && | ||
35 | sig != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) | ||
33 | return 0; | 36 | return 0; |
34 | 37 | ||
35 | attrib = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ATTRIB)); | 38 | attrib = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ATTRIB)); |
@@ -114,6 +117,10 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
114 | } | 117 | } |
115 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) | 118 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) |
116 | break; | 119 | break; |
120 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) { | ||
121 | HFSPLUS_SB(sb).flags |= HFSPLUS_SB_HFSX; | ||
122 | break; | ||
123 | } | ||
117 | brelse(bh); | 124 | brelse(bh); |
118 | 125 | ||
119 | /* check for a partition block | 126 | /* check for a partition block |
@@ -158,7 +165,9 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
158 | return -EIO; | 165 | return -EIO; |
159 | 166 | ||
160 | /* should still be the same... */ | 167 | /* should still be the same... */ |
161 | if (be16_to_cpu(vhdr->signature) != HFSPLUS_VOLHEAD_SIG) | 168 | if (vhdr->signature != (HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX ? |
169 | cpu_to_be16(HFSPLUS_VOLHEAD_SIGX) : | ||
170 | cpu_to_be16(HFSPLUS_VOLHEAD_SIG))) | ||
162 | goto error; | 171 | goto error; |
163 | HFSPLUS_SB(sb).s_vhbh = bh; | 172 | HFSPLUS_SB(sb).s_vhbh = bh; |
164 | HFSPLUS_SB(sb).s_vhdr = vhdr; | 173 | HFSPLUS_SB(sb).s_vhdr = vhdr; |