Commit 2179d372 authored by David Elliott's avatar David Elliott Committed by Linus Torvalds

[PATCH] hfs: add HFSX support

Add support for HFSX, which allows for case-sensitive filenames.
Signed-off-by: default avatarRoman Zippel <zippel@linux-m68k.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7cf3cc30
...@@ -31,17 +31,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) ...@@ -31,17 +31,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
init_MUTEX(&tree->tree_lock); init_MUTEX(&tree->tree_lock);
spin_lock_init(&tree->hash_lock); spin_lock_init(&tree->hash_lock);
/* Set the correct compare function */
tree->sb = sb; tree->sb = sb;
tree->cnid = id; 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); tree->inode = iget(sb, id);
if (!tree->inode) if (!tree->inode)
goto free_tree; goto free_tree;
...@@ -64,6 +55,20 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) ...@@ -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->max_key_len = be16_to_cpu(head->max_key_len);
tree->depth = be16_to_cpu(head->depth); 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; size = tree->node_size;
if (!size || size & (size - 1)) if (!size || size & (size - 1))
goto fail_page; goto fail_page;
......
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
#include "hfsplus_fs.h" #include "hfsplus_fs.h"
#include "hfsplus_raw.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; __be32 k1p, k2p;
...@@ -22,7 +23,20 @@ int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) ...@@ -22,7 +23,20 @@ int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2)
if (k1p != k2p) if (k1p != k2p)
return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; 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, void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key,
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
#include "hfsplus_raw.h" #include "hfsplus_raw.h"
/* Compare two extents keys, returns 0 on same, pos/neg for difference */ /* 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 k1id, k2id;
__be32 k1s, k2s; __be32 k1s, k2s;
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#define HFSPLUS_TYPE_DATA 0x00 #define HFSPLUS_TYPE_DATA 0x00
#define HFSPLUS_TYPE_RSRC 0xFF #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 NODE_HASH_SIZE 256
...@@ -149,6 +149,7 @@ struct hfsplus_sb_info { ...@@ -149,6 +149,7 @@ struct hfsplus_sb_info {
#define HFSPLUS_SB_WRITEBACKUP 0x0001 #define HFSPLUS_SB_WRITEBACKUP 0x0001
#define HFSPLUS_SB_NODECOMPOSE 0x0002 #define HFSPLUS_SB_NODECOMPOSE 0x0002
#define HFSPLUS_SB_FORCE 0x0004 #define HFSPLUS_SB_FORCE 0x0004
#define HFSPLUS_SB_HFSX 0x0008
struct hfsplus_inode_info { struct hfsplus_inode_info {
...@@ -303,7 +304,8 @@ int hfs_brec_read(struct hfs_find_data *, void *, int); ...@@ -303,7 +304,8 @@ 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_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 *); 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 *);
...@@ -312,7 +314,7 @@ int hfsplus_rename_cat(u32, struct inode *, struct qstr *, ...@@ -312,7 +314,7 @@ int hfsplus_rename_cat(u32, struct inode *, struct qstr *,
struct inode *, struct qstr *); struct inode *, struct qstr *);
/* extents.c */ /* 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 *); 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);
...@@ -350,7 +352,8 @@ extern u16 hfsplus_decompose_table[]; ...@@ -350,7 +352,8 @@ extern u16 hfsplus_decompose_table[];
extern u16 hfsplus_compose_table[]; extern u16 hfsplus_compose_table[];
/* unicode.c */ /* 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_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *);
int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
......
...@@ -22,8 +22,10 @@ ...@@ -22,8 +22,10 @@
#define HFSPLUS_SECTOR_SHIFT 9 #define HFSPLUS_SECTOR_SHIFT 9
#define HFSPLUS_VOLHEAD_SECTOR 2 #define HFSPLUS_VOLHEAD_SECTOR 2
#define HFSPLUS_VOLHEAD_SIG 0x482b #define HFSPLUS_VOLHEAD_SIG 0x482b
#define HFSPLUS_VOLHEAD_SIGX 0x4858
#define HFSPLUS_SUPER_MAGIC 0x482b #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_MAGIC 0x4244
#define HFSP_WRAP_ATTRIB_SLOCK 0x8000 #define HFSP_WRAP_ATTRIB_SLOCK 0x8000
...@@ -161,7 +163,7 @@ struct hfs_btree_header_rec { ...@@ -161,7 +163,7 @@ struct hfs_btree_header_rec {
u16 reserved1; u16 reserved1;
__be32 clump_size; __be32 clump_size;
u8 btree_type; u8 btree_type;
u8 reserved2; u8 key_type;
__be32 attributes; __be32 attributes;
u32 reserved3[16]; u32 reserved3[16];
} __packed; } __packed;
...@@ -186,6 +188,10 @@ struct hfs_btree_header_rec { ...@@ -186,6 +188,10 @@ struct hfs_btree_header_rec {
#define HFSPLUS_EXCH_CNID 15 /* ExchangeFiles temp id */ #define HFSPLUS_EXCH_CNID 15 /* ExchangeFiles temp id */
#define HFSPLUS_FIRSTUSER_CNID 16 /* first available user 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 */ /* HFS+ catalog entry key */
struct hfsplus_cat_key { struct hfsplus_cat_key {
__be16 key_len; __be16 key_len;
......
...@@ -316,8 +316,9 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) ...@@ -316,8 +316,9 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
vhdr = HFSPLUS_SB(sb).s_vhdr; vhdr = HFSPLUS_SB(sb).s_vhdr;
/* Copy parts of the volume header into the superblock */ /* Copy parts of the volume header into the superblock */
sb->s_magic = be16_to_cpu(vhdr->signature); sb->s_magic = HFSPLUS_VOLHEAD_SIG;
if (be16_to_cpu(vhdr->version) != HFSPLUS_CURRENT_VERSION) { 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"); printk(KERN_ERR "hfs: wrong filesystem version\n");
goto cleanup; goto cleanup;
} }
......
...@@ -28,7 +28,8 @@ static inline u16 case_fold(u16 c) ...@@ -28,7 +28,8 @@ static inline u16 case_fold(u16 c)
} }
/* Compare unicode strings, return values like normal strcmp */ /* 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; u16 len1, len2, c1, c2;
const hfsplus_unichr *p1, *p2; const hfsplus_unichr *p1, *p2;
...@@ -59,6 +60,33 @@ int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unis ...@@ -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_SBase 0xac00
#define Hangul_LBase 0x1100 #define Hangul_LBase 0x1100
#define Hangul_VBase 0x1161 #define Hangul_VBase 0x1161
......
...@@ -28,8 +28,11 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) ...@@ -28,8 +28,11 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
{ {
u32 extent; u32 extent;
u16 attrib; 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; return 0;
attrib = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ATTRIB)); attrib = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ATTRIB));
...@@ -114,6 +117,10 @@ int hfsplus_read_wrapper(struct super_block *sb) ...@@ -114,6 +117,10 @@ int hfsplus_read_wrapper(struct super_block *sb)
} }
if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
break; break;
if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) {
HFSPLUS_SB(sb).flags |= HFSPLUS_SB_HFSX;
break;
}
brelse(bh); brelse(bh);
/* check for a partition block /* check for a partition block
...@@ -158,7 +165,9 @@ int hfsplus_read_wrapper(struct super_block *sb) ...@@ -158,7 +165,9 @@ int hfsplus_read_wrapper(struct super_block *sb)
return -EIO; return -EIO;
/* should still be the same... */ /* 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; goto error;
HFSPLUS_SB(sb).s_vhbh = bh; HFSPLUS_SB(sb).s_vhbh = bh;
HFSPLUS_SB(sb).s_vhdr = vhdr; HFSPLUS_SB(sb).s_vhdr = vhdr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment