aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus/unicode.c
diff options
context:
space:
mode:
authorDuane Griffin <duaneg@dghda.com>2007-07-16 02:41:23 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:49 -0400
commitd45bce8faf55511ec7d7ffc301461d864d67f1af (patch)
tree1b3c33667f5cb30d3daa91ddd50a726045991d74 /fs/hfsplus/unicode.c
parent1e96b7ca1e8f17c5117da369daaa7cf2edfdf9b1 (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.c123
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 */
323int 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 */
365int 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}