[RTL]
authorPierre Schweitzer <pierre@reactos.org>
Sun, 27 Sep 2015 20:54:20 +0000 (20:54 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Sun, 27 Sep 2015 20:54:20 +0000 (20:54 +0000)
Major bugfixing session for RtlGenerate8dot3Name()... Up to know, AllowExtendedCharacters was totally ignored and any upcased char, as long as it was not in the forbidden list was accepted. This was bringing numerous problems (cf: apitest :-)).

So, now, the following fixes were brought:
- AllowExtendedCharacters isn't ignored any longer. If it's given, the unicode char is upcased, if it's not, as previously, the ansi char is upcased
- Be more strict in the allowed chars in name: only allow "graph" chars. This avoids generating broken names that aren't allowed in FAT
- In case no char could be added in the name, then, for the generation of the name checksum and use it as shortname
- When writing the checksum, don't use reversed order, but direct order, to match Windows behavior (as exposed with tests)
- When writing the checksum, use when possible bit operations instead of numerical operations for performances reasons (NFC)
- Rewrite RtlpGetCheckSum() with an algorithm that produces the exact same checksums than Windows 2003.

This whole commit fixes all apitests related (direct visible effect). As a bonus, it also fixes short names generation in FAT: we no longer produce broken volumes with international file names.
This also fixes less visible issues: we were producing unicode strings with null char in their middle (as exposed in tests), not sure about how all functions could handle this: likely not that good, this could have lead to various memory issues & corruptions.

CORE-10223 #resolve #comment Fixed with r69389

svn path=/trunk/; revision=69389

reactos/lib/rtl/dos8dot3.c

index 145dce9..75524c1 100644 (file)
@@ -30,17 +30,42 @@ RtlpIsShortIllegal(CHAR Char)
 static USHORT
 RtlpGetCheckSum(PUNICODE_STRING Name)
 {
-   USHORT Hash = 0;
-   ULONG Length;
-   PWCHAR c;
+   USHORT Hash, Saved;
+   WCHAR * CurChar;
+   USHORT Len;
 
-   Length = Name->Length / sizeof(WCHAR);
-   c = Name->Buffer;
-   while(Length--)
+   if (Name->Length == 0)
    {
-      Hash = (Hash + (*c << 4) + (*c >> 4)) * 11;
-      c++;
+      return 0;
    }
+
+   if (Name->Length == sizeof(WCHAR))
+   {
+      return Name->Buffer[0];
+   }
+
+   CurChar = Name->Buffer;
+   Hash = (*CurChar << 8) + *(CurChar + 1);
+   if (Name->Length == 2 * sizeof(WCHAR))
+   {
+      return Hash;
+   }
+
+   Saved = Hash;
+   Len = 2;
+   do
+   {
+      CurChar = CurChar + 2;
+      Hash = (Hash << 7) + *CurChar;
+      Hash = (Saved >> 1) + (Hash << 8);
+      if (Len + 1 < Name->Length / sizeof(WCHAR))
+      {
+         Hash += *(CurChar + 1);
+      }
+      Saved = Hash;
+      Len += 2;
+   } while (Len < Name->Length / sizeof(WCHAR));
+
    return Hash;
 }
 
@@ -78,7 +103,7 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
    ULONG IndexLength;
    ULONG CurrentIndex;
    USHORT Checksum;
-   CHAR c;
+   WCHAR c;
 
    StrLength = Name->Length / sizeof(WCHAR);
    DPRINT("StrLength: %lu\n", StrLength);
@@ -98,15 +123,27 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
    /* Copy name (6 valid characters max) */
    for (i = 0, NameLength = 0; NameLength < 6 && i < DotPos; i++)
    {
-      c = 0;
-      RtlUpcaseUnicodeToOemN(&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
-      if (Count != 1 || c == 0 || RtlpIsShortIllegal(c))
+      c = UNICODE_NULL;
+      if (AllowExtendedCharacters)
+      {
+          c = RtlUpcaseUnicodeChar(Name->Buffer[i]);
+          Count = 1;
+      }
+      else
+      {
+          RtlUpcaseUnicodeToOemN((CHAR *)&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
+      }
+
+      if (Count != 1 || c == UNICODE_NULL || RtlpIsShortIllegal(c))
       {
          NameBuffer[NameLength++] = L'_';
       }
-      else if (c != '.' && c != ' ')
+      else if (c != L'.' && c != L' ')
       {
-         NameBuffer[NameLength++] = (WCHAR)c;
+         if (isgraph(c) || (AllowExtendedCharacters && iswgraph(c)))
+         {
+            NameBuffer[NameLength++] = c;
+         }
       }
    }
 
@@ -118,15 +155,27 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
    {
       for (i = DotPos, ExtLength = 0; ExtLength < 4 && i < StrLength; i++)
       {
-         c = 0;
-         RtlUpcaseUnicodeToOemN(&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
-         if (Count != 1 || c == 0 || RtlpIsShortIllegal(c))
+          c = UNICODE_NULL;
+          if (AllowExtendedCharacters)
+          {
+              c = RtlUpcaseUnicodeChar(Name->Buffer[i]);
+              Count = 1;
+          }
+          else
+          {
+              RtlUpcaseUnicodeToOemN((CHAR *)&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
+          }
+
+         if (Count != 1 || c == UNICODE_NULL || RtlpIsShortIllegal(c))
          {
             ExtBuffer[ExtLength++] = L'_';
          }
-         else if (c != ' ')
+         else if (c != L' ')
          {
-            ExtBuffer[ExtLength++] = c;
+            if (isgraph(c) || c == L'.' || (AllowExtendedCharacters && iswgraph(c)))
+            {
+               ExtBuffer[ExtLength++] = c;
+            }
          }
       }
    }
@@ -171,7 +220,15 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
    else
    {
       Context->LastIndexValue = 1;
-      Context->CheckSumInserted = FALSE;
+      if (NameLength == 0)
+      {
+         Context->CheckSumInserted = TRUE;
+         Context->Checksum = RtlpGetCheckSum(Name);
+      }
+      else
+      {
+         Context->CheckSumInserted = FALSE;
+      }
    }
 
    IndexLength = RtlpGetIndexLength(Context->LastIndexValue);
@@ -192,12 +249,11 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
    j = CopyLength;
    if (Context->CheckSumInserted)
    {
-      j += 3;
       Checksum = Context->Checksum;
       for (i = 0; i < 4; i++)
       {
-         Name8dot3->Buffer[j--] = (Checksum % 16) > 9 ? (Checksum % 16) + L'A' - 10 : (Checksum % 16) + L'0';
-         Checksum /= 16;
+         Name8dot3->Buffer[j++] = (Checksum & 0xF) > 9 ? (Checksum & 0xF) + L'A' - 10 : (Checksum & 0xF) + L'0';
+         Checksum >>= 4;
       }
       j = CopyLength + 4;
    }