diff options
| -rw-r--r-- | fs/hfsplus/btree.c | 4 | ||||
| -rw-r--r-- | fs/hfsplus/dir.c | 2 | ||||
| -rw-r--r-- | fs/hfsplus/hfsplus_fs.h | 4 | ||||
| -rw-r--r-- | fs/hfsplus/inode.c | 5 | ||||
| -rw-r--r-- | fs/hfsplus/super.c | 1 | ||||
| -rw-r--r-- | fs/hfsplus/unicode.c | 123 |
6 files changed, 138 insertions, 1 deletions
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 90ebab753d..050d29c0a5 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c | |||
| @@ -62,8 +62,10 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
| 62 | if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && | 62 | if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && |
| 63 | (head->key_type == HFSPLUS_KEY_BINARY)) | 63 | (head->key_type == HFSPLUS_KEY_BINARY)) |
| 64 | tree->keycmp = hfsplus_cat_bin_cmp_key; | 64 | tree->keycmp = hfsplus_cat_bin_cmp_key; |
| 65 | else | 65 | else { |
| 66 | tree->keycmp = hfsplus_cat_case_cmp_key; | 66 | tree->keycmp = hfsplus_cat_case_cmp_key; |
| 67 | HFSPLUS_SB(sb).flags |= HFSPLUS_SB_CASEFOLD; | ||
| 68 | } | ||
| 67 | } else { | 69 | } else { |
| 68 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | 70 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); |
| 69 | goto fail_page; | 71 | goto fail_page; |
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 80b5682a22..1955ee6125 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c | |||
| @@ -36,6 +36,8 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, | |||
| 36 | u16 type; | 36 | u16 type; |
| 37 | 37 | ||
| 38 | sb = dir->i_sb; | 38 | sb = dir->i_sb; |
| 39 | |||
| 40 | dentry->d_op = &hfsplus_dentry_operations; | ||
| 39 | dentry->d_fsdata = NULL; | 41 | dentry->d_fsdata = NULL; |
| 40 | hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); | 42 | hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); |
| 41 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); | 43 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 3915635b44..d9f5eda6d0 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
| @@ -150,6 +150,7 @@ struct hfsplus_sb_info { | |||
| 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 | #define HFSPLUS_SB_HFSX 0x0008 |
| 153 | #define HFSPLUS_SB_CASEFOLD 0x0010 | ||
| 153 | 154 | ||
| 154 | 155 | ||
| 155 | struct hfsplus_inode_info { | 156 | struct hfsplus_inode_info { |
| @@ -321,6 +322,7 @@ void hfsplus_file_truncate(struct inode *); | |||
| 321 | /* inode.c */ | 322 | /* inode.c */ |
| 322 | extern const struct address_space_operations hfsplus_aops; | 323 | extern const struct address_space_operations hfsplus_aops; |
| 323 | extern const struct address_space_operations hfsplus_btree_aops; | 324 | extern const struct address_space_operations hfsplus_btree_aops; |
| 325 | extern struct dentry_operations hfsplus_dentry_operations; | ||
| 324 | 326 | ||
| 325 | void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *); | 327 | void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *); |
| 326 | void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *); | 328 | void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *); |
| @@ -353,6 +355,8 @@ int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unist | |||
| 353 | int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | 355 | int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); |
| 354 | int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); | 356 | 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); | 357 | int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); |
| 358 | int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str); | ||
| 359 | int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2); | ||
| 356 | 360 | ||
| 357 | /* wrapper.c */ | 361 | /* wrapper.c */ |
| 358 | int hfsplus_read_wrapper(struct super_block *); | 362 | int hfsplus_read_wrapper(struct super_block *); |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 409ce5429c..6f7c662174 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
| @@ -131,6 +131,11 @@ const struct address_space_operations hfsplus_aops = { | |||
| 131 | .writepages = hfsplus_writepages, | 131 | .writepages = hfsplus_writepages, |
| 132 | }; | 132 | }; |
| 133 | 133 | ||
| 134 | struct dentry_operations hfsplus_dentry_operations = { | ||
| 135 | .d_hash = hfsplus_hash_dentry, | ||
| 136 | .d_compare = hfsplus_compare_dentry, | ||
| 137 | }; | ||
| 138 | |||
| 134 | static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry, | 139 | static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry, |
| 135 | struct nameidata *nd) | 140 | struct nameidata *nd) |
| 136 | { | 141 | { |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 42570c95ad..6d87a2a953 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
| @@ -380,6 +380,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
| 380 | iput(root); | 380 | iput(root); |
| 381 | goto cleanup; | 381 | goto cleanup; |
| 382 | } | 382 | } |
| 383 | sb->s_root->d_op = &hfsplus_dentry_operations; | ||
| 383 | 384 | ||
| 384 | str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; | 385 | str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; |
| 385 | str.name = HFSP_HIDDENDIR_NAME; | 386 | str.name = HFSP_HIDDENDIR_NAME; |
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index 5df0052b27..9e10f9444b 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c | |||
| @@ -314,3 +314,126 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | |||
| 314 | return -ENAMETOOLONG; | 314 | return -ENAMETOOLONG; |
| 315 | return 0; | 315 | return 0; |
| 316 | } | 316 | } |
| 317 | |||
| 318 | /* | ||
| 319 | * Hash a string to an integer as appropriate for the HFS+ filesystem. | ||
| 320 | * Composed unicode characters are decomposed and case-folding is performed | ||
| 321 | * if the appropriate bits are (un)set on the superblock. | ||
| 322 | */ | ||
| 323 | int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str) | ||
| 324 | { | ||
| 325 | struct super_block *sb = dentry->d_sb; | ||
| 326 | const char *astr; | ||
| 327 | const u16 *dstr; | ||
| 328 | int casefold, decompose, size, dsize, len; | ||
| 329 | unsigned long hash; | ||
| 330 | wchar_t c; | ||
| 331 | u16 c2; | ||
| 332 | |||
| 333 | casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD); | ||
| 334 | decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); | ||
| 335 | hash = init_name_hash(); | ||
| 336 | astr = str->name; | ||
| 337 | len = str->len; | ||
| 338 | while (len > 0) { | ||
| 339 | size = asc2unichar(sb, astr, len, &c); | ||
| 340 | astr += size; | ||
| 341 | len -= size; | ||
| 342 | |||
| 343 | if (decompose && (dstr = decompose_unichar(c, &dsize))) { | ||
| 344 | do { | ||
| 345 | c2 = *dstr++; | ||
| 346 | if (!casefold || (c2 = case_fold(c2))) | ||
| 347 | hash = partial_name_hash(c2, hash); | ||
| 348 | } while (--dsize > 0); | ||
| 349 | } else { | ||
| 350 | c2 = c; | ||
| 351 | if (!casefold || (c2 = case_fold(c2))) | ||
| 352 | hash = partial_name_hash(c2, hash); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | str->hash = end_name_hash(hash); | ||
| 356 | |||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | /* | ||
| 361 | * Compare strings with HFS+ filename ordering. | ||
| 362 | * Composed unicode characters are decomposed and case-folding is performed | ||
| 363 | * if the appropriate bits are (un)set on the superblock. | ||
| 364 | */ | ||
| 365 | int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2) | ||
| 366 | { | ||
| 367 | struct super_block *sb = dentry->d_sb; | ||
| 368 | int casefold, decompose, size; | ||
| 369 | int dsize1, dsize2, len1, len2; | ||
| 370 | const u16 *dstr1, *dstr2; | ||
| 371 | const char *astr1, *astr2; | ||
| 372 | u16 c1, c2; | ||
| 373 | wchar_t c; | ||
| 374 | |||
| 375 | casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD); | ||
| 376 | decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); | ||
| 377 | astr1 = s1->name; | ||
| 378 | len1 = s1->len; | ||
| 379 | astr2 = s2->name; | ||
| 380 | len2 = s2->len; | ||
| 381 | dsize1 = dsize2 = 0; | ||
| 382 | dstr1 = dstr2 = NULL; | ||
| 383 | |||
| 384 | while (len1 > 0 && len2 > 0) { | ||
| 385 | if (!dsize1) { | ||
| 386 | size = asc2unichar(sb, astr1, len1, &c); | ||
| 387 | astr1 += size; | ||
| 388 | len1 -= size; | ||
| 389 | |||
| 390 | if (!decompose || !(dstr1 = decompose_unichar(c, &dsize1))) { | ||
| 391 | c1 = c; | ||
| 392 | dstr1 = &c1; | ||
| 393 | dsize1 = 1; | ||
| 394 | } | ||
| 395 | } | ||
| 396 | |||
| 397 | if (!dsize2) { | ||
| 398 | size = asc2unichar(sb, astr2, len2, &c); | ||
| 399 | astr2 += size; | ||
| 400 | len2 -= size; | ||
| 401 | |||
| 402 | if (!decompose || !(dstr2 = decompose_unichar(c, &dsize2))) { | ||
| 403 | c2 = c; | ||
| 404 | dstr2 = &c2; | ||
| 405 | dsize2 = 1; | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | c1 = *dstr1; | ||
| 410 | c2 = *dstr2; | ||
| 411 | if (casefold) { | ||
| 412 | if (!(c1 = case_fold(c1))) { | ||
| 413 | dstr1++; | ||
| 414 | dsize1--; | ||
| 415 | continue; | ||
| 416 | } | ||
| 417 | if (!(c2 = case_fold(c2))) { | ||
| 418 | dstr2++; | ||
| 419 | dsize2--; | ||
| 420 | continue; | ||
| 421 | } | ||
| 422 | } | ||
| 423 | if (c1 < c2) | ||
| 424 | return -1; | ||
| 425 | else if (c1 > c2) | ||
| 426 | return 1; | ||
| 427 | |||
| 428 | dstr1++; | ||
| 429 | dsize1--; | ||
| 430 | dstr2++; | ||
| 431 | dsize2--; | ||
| 432 | } | ||
| 433 | |||
| 434 | if (len1 < len2) | ||
| 435 | return -1; | ||
| 436 | if (len1 > len2) | ||
| 437 | return 1; | ||
| 438 | return 0; | ||
| 439 | } | ||
