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>
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(KERN_ERR "hfs: unknown B*Tree requested\n");
- goto free_tree;
- }
tree->inode = iget(sb, id);
if (!tree->inode)
goto free_tree;
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;
#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;
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,
#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;
#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
#define HFSPLUS_SB_WRITEBACKUP 0x0001
#define HFSPLUS_SB_NODECOMPOSE 0x0002
#define HFSPLUS_SB_FORCE 0x0004
+#define HFSPLUS_SB_HFSX 0x0008
struct hfsplus_inode_info {
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 *);
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);
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);
#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
u16 reserved1;
__be32 clump_size;
u8 btree_type;
- u8 reserved2;
+ u8 key_type;
__be32 attributes;
u32 reserved3[16];
} __packed;
#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;
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) {
+ 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;
}
}
/* 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;
}
}
+/* 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
{
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));
}
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
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;