Alexandre Julliard : ntdll: Add a local helper function to check DOS 8.3 names.

Alexandre Julliard julliard at winehq.org
Fri Jul 10 16:30:30 CDT 2020


Module: wine
Branch: master
Commit: 4a49af0cbeb1bb5570d92f679c98ad05abc693e6
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=4a49af0cbeb1bb5570d92f679c98ad05abc693e6

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri Jul 10 07:56:39 2020 +0200

ntdll: Add a local helper function to check DOS 8.3 names.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/unix/file.c | 82 +++++++++++++++++++++++++++++---------------------
 1 file changed, 48 insertions(+), 34 deletions(-)

diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index e985c75a41..b4c9b75b3e 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -1263,11 +1263,11 @@ static BOOL is_hidden_file( const UNICODE_STRING *name )
  * 'buffer' must be at least 12 characters long.
  * Returns length of short name in bytes; short name is NOT null-terminated.
  */
-static ULONG hash_short_file_name( const UNICODE_STRING *name, LPWSTR buffer )
+static ULONG hash_short_file_name( const WCHAR *name, int length, LPWSTR buffer )
 {
     static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
 
-    LPCWSTR p, ext, end = name->Buffer + name->Length / sizeof(WCHAR);
+    LPCWSTR p, ext, end = name + length;
     LPWSTR dst;
     unsigned short hash;
     int i;
@@ -1277,22 +1277,22 @@ static ULONG hash_short_file_name( const UNICODE_STRING *name, LPWSTR buffer )
     /* insert a better algorithm here... */
     if (!is_case_sensitive)
     {
-        for (p = name->Buffer, hash = 0xbeef; p < end - 1; p++)
+        for (p = name, hash = 0xbeef; p < end - 1; p++)
             hash = (hash<<3) ^ (hash>>5) ^ towlower(*p) ^ (towlower(p[1]) << 8);
         hash = (hash<<3) ^ (hash>>5) ^ towlower(*p); /* Last character */
     }
     else
     {
-        for (p = name->Buffer, hash = 0xbeef; p < end - 1; p++)
+        for (p = name, hash = 0xbeef; p < end - 1; p++)
             hash = (hash << 3) ^ (hash >> 5) ^ *p ^ (p[1] << 8);
         hash = (hash << 3) ^ (hash >> 5) ^ *p;  /* Last character */
     }
 
     /* Find last dot for start of the extension */
-    for (p = name->Buffer + 1, ext = NULL; p < end - 1; p++) if (*p == '.') ext = p;
+    for (p = name + 1, ext = NULL; p < end - 1; p++) if (*p == '.') ext = p;
 
     /* Copy first 4 chars, replacing invalid chars with '_' */
-    for (i = 4, p = name->Buffer, dst = buffer; i > 0; i--, p++)
+    for (i = 4, p = name, dst = buffer; i > 0; i--, p++)
     {
         if (p == end || p == ext) break;
         *dst++ = is_invalid_dos_char(*p) ? '_' : *p;
@@ -1332,12 +1332,11 @@ static ULONG hash_short_file_name( const UNICODE_STRING *name, LPWSTR buffer )
  * *test1.txt*			test1.txt				*
  * h?l?o*t.dat			hellothisisatest.dat			*
  */
-static BOOLEAN match_filename( const UNICODE_STRING *name_str, const UNICODE_STRING *mask_str )
+static BOOLEAN match_filename( const WCHAR *name, int length, const UNICODE_STRING *mask_str )
 {
     BOOL mismatch;
-    const WCHAR *name = name_str->Buffer;
     const WCHAR *mask = mask_str->Buffer;
-    const WCHAR *name_end = name + name_str->Length / sizeof(WCHAR);
+    const WCHAR *name_end = name + length;
     const WCHAR *mask_end = mask + mask_str->Length / sizeof(WCHAR);
     const WCHAR *lastjoker = NULL;
     const WCHAR *next_to_retry = NULL;
@@ -1399,6 +1398,38 @@ static BOOLEAN match_filename( const UNICODE_STRING *name_str, const UNICODE_STR
 }
 
 
+/***********************************************************************
+ *           is_legal_8dot3_name
+ *
+ * Simplified version of RtlIsNameLegalDOS8Dot3.
+ */
+static BOOLEAN is_legal_8dot3_name( const WCHAR *name, int len )
+{
+    static const WCHAR invalid_chars[] = { INVALID_DOS_CHARS,':','/','\\',0 };
+    int i, dot = -1;
+
+    if (len > 12) return FALSE;
+
+    /* a starting . is invalid, except for . and .. */
+    if (len > 0 && name[0] == '.') return (len == 1 || (len == 2 && name[1] == '.'));
+
+    for (i = 0; i < len; i++)
+    {
+        if (name[i] > 0x7f) return FALSE;
+        if (wcschr( invalid_chars, name[i] )) return FALSE;
+        if (name[i] == '.')
+        {
+            if (dot != -1) return FALSE;
+            dot = i;
+        }
+    }
+
+    if (dot == -1) return (len <= 8);
+    if (dot > 8) return FALSE;
+    return (len - dot > 1 && len - dot < 5);
+}
+
+
 /***********************************************************************
  *           append_entry
  *
@@ -1410,16 +1441,11 @@ static BOOL append_entry( struct dir_data *data, const char *long_name,
     int long_len, short_len;
     WCHAR long_nameW[MAX_DIR_ENTRY_LEN + 1];
     WCHAR short_nameW[13];
-    UNICODE_STRING str;
 
     long_len = ntdll_umbstowcs( long_name, strlen(long_name), long_nameW, ARRAY_SIZE(long_nameW) );
     if (long_len == ARRAY_SIZE(long_nameW)) return TRUE;
     long_nameW[long_len] = 0;
 
-    str.Buffer = long_nameW;
-    str.Length = long_len * sizeof(WCHAR);
-    str.MaximumLength = sizeof(long_nameW);
-
     if (short_name)
     {
         short_len = ntdll_umbstowcs( short_name, strlen(short_name),
@@ -1427,11 +1453,9 @@ static BOOL append_entry( struct dir_data *data, const char *long_name,
     }
     else  /* generate a short name if necessary */
     {
-        BOOLEAN spaces;
-
         short_len = 0;
-        if (!RtlIsNameLegalDOS8Dot3( &str, NULL, &spaces ) || spaces)
-            short_len = hash_short_file_name( &str, short_nameW );
+        if (!is_legal_8dot3_name( long_nameW, long_len ))
+            short_len = hash_short_file_name( long_nameW, long_len, short_nameW );
     }
     short_nameW[short_len] = 0;
     wcsupr( short_nameW );
@@ -1439,13 +1463,10 @@ static BOOL append_entry( struct dir_data *data, const char *long_name,
     TRACE( "long %s short %s mask %s\n",
            debugstr_w( long_nameW ), debugstr_w( short_nameW ), debugstr_us( mask ));
 
-    if (mask && !match_filename( &str, mask ))
+    if (mask && !match_filename( long_nameW, long_len, mask ))
     {
         if (!short_len) return TRUE;  /* no short name to match */
-        str.Buffer = short_nameW;
-        str.Length = short_len * sizeof(WCHAR);
-        str.MaximumLength = sizeof(short_nameW);
-        if (!match_filename( &str, mask )) return TRUE;
+        if (!match_filename( short_nameW, short_len, mask )) return TRUE;
     }
 
     return add_dir_data_names( data, long_nameW, short_nameW, long_name );
@@ -2496,8 +2517,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
                                   BOOLEAN check_case, BOOLEAN *is_win_dir )
 {
     WCHAR buffer[MAX_DIR_ENTRY_LEN];
-    UNICODE_STRING str;
-    BOOLEAN spaces, is_name_8_dot_3;
+    BOOLEAN is_name_8_dot_3;
     DIR *dir;
     struct dirent *de;
     struct stat st;
@@ -2523,10 +2543,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
 
     /* check if it fits in 8.3 so that we don't look for short names if we won't need them */
 
-    str.Buffer = (WCHAR *)name;
-    str.Length = length * sizeof(WCHAR);
-    str.MaximumLength = str.Length;
-    is_name_8_dot_3 = RtlIsNameLegalDOS8Dot3( &str, NULL, &spaces ) && !spaces;
+    is_name_8_dot_3 = is_legal_8dot3_name( name, length );
 #ifndef VFAT_IOCTL_READDIR_BOTH
     is_name_8_dot_3 = is_name_8_dot_3 && length >= 8 && name[4] == '~';
 #endif
@@ -2587,8 +2604,6 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
         else return STATUS_ACCESS_DENIED;
     }
     unix_name[pos - 1] = '/';
-    str.Buffer = buffer;
-    str.MaximumLength = sizeof(buffer);
     while ((de = readdir( dir )))
     {
         ret = ntdll_umbstowcs( de->d_name, strlen(de->d_name), buffer, MAX_DIR_ENTRY_LEN );
@@ -2601,11 +2616,10 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
 
         if (!is_name_8_dot_3) continue;
 
-        str.Length = ret * sizeof(WCHAR);
-        if (!RtlIsNameLegalDOS8Dot3( &str, NULL, &spaces ) || spaces)
+        if (!is_legal_8dot3_name( buffer, ret ))
         {
             WCHAR short_nameW[12];
-            ret = hash_short_file_name( &str, short_nameW );
+            ret = hash_short_file_name( buffer, ret, short_nameW );
             if (ret == length && !wcsnicmp( short_nameW, name, length ))
             {
                 strcpy( unix_name + pos, de->d_name );




More information about the wine-cvs mailing list