Browse Source

[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>
master
David Elliott 16 years ago
committed by Linus Torvalds
parent
commit
2179d372d9
  1. 23
      fs/hfsplus/btree.c
  2. 18
      fs/hfsplus/catalog.c
  3. 3
      fs/hfsplus/extents.c
  4. 11
      fs/hfsplus/hfsplus_fs.h
  5. 10
      fs/hfsplus/hfsplus_raw.h
  6. 5
      fs/hfsplus/super.c
  7. 30
      fs/hfsplus/unicode.c
  8. 13
      fs/hfsplus/wrapper.c

23
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(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;

18
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,

3
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;

11
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 {
@ -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);

10
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
@ -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;

5
fs/hfsplus/super.c

@ -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;
}

30
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

13
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));
@ -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…
Cancel
Save