diff options
author | Duane Griffin <duaneg@dghda.com> | 2007-07-16 02:41:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 12:05:49 -0400 |
commit | d45bce8faf55511ec7d7ffc301461d864d67f1af (patch) | |
tree | 1b3c33667f5cb30d3daa91ddd50a726045991d74 | |
parent | 1e96b7ca1e8f17c5117da369daaa7cf2edfdf9b1 (diff) |
HFS+: add custom dentry hash and comparison operations
Add custom dentry hash and comparison operations for HFS+ filesystems that are
case-insensitive and/or do automatic unicode decomposition. The new
operations reuse the existing HFS+ ASCII to unicode conversion, unicode
decomposition and case folding functionality.
Signed-off-by: Duane Griffin <duaneg@dghda.com>
Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-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 90ebab753d30..050d29c0a5b5 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 80b5682a2273..1955ee61251c 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 3915635b4470..d9f5eda6d039 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 409ce5429c91..6f7c662174db 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 42570c95ad62..6d87a2a9534d 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 5df0052b2775..9e10f9444b64 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 | } | ||