upcase.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. *
  4. * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
  5. *
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/types.h>
  9. #include "ntfs_fs.h"
  10. static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr)
  11. {
  12. if (chr < 'a')
  13. return chr;
  14. if (chr <= 'z')
  15. return chr - ('a' - 'A');
  16. return upcase[chr];
  17. }
  18. /*
  19. * ntfs_cmp_names
  20. *
  21. * Thanks Kari Argillander <kari.argillander@gmail.com> for idea and implementation 'bothcase'
  22. *
  23. * Straight way to compare names:
  24. * - Case insensitive
  25. * - If name equals and 'bothcases' then
  26. * - Case sensitive
  27. * 'Straight way' code scans input names twice in worst case.
  28. * Optimized code scans input names only once.
  29. */
  30. int ntfs_cmp_names(const __le16 *s1, size_t l1, const __le16 *s2, size_t l2,
  31. const u16 *upcase, bool bothcase)
  32. {
  33. int diff1 = 0;
  34. int diff2;
  35. size_t len = min(l1, l2);
  36. if (!bothcase && upcase)
  37. goto case_insentive;
  38. for (; len; s1++, s2++, len--) {
  39. diff1 = le16_to_cpu(*s1) - le16_to_cpu(*s2);
  40. if (diff1) {
  41. if (bothcase && upcase)
  42. goto case_insentive;
  43. return diff1;
  44. }
  45. }
  46. return l1 - l2;
  47. case_insentive:
  48. for (; len; s1++, s2++, len--) {
  49. diff2 = upcase_unicode_char(upcase, le16_to_cpu(*s1)) -
  50. upcase_unicode_char(upcase, le16_to_cpu(*s2));
  51. if (diff2)
  52. return diff2;
  53. }
  54. diff2 = l1 - l2;
  55. return diff2 ? diff2 : diff1;
  56. }
  57. int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2,
  58. const u16 *upcase, bool bothcase)
  59. {
  60. const u16 *s1 = uni1->name;
  61. const __le16 *s2 = uni2->name;
  62. size_t l1 = uni1->len;
  63. size_t l2 = uni2->len;
  64. size_t len = min(l1, l2);
  65. int diff1 = 0;
  66. int diff2;
  67. if (!bothcase && upcase)
  68. goto case_insentive;
  69. for (; len; s1++, s2++, len--) {
  70. diff1 = *s1 - le16_to_cpu(*s2);
  71. if (diff1) {
  72. if (bothcase && upcase)
  73. goto case_insentive;
  74. return diff1;
  75. }
  76. }
  77. return l1 - l2;
  78. case_insentive:
  79. for (; len; s1++, s2++, len--) {
  80. diff2 = upcase_unicode_char(upcase, *s1) -
  81. upcase_unicode_char(upcase, le16_to_cpu(*s2));
  82. if (diff2)
  83. return diff2;
  84. }
  85. diff2 = l1 - l2;
  86. return diff2 ? diff2 : diff1;
  87. }
  88. /* Helper function for ntfs_d_hash. */
  89. unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase,
  90. unsigned long hash)
  91. {
  92. while (len--) {
  93. unsigned int c = upcase_unicode_char(upcase, *name++);
  94. hash = partial_name_hash(c, hash);
  95. }
  96. return hash;
  97. }