|
|
6a74ba |
From d5a522c0bb738efdd7cc1e762840b579fc9ea3de Mon Sep 17 00:00:00 2001
|
|
|
6a74ba |
From: Laszlo Ersek <lersek@redhat.com>
|
|
|
6a74ba |
Date: Fri, 10 Sep 2021 01:06:17 +0200
|
|
|
6a74ba |
Subject: [PATCH] lib: write: improve key collation compatibility with Windows
|
|
|
6a74ba |
|
|
|
6a74ba |
There are multiple problems with using strcasecmp() for ordering registry
|
|
|
6a74ba |
keys:
|
|
|
6a74ba |
|
|
|
6a74ba |
(1) strcasecmp() is influenced by LC_CTYPE.
|
|
|
6a74ba |
|
|
|
6a74ba |
(2) strcasecmp() cannot implement case conversion for multibyte UTF-8
|
|
|
6a74ba |
sequences.
|
|
|
6a74ba |
|
|
|
6a74ba |
(3) Even with LC_CTYPE=POSIX and key names consisting solely of ASCII
|
|
|
6a74ba |
characters, strcasecmp() converts characters to lowercase, for
|
|
|
6a74ba |
comparison. But on Windows, the CompareStringOrdinal() function
|
|
|
6a74ba |
converts characters to uppercase. This makes a difference when
|
|
|
6a74ba |
comparing a letter to one of the characters that fall between 'Z'
|
|
|
6a74ba |
(0x5A) and 'a' (0x61), namely {'[', '\\', ']', '^', '_', '`'}. For
|
|
|
6a74ba |
example,
|
|
|
6a74ba |
|
|
|
6a74ba |
'c' (0x63) > '_' (0x5F)
|
|
|
6a74ba |
'C' (0x43) < '_' (0x5F)
|
|
|
6a74ba |
|
|
|
6a74ba |
Compare key names byte for byte, eliminating problems (1) and (3).
|
|
|
6a74ba |
|
|
|
6a74ba |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1648520
|
|
|
6a74ba |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
6a74ba |
Message-Id: <20210909230617.31256-1-lersek@redhat.com>
|
|
|
6a74ba |
Acked-by: Richard W.M. Jones <rjones@redhat.com>
|
|
|
6a74ba |
---
|
|
|
6a74ba |
lib/write.c | 32 +++++++++++++++++++++++++++++++-
|
|
|
6a74ba |
1 file changed, 31 insertions(+), 1 deletion(-)
|
|
|
6a74ba |
|
|
|
6a74ba |
diff --git a/lib/write.c b/lib/write.c
|
|
|
6a74ba |
index 70105c9d9907..d9a13a3c18b6 100644
|
|
|
6a74ba |
--- a/lib/write.c
|
|
|
6a74ba |
+++ b/lib/write.c
|
|
|
6a74ba |
@@ -462,7 +462,37 @@ compare_name_with_nk_name (hive_h *h, const char *name, hive_node_h nk_offs)
|
|
|
6a74ba |
return 0;
|
|
|
6a74ba |
}
|
|
|
6a74ba |
|
|
|
6a74ba |
- int r = strcasecmp (name, nname);
|
|
|
6a74ba |
+ /* Perform a limited case-insensitive comparison. ASCII letters will be
|
|
|
6a74ba |
+ * *upper-cased*. Multibyte sequences will produce nonsensical orderings.
|
|
|
6a74ba |
+ */
|
|
|
6a74ba |
+ int r = 0;
|
|
|
6a74ba |
+ const char *s1 = name;
|
|
|
6a74ba |
+ const char *s2 = nname;
|
|
|
6a74ba |
+
|
|
|
6a74ba |
+ for (;;) {
|
|
|
6a74ba |
+ unsigned char c1 = *(s1++);
|
|
|
6a74ba |
+ unsigned char c2 = *(s2++);
|
|
|
6a74ba |
+
|
|
|
6a74ba |
+ if (c1 >= 'a' && c1 <= 'z')
|
|
|
6a74ba |
+ c1 = 'A' + (c1 - 'a');
|
|
|
6a74ba |
+ if (c2 >= 'a' && c2 <= 'z')
|
|
|
6a74ba |
+ c2 = 'A' + (c2 - 'a');
|
|
|
6a74ba |
+ if (c1 < c2) {
|
|
|
6a74ba |
+ /* Also covers the case when "name" is a prefix of "nname". */
|
|
|
6a74ba |
+ r = -1;
|
|
|
6a74ba |
+ break;
|
|
|
6a74ba |
+ }
|
|
|
6a74ba |
+ if (c1 > c2) {
|
|
|
6a74ba |
+ /* Also covers the case when "nname" is a prefix of "name". */
|
|
|
6a74ba |
+ r = 1;
|
|
|
6a74ba |
+ break;
|
|
|
6a74ba |
+ }
|
|
|
6a74ba |
+ if (c1 == '\0') {
|
|
|
6a74ba |
+ /* Both strings end. */
|
|
|
6a74ba |
+ break;
|
|
|
6a74ba |
+ }
|
|
|
6a74ba |
+ }
|
|
|
6a74ba |
+
|
|
|
6a74ba |
free (nname);
|
|
|
6a74ba |
|
|
|
6a74ba |
return r;
|
|
|
6a74ba |
--
|
|
|
6a74ba |
2.19.1.3.g30247aa5d201
|
|
|
6a74ba |
|