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 /fs/hfsplus/unicode.c | |
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>
Diffstat (limited to 'fs/hfsplus/unicode.c')
-rw-r--r-- | fs/hfsplus/unicode.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index 5df0052b277..9e10f9444b6 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 | } | ||