[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>
This commit is contained in:
parent
7cf3cc3036
commit
2179d372d9
8 changed files with 90 additions and 23 deletions
|
@ -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(KERN_ERR "hfs: 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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
@ -303,7 +304,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 +314,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 +352,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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -161,7 +163,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 +188,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;
|
||||
|
|
|
@ -316,8 +316,9 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue