ntdll: Add a local helper function to check DOS 8.3 names.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
eccd21e387
commit
4a49af0cbe
|
@ -1263,11 +1263,11 @@ static BOOL is_hidden_file( const UNICODE_STRING *name )
|
||||||
* 'buffer' must be at least 12 characters long.
|
* 'buffer' must be at least 12 characters long.
|
||||||
* Returns length of short name in bytes; short name is NOT null-terminated.
|
* 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";
|
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;
|
LPWSTR dst;
|
||||||
unsigned short hash;
|
unsigned short hash;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1277,22 +1277,22 @@ static ULONG hash_short_file_name( const UNICODE_STRING *name, LPWSTR buffer )
|
||||||
/* insert a better algorithm here... */
|
/* insert a better algorithm here... */
|
||||||
if (!is_case_sensitive)
|
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) ^ (towlower(p[1]) << 8);
|
||||||
hash = (hash<<3) ^ (hash>>5) ^ towlower(*p); /* Last character */
|
hash = (hash<<3) ^ (hash>>5) ^ towlower(*p); /* Last character */
|
||||||
}
|
}
|
||||||
else
|
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 ^ (p[1] << 8);
|
||||||
hash = (hash << 3) ^ (hash >> 5) ^ *p; /* Last character */
|
hash = (hash << 3) ^ (hash >> 5) ^ *p; /* Last character */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find last dot for start of the extension */
|
/* 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 '_' */
|
/* 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;
|
if (p == end || p == ext) break;
|
||||||
*dst++ = is_invalid_dos_char(*p) ? '_' : *p;
|
*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 *
|
* *test1.txt* test1.txt *
|
||||||
* h?l?o*t.dat hellothisisatest.dat *
|
* 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;
|
BOOL mismatch;
|
||||||
const WCHAR *name = name_str->Buffer;
|
|
||||||
const WCHAR *mask = mask_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 *mask_end = mask + mask_str->Length / sizeof(WCHAR);
|
||||||
const WCHAR *lastjoker = NULL;
|
const WCHAR *lastjoker = NULL;
|
||||||
const WCHAR *next_to_retry = 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
|
* append_entry
|
||||||
*
|
*
|
||||||
|
@ -1410,16 +1441,11 @@ static BOOL append_entry( struct dir_data *data, const char *long_name,
|
||||||
int long_len, short_len;
|
int long_len, short_len;
|
||||||
WCHAR long_nameW[MAX_DIR_ENTRY_LEN + 1];
|
WCHAR long_nameW[MAX_DIR_ENTRY_LEN + 1];
|
||||||
WCHAR short_nameW[13];
|
WCHAR short_nameW[13];
|
||||||
UNICODE_STRING str;
|
|
||||||
|
|
||||||
long_len = ntdll_umbstowcs( long_name, strlen(long_name), long_nameW, ARRAY_SIZE(long_nameW) );
|
long_len = ntdll_umbstowcs( long_name, strlen(long_name), long_nameW, ARRAY_SIZE(long_nameW) );
|
||||||
if (long_len == ARRAY_SIZE(long_nameW)) return TRUE;
|
if (long_len == ARRAY_SIZE(long_nameW)) return TRUE;
|
||||||
long_nameW[long_len] = 0;
|
long_nameW[long_len] = 0;
|
||||||
|
|
||||||
str.Buffer = long_nameW;
|
|
||||||
str.Length = long_len * sizeof(WCHAR);
|
|
||||||
str.MaximumLength = sizeof(long_nameW);
|
|
||||||
|
|
||||||
if (short_name)
|
if (short_name)
|
||||||
{
|
{
|
||||||
short_len = ntdll_umbstowcs( short_name, strlen(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 */
|
else /* generate a short name if necessary */
|
||||||
{
|
{
|
||||||
BOOLEAN spaces;
|
|
||||||
|
|
||||||
short_len = 0;
|
short_len = 0;
|
||||||
if (!RtlIsNameLegalDOS8Dot3( &str, NULL, &spaces ) || spaces)
|
if (!is_legal_8dot3_name( long_nameW, long_len ))
|
||||||
short_len = hash_short_file_name( &str, short_nameW );
|
short_len = hash_short_file_name( long_nameW, long_len, short_nameW );
|
||||||
}
|
}
|
||||||
short_nameW[short_len] = 0;
|
short_nameW[short_len] = 0;
|
||||||
wcsupr( short_nameW );
|
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",
|
TRACE( "long %s short %s mask %s\n",
|
||||||
debugstr_w( long_nameW ), debugstr_w( short_nameW ), debugstr_us( mask ));
|
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 */
|
if (!short_len) return TRUE; /* no short name to match */
|
||||||
str.Buffer = short_nameW;
|
if (!match_filename( short_nameW, short_len, mask )) return TRUE;
|
||||||
str.Length = short_len * sizeof(WCHAR);
|
|
||||||
str.MaximumLength = sizeof(short_nameW);
|
|
||||||
if (!match_filename( &str, mask )) return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return add_dir_data_names( data, long_nameW, short_nameW, long_name );
|
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 )
|
BOOLEAN check_case, BOOLEAN *is_win_dir )
|
||||||
{
|
{
|
||||||
WCHAR buffer[MAX_DIR_ENTRY_LEN];
|
WCHAR buffer[MAX_DIR_ENTRY_LEN];
|
||||||
UNICODE_STRING str;
|
BOOLEAN is_name_8_dot_3;
|
||||||
BOOLEAN spaces, is_name_8_dot_3;
|
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
struct stat st;
|
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 */
|
/* 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;
|
is_name_8_dot_3 = is_legal_8dot3_name( name, length );
|
||||||
str.Length = length * sizeof(WCHAR);
|
|
||||||
str.MaximumLength = str.Length;
|
|
||||||
is_name_8_dot_3 = RtlIsNameLegalDOS8Dot3( &str, NULL, &spaces ) && !spaces;
|
|
||||||
#ifndef VFAT_IOCTL_READDIR_BOTH
|
#ifndef VFAT_IOCTL_READDIR_BOTH
|
||||||
is_name_8_dot_3 = is_name_8_dot_3 && length >= 8 && name[4] == '~';
|
is_name_8_dot_3 = is_name_8_dot_3 && length >= 8 && name[4] == '~';
|
||||||
#endif
|
#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;
|
else return STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
unix_name[pos - 1] = '/';
|
unix_name[pos - 1] = '/';
|
||||||
str.Buffer = buffer;
|
|
||||||
str.MaximumLength = sizeof(buffer);
|
|
||||||
while ((de = readdir( dir )))
|
while ((de = readdir( dir )))
|
||||||
{
|
{
|
||||||
ret = ntdll_umbstowcs( de->d_name, strlen(de->d_name), buffer, MAX_DIR_ENTRY_LEN );
|
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;
|
if (!is_name_8_dot_3) continue;
|
||||||
|
|
||||||
str.Length = ret * sizeof(WCHAR);
|
if (!is_legal_8dot3_name( buffer, ret ))
|
||||||
if (!RtlIsNameLegalDOS8Dot3( &str, NULL, &spaces ) || spaces)
|
|
||||||
{
|
{
|
||||||
WCHAR short_nameW[12];
|
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 ))
|
if (ret == length && !wcsnicmp( short_nameW, name, length ))
|
||||||
{
|
{
|
||||||
strcpy( unix_name + pos, de->d_name );
|
strcpy( unix_name + pos, de->d_name );
|
||||||
|
|
Loading…
Reference in New Issue