ntdll: Reject NT path names that are not in canonical form.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
302d44004e
commit
405666b736
|
@ -31,6 +31,7 @@ static BOOLEAN (WINAPI *pRtlIsNameLegalDOS8Dot3)(const UNICODE_STRING*,POEM_STRI
|
||||||
static DWORD (WINAPI *pRtlGetFullPathName_U)(const WCHAR*,ULONG,WCHAR*,WCHAR**);
|
static DWORD (WINAPI *pRtlGetFullPathName_U)(const WCHAR*,ULONG,WCHAR*,WCHAR**);
|
||||||
static BOOLEAN (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR*, UNICODE_STRING*, WCHAR**, CURDIR*);
|
static BOOLEAN (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR*, UNICODE_STRING*, WCHAR**, CURDIR*);
|
||||||
static NTSTATUS (WINAPI *pRtlDosPathNameToNtPathName_U_WithStatus)(const WCHAR*, UNICODE_STRING*, WCHAR**, CURDIR*);
|
static NTSTATUS (WINAPI *pRtlDosPathNameToNtPathName_U_WithStatus)(const WCHAR*, UNICODE_STRING*, WCHAR**, CURDIR*);
|
||||||
|
static NTSTATUS (WINAPI *pNtOpenFile)( HANDLE*, ACCESS_MASK, OBJECT_ATTRIBUTES*, IO_STATUS_BLOCK*, ULONG, ULONG );
|
||||||
|
|
||||||
static void test_RtlDetermineDosPathNameType_U(void)
|
static void test_RtlDetermineDosPathNameType_U(void)
|
||||||
{
|
{
|
||||||
|
@ -619,6 +620,95 @@ static void test_RtlDosPathNameToNtPathName_U(void)
|
||||||
SetCurrentDirectoryA(curdir);
|
SetCurrentDirectoryA(curdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_nt_names(void)
|
||||||
|
{
|
||||||
|
static const struct { const WCHAR *root, *name; NTSTATUS expect; BOOL todo; } tests[] =
|
||||||
|
{
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll", STATUS_SUCCESS },
|
||||||
|
{ NULL, L"\\??\\C:\\\\windows\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ NULL, L"\\??\\C:\\\\windows\\system32\\", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\system32\\.\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\system32\\..\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ NULL, L"\\??\\C:\\.\\windows\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll ", STATUS_OBJECT_NAME_NOT_FOUND },
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll..", STATUS_OBJECT_NAME_NOT_FOUND },
|
||||||
|
{ NULL, L"\\??\\C:\\windows \\system32 \\kernel32.dll", STATUS_OBJECT_PATH_NOT_FOUND },
|
||||||
|
{ NULL, L"\\??\\C:\\windows.\\system32.\\kernel32.dll", STATUS_OBJECT_PATH_NOT_FOUND },
|
||||||
|
{ NULL, L"\\??\\C:\\windows/system32/kernel32.dll", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll*", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\system32?\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ NULL, L"C:\\windows\\system32?\\kernel32.dll", STATUS_OBJECT_PATH_SYNTAX_BAD },
|
||||||
|
{ NULL, L"/??\\C:\\windows\\system32\\kernel32.dll", STATUS_OBJECT_PATH_SYNTAX_BAD },
|
||||||
|
{ NULL, L"\\??" L"/C:\\windows\\system32\\kernel32.dll", STATUS_OBJECT_PATH_NOT_FOUND },
|
||||||
|
{ NULL, L"\\??\\C:/windows\\system32\\kernel32.dll", STATUS_OBJECT_PATH_NOT_FOUND },
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll\\", STATUS_OBJECT_NAME_INVALID, TRUE },
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll\\foo", STATUS_OBJECT_PATH_NOT_FOUND, TRUE },
|
||||||
|
{ NULL, L"\\??\\C:\\windows\\sys\001", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\", NULL, STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\C:\\", NULL, STATUS_SUCCESS },
|
||||||
|
{ L"\\??\\C:\\\\", NULL, STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"/??\\C:\\", NULL, STATUS_OBJECT_PATH_SYNTAX_BAD },
|
||||||
|
{ L"\\??\\C:/", NULL, STATUS_OBJECT_NAME_NOT_FOUND },
|
||||||
|
{ L"\\??" L"/C:", NULL, STATUS_OBJECT_NAME_NOT_FOUND },
|
||||||
|
{ L"\\??" L"/C:\\", NULL, STATUS_OBJECT_PATH_NOT_FOUND },
|
||||||
|
{ L"\\??\\C:\\windows", NULL, STATUS_SUCCESS },
|
||||||
|
{ L"\\??\\C:\\windows\\", NULL, STATUS_SUCCESS },
|
||||||
|
{ L"\\??\\C:\\windows\\.", NULL, STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\C:\\windows\\.\\", NULL, STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\C:\\windows\\..", NULL, STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\C:\\windows\\..\\", NULL, STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\C:\\", L"windows\\system32\\kernel32.dll", STATUS_SUCCESS },
|
||||||
|
{ L"\\??\\C:\\windows", L"system32\\kernel32.dll", STATUS_SUCCESS },
|
||||||
|
{ L"\\??\\C:\\windows\\", L"system32\\kernel32.dll", STATUS_SUCCESS },
|
||||||
|
{ L"\\??\\C:\\windows\\", L"system32\\", STATUS_FILE_IS_A_DIRECTORY },
|
||||||
|
{ L"\\??\\C:\\windows\\", L"system32\\kernel32.dll\\", STATUS_OBJECT_NAME_INVALID, TRUE },
|
||||||
|
{ L"\\??\\C:\\windows\\", L"system32\\kernel32.dll\\foo", STATUS_OBJECT_PATH_NOT_FOUND, TRUE },
|
||||||
|
{ L"\\??\\C:\\windows\\", L"\\system32\\kernel32.dll", STATUS_INVALID_PARAMETER },
|
||||||
|
{ L"\\??\\C:\\windows\\", L"/system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\C:\\windows\\", L".\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\C:\\windows\\", L"..\\windows\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\C:\\windows\\", L".", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\C:\\windows\\", L"..", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"\\??\\C:\\windows\\", L"sys\001", STATUS_OBJECT_NAME_INVALID },
|
||||||
|
{ L"C:\\", L"windows\\system32\\kernel32.dll", STATUS_OBJECT_PATH_SYNTAX_BAD },
|
||||||
|
};
|
||||||
|
unsigned int i;
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
UNICODE_STRING nameW;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
NTSTATUS status;
|
||||||
|
HANDLE handle;
|
||||||
|
|
||||||
|
InitializeObjectAttributes( &attr, &nameW, OBJ_CASE_INSENSITIVE, 0, NULL );
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(tests); i++)
|
||||||
|
{
|
||||||
|
attr.RootDirectory = 0;
|
||||||
|
handle = 0;
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
if (tests[i].root)
|
||||||
|
{
|
||||||
|
RtlInitUnicodeString( &nameW, tests[i].root );
|
||||||
|
status = pNtOpenFile( &attr.RootDirectory, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io,
|
||||||
|
FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT |
|
||||||
|
FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE );
|
||||||
|
}
|
||||||
|
if (!status && tests[i].name)
|
||||||
|
{
|
||||||
|
RtlInitUnicodeString( &nameW, tests[i].name );
|
||||||
|
status = pNtOpenFile( &handle, FILE_GENERIC_READ, &attr, &io, FILE_SHARE_READ,
|
||||||
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE );
|
||||||
|
}
|
||||||
|
if (attr.RootDirectory) NtClose( attr.RootDirectory );
|
||||||
|
if (handle) NtClose( handle );
|
||||||
|
todo_wine_if( tests[i].todo )
|
||||||
|
ok( status == tests[i].expect, "%u: got %x / %x for %s + %s\n", i, status, tests[i].expect,
|
||||||
|
debugstr_w( tests[i].root ), debugstr_w( tests[i].name ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
START_TEST(path)
|
START_TEST(path)
|
||||||
{
|
{
|
||||||
HMODULE mod = GetModuleHandleA("ntdll.dll");
|
HMODULE mod = GetModuleHandleA("ntdll.dll");
|
||||||
|
@ -632,10 +722,12 @@ START_TEST(path)
|
||||||
pRtlGetFullPathName_U = (void *)GetProcAddress(mod,"RtlGetFullPathName_U");
|
pRtlGetFullPathName_U = (void *)GetProcAddress(mod,"RtlGetFullPathName_U");
|
||||||
pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U");
|
pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U");
|
||||||
pRtlDosPathNameToNtPathName_U_WithStatus = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U_WithStatus");
|
pRtlDosPathNameToNtPathName_U_WithStatus = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U_WithStatus");
|
||||||
|
pNtOpenFile = (void *)GetProcAddress(mod, "NtOpenFile");
|
||||||
|
|
||||||
test_RtlDetermineDosPathNameType_U();
|
test_RtlDetermineDosPathNameType_U();
|
||||||
test_RtlIsDosDeviceName_U();
|
test_RtlIsDosDeviceName_U();
|
||||||
test_RtlIsNameLegalDOS8Dot3();
|
test_RtlIsNameLegalDOS8Dot3();
|
||||||
test_RtlGetFullPathName_U();
|
test_RtlGetFullPathName_U();
|
||||||
test_RtlDosPathNameToNtPathName_U();
|
test_RtlDosPathNameToNtPathName_U();
|
||||||
|
test_nt_names();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1228,13 +1228,9 @@ static BOOL is_hidden_file( const UNICODE_STRING *name )
|
||||||
if (show_dot_files) return FALSE;
|
if (show_dot_files) return FALSE;
|
||||||
|
|
||||||
end = p = name->Buffer + name->Length/sizeof(WCHAR);
|
end = p = name->Buffer + name->Length/sizeof(WCHAR);
|
||||||
while (p > name->Buffer && IS_SEPARATOR(p[-1])) p--;
|
while (p > name->Buffer && p[-1] == '\\') p--;
|
||||||
while (p > name->Buffer && !IS_SEPARATOR(p[-1])) p--;
|
while (p > name->Buffer && p[-1] != '\\') p--;
|
||||||
if (p == end || *p != '.') return FALSE;
|
return (p < end && *p == '.');
|
||||||
/* make sure it isn't '.' or '..' */
|
|
||||||
if (p + 1 == end) return FALSE;
|
|
||||||
if (p[1] == '.' && p + 2 == end) return FALSE;
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2779,6 +2775,8 @@ static NTSTATUS get_dos_device( char **unix_name, int start_pos )
|
||||||
/* special case for drive devices */
|
/* special case for drive devices */
|
||||||
if (dev[0] && dev[1] == ':' && !dev[2]) strcpy( dev + 1, "::" );
|
if (dev[0] && dev[1] == ':' && !dev[2]) strcpy( dev + 1, "::" );
|
||||||
|
|
||||||
|
if (strchr( dev, '/' )) goto failed;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (!stat( *unix_name, &st ))
|
if (!stat( *unix_name, &st ))
|
||||||
|
@ -2811,6 +2809,7 @@ static NTSTATUS get_dos_device( char **unix_name, int start_pos )
|
||||||
if (!new_name) return STATUS_BAD_DEVICE_TYPE;
|
if (!new_name) return STATUS_BAD_DEVICE_TYPE;
|
||||||
dev = NULL; /* last try */
|
dev = NULL; /* last try */
|
||||||
}
|
}
|
||||||
|
failed:
|
||||||
free( *unix_name );
|
free( *unix_name );
|
||||||
*unix_name = NULL;
|
*unix_name = NULL;
|
||||||
return STATUS_BAD_DEVICE_TYPE;
|
return STATUS_BAD_DEVICE_TYPE;
|
||||||
|
@ -3090,21 +3089,41 @@ done:
|
||||||
* Helper for nt_to_unix_file_name
|
* Helper for nt_to_unix_file_name
|
||||||
*/
|
*/
|
||||||
static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer, int unix_len, int pos,
|
static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer, int unix_len, int pos,
|
||||||
UINT disposition, BOOLEAN check_case )
|
UINT disposition, BOOL is_unix )
|
||||||
{
|
{
|
||||||
|
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, '/', 0 };
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
int ret, len;
|
int ret, len;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *unix_name = *buffer;
|
char *unix_name = *buffer;
|
||||||
|
const WCHAR *ptr, *end;
|
||||||
const BOOL redirect = NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR];
|
const BOOL redirect = NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR];
|
||||||
|
|
||||||
/* try a shortcut first */
|
/* check syntax of individual components */
|
||||||
|
|
||||||
while (name_len && IS_SEPARATOR(*name))
|
for (ptr = name, end = name + name_len; ptr < end; ptr++)
|
||||||
{
|
{
|
||||||
name++;
|
if (*ptr == '\\') return STATUS_OBJECT_NAME_INVALID; /* duplicate backslash */
|
||||||
name_len--;
|
if (*ptr == '.')
|
||||||
|
{
|
||||||
|
if (ptr + 1 == end) return STATUS_OBJECT_NAME_INVALID; /* "." element */
|
||||||
|
if (ptr[1] == '\\') return STATUS_OBJECT_NAME_INVALID; /* "." element */
|
||||||
|
if (ptr[1] == '.')
|
||||||
|
{
|
||||||
|
if (ptr + 2 == end) return STATUS_OBJECT_NAME_INVALID; /* ".." element */
|
||||||
|
if (ptr[2] == '\\') return STATUS_OBJECT_NAME_INVALID; /* ".." element */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/* check for invalid characters (all chars except 0 are valid for unix) */
|
||||||
|
for ( ; ptr < end && *ptr != '\\'; ptr++)
|
||||||
|
{
|
||||||
|
if (!*ptr) return STATUS_OBJECT_NAME_INVALID;
|
||||||
|
if (is_unix) continue;
|
||||||
|
if (*ptr < 32 || wcschr( invalid_charsW, *ptr )) return STATUS_OBJECT_NAME_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try a shortcut first */
|
||||||
|
|
||||||
unix_name[pos] = '/';
|
unix_name[pos] = '/';
|
||||||
ret = ntdll_wcstoumbs( name, name_len, unix_name + pos + 1, unix_len - pos - 1, TRUE );
|
ret = ntdll_wcstoumbs( name, name_len, unix_name + pos + 1, unix_len - pos - 1, TRUE );
|
||||||
|
@ -3126,7 +3145,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
|
||||||
|
|
||||||
if (!name_len) /* empty name -> drive root doesn't exist */
|
if (!name_len) /* empty name -> drive root doesn't exist */
|
||||||
return STATUS_OBJECT_PATH_NOT_FOUND;
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
if (check_case && !redirect && (disposition == FILE_OPEN || disposition == FILE_OVERWRITE))
|
if (is_unix && !redirect && (disposition == FILE_OPEN || disposition == FILE_OVERWRITE))
|
||||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
|
||||||
/* now do it component by component */
|
/* now do it component by component */
|
||||||
|
@ -3137,9 +3156,9 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
|
||||||
BOOLEAN is_win_dir = FALSE;
|
BOOLEAN is_win_dir = FALSE;
|
||||||
|
|
||||||
end = name;
|
end = name;
|
||||||
while (end < name + name_len && !IS_SEPARATOR(*end)) end++;
|
while (end < name + name_len && *end != '\\') end++;
|
||||||
next = end;
|
next = end;
|
||||||
while (next < name + name_len && IS_SEPARATOR(*next)) next++;
|
if (next < name + name_len) next++;
|
||||||
name_len -= next - name;
|
name_len -= next - name;
|
||||||
|
|
||||||
/* grow the buffer if needed */
|
/* grow the buffer if needed */
|
||||||
|
@ -3153,7 +3172,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
status = find_file_in_dir( unix_name, pos, name, end - name,
|
status = find_file_in_dir( unix_name, pos, name, end - name,
|
||||||
check_case, redirect ? &is_win_dir : NULL );
|
is_unix, redirect ? &is_win_dir : NULL );
|
||||||
|
|
||||||
/* if this is the last element, not finding it is not necessarily fatal */
|
/* if this is the last element, not finding it is not necessarily fatal */
|
||||||
if (!name_len)
|
if (!name_len)
|
||||||
|
@ -3184,7 +3203,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
|
||||||
pos += strlen( unix_name + pos );
|
pos += strlen( unix_name + pos );
|
||||||
name = next;
|
name = next;
|
||||||
|
|
||||||
if (is_win_dir && (len = get_redirect_path( unix_name, pos, name, name_len, check_case )))
|
if (is_win_dir && (len = get_redirect_path( unix_name, pos, name, name_len, is_unix )))
|
||||||
{
|
{
|
||||||
name += len;
|
name += len;
|
||||||
name_len -= len;
|
name_len -= len;
|
||||||
|
@ -3203,10 +3222,9 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
|
||||||
static NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, char **name_ret,
|
static NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, char **name_ret,
|
||||||
UNICODE_STRING *nt_name, UINT disposition )
|
UNICODE_STRING *nt_name, UINT disposition )
|
||||||
{
|
{
|
||||||
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 };
|
|
||||||
enum server_fd_type type;
|
enum server_fd_type type;
|
||||||
int old_cwd, root_fd, needs_close;
|
int old_cwd, root_fd, needs_close;
|
||||||
const WCHAR *name, *p;
|
const WCHAR *name;
|
||||||
char *unix_name;
|
char *unix_name;
|
||||||
int name_len, unix_len;
|
int name_len, unix_len;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
@ -3217,11 +3235,7 @@ static NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, char *
|
||||||
name = attr->ObjectName->Buffer;
|
name = attr->ObjectName->Buffer;
|
||||||
name_len = attr->ObjectName->Length / sizeof(WCHAR);
|
name_len = attr->ObjectName->Length / sizeof(WCHAR);
|
||||||
|
|
||||||
if (name_len && IS_SEPARATOR(name[0])) return STATUS_INVALID_PARAMETER;
|
if (name_len && name[0] == '\\') return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
/* check for invalid characters */
|
|
||||||
for (p = name; p < name + name_len; p++)
|
|
||||||
if (*p < 32 || wcschr( invalid_charsW, *p )) return STATUS_OBJECT_NAME_INVALID;
|
|
||||||
|
|
||||||
unix_len = name_len * 3 + MAX_DIR_ENTRY_LEN + 3;
|
unix_len = name_len * 3 + MAX_DIR_ENTRY_LEN + 3;
|
||||||
if (!(unix_name = malloc( unix_len ))) return STATUS_NO_MEMORY;
|
if (!(unix_name = malloc( unix_len ))) return STATUS_NO_MEMORY;
|
||||||
|
@ -3239,8 +3253,7 @@ static NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, char *
|
||||||
mutex_lock( &dir_mutex );
|
mutex_lock( &dir_mutex );
|
||||||
if ((old_cwd = open( ".", O_RDONLY )) != -1 && fchdir( root_fd ) != -1)
|
if ((old_cwd = open( ".", O_RDONLY )) != -1 && fchdir( root_fd ) != -1)
|
||||||
{
|
{
|
||||||
status = lookup_unix_name( name, name_len, &unix_name, unix_len, 1,
|
status = lookup_unix_name( name, name_len, &unix_name, unix_len, 1, disposition, FALSE );
|
||||||
disposition, FALSE );
|
|
||||||
if (fchdir( old_cwd ) == -1) chdir( "/" );
|
if (fchdir( old_cwd ) == -1) chdir( "/" );
|
||||||
}
|
}
|
||||||
else status = errno_to_status( errno );
|
else status = errno_to_status( errno );
|
||||||
|
@ -3282,18 +3295,17 @@ NTSTATUS nt_to_unix_file_name( const UNICODE_STRING *nameW, char **unix_name_ret
|
||||||
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 };
|
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 };
|
||||||
|
|
||||||
NTSTATUS status = STATUS_SUCCESS;
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
const WCHAR *name, *p;
|
const WCHAR *name;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *unix_name;
|
char *unix_name;
|
||||||
int pos, ret, name_len, unix_len, prefix_len;
|
int pos, ret, name_len, unix_len, prefix_len;
|
||||||
WCHAR prefix[MAX_DIR_ENTRY_LEN + 1];
|
WCHAR prefix[MAX_DIR_ENTRY_LEN + 1];
|
||||||
BOOLEAN check_case = FALSE;
|
|
||||||
BOOLEAN is_unix = FALSE;
|
BOOLEAN is_unix = FALSE;
|
||||||
|
|
||||||
name = nameW->Buffer;
|
name = nameW->Buffer;
|
||||||
name_len = nameW->Length / sizeof(WCHAR);
|
name_len = nameW->Length / sizeof(WCHAR);
|
||||||
|
|
||||||
if (!name_len || !IS_SEPARATOR(name[0])) return STATUS_OBJECT_PATH_SYNTAX_BAD;
|
if (!name_len || name[0] != '\\') return STATUS_OBJECT_PATH_SYNTAX_BAD;
|
||||||
|
|
||||||
if (!(pos = get_dos_prefix_len( nameW )))
|
if (!(pos = get_dos_prefix_len( nameW )))
|
||||||
return STATUS_BAD_DEVICE_TYPE; /* no DOS prefix, assume NT native name */
|
return STATUS_BAD_DEVICE_TYPE; /* no DOS prefix, assume NT native name */
|
||||||
|
@ -3306,30 +3318,22 @@ NTSTATUS nt_to_unix_file_name( const UNICODE_STRING *nameW, char **unix_name_ret
|
||||||
/* check for sub-directory */
|
/* check for sub-directory */
|
||||||
for (pos = 0; pos < name_len && pos <= MAX_DIR_ENTRY_LEN; pos++)
|
for (pos = 0; pos < name_len && pos <= MAX_DIR_ENTRY_LEN; pos++)
|
||||||
{
|
{
|
||||||
if (IS_SEPARATOR(name[pos])) break;
|
if (name[pos] == '\\') break;
|
||||||
if (name[pos] < 32 || wcschr( invalid_charsW, name[pos] ))
|
if (name[pos] < 32 || wcschr( invalid_charsW, name[pos] ))
|
||||||
return STATUS_OBJECT_NAME_INVALID;
|
return STATUS_OBJECT_NAME_INVALID;
|
||||||
prefix[pos] = (name[pos] >= 'A' && name[pos] <= 'Z') ? name[pos] + 'a' - 'A' : name[pos];
|
prefix[pos] = (name[pos] >= 'A' && name[pos] <= 'Z') ? name[pos] + 'a' - 'A' : name[pos];
|
||||||
}
|
}
|
||||||
if (pos > MAX_DIR_ENTRY_LEN) return STATUS_OBJECT_NAME_INVALID;
|
if (pos > MAX_DIR_ENTRY_LEN) return STATUS_OBJECT_NAME_INVALID;
|
||||||
|
|
||||||
|
if (pos >= 4 && !memcmp( prefix, unixW, sizeof(unixW) ))
|
||||||
|
{
|
||||||
|
/* allow slash for unix namespace */
|
||||||
|
if (pos > 4 && prefix[4] == '/') pos = 4;
|
||||||
|
is_unix = pos == 4;
|
||||||
|
}
|
||||||
prefix_len = pos;
|
prefix_len = pos;
|
||||||
prefix[prefix_len] = 0;
|
prefix[prefix_len] = 0;
|
||||||
|
|
||||||
/* check for invalid characters (all chars except 0 are valid for unix) */
|
|
||||||
is_unix = (prefix_len == 4 && !memcmp( prefix, unixW, sizeof(unixW) ));
|
|
||||||
if (is_unix)
|
|
||||||
{
|
|
||||||
for (p = name + prefix_len; p < name + name_len; p++)
|
|
||||||
if (!*p) return STATUS_OBJECT_NAME_INVALID;
|
|
||||||
check_case = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (p = name + prefix_len; p < name + name_len; p++)
|
|
||||||
if (*p < 32 || wcschr( invalid_charsW, *p )) return STATUS_OBJECT_NAME_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
unix_len = name_len * 3 + MAX_DIR_ENTRY_LEN + 3;
|
unix_len = name_len * 3 + MAX_DIR_ENTRY_LEN + 3;
|
||||||
unix_len += strlen(config_dir) + sizeof("/dosdevices/");
|
unix_len += strlen(config_dir) + sizeof("/dosdevices/");
|
||||||
if (!(unix_name = malloc( unix_len ))) return STATUS_NO_MEMORY;
|
if (!(unix_name = malloc( unix_len ))) return STATUS_NO_MEMORY;
|
||||||
|
@ -3353,6 +3357,7 @@ NTSTATUS nt_to_unix_file_name( const UNICODE_STRING *nameW, char **unix_name_ret
|
||||||
|
|
||||||
/* check if prefix exists (except for DOS drives to avoid extra stat calls) */
|
/* check if prefix exists (except for DOS drives to avoid extra stat calls) */
|
||||||
|
|
||||||
|
if (wcschr( prefix, '/' )) return STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
if (prefix_len != 2 || prefix[1] != ':')
|
if (prefix_len != 2 || prefix[1] != ':')
|
||||||
{
|
{
|
||||||
unix_name[pos] = 0;
|
unix_name[pos] = 0;
|
||||||
|
@ -3367,10 +3372,10 @@ NTSTATUS nt_to_unix_file_name( const UNICODE_STRING *nameW, char **unix_name_ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
name += prefix_len;
|
name += prefix_len + 1;
|
||||||
name_len -= prefix_len;
|
name_len -= prefix_len + 1;
|
||||||
|
|
||||||
status = lookup_unix_name( name, name_len, &unix_name, unix_len, pos, disposition, check_case );
|
status = lookup_unix_name( name, name_len, &unix_name, unix_len, pos, disposition, is_unix );
|
||||||
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
|
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
|
||||||
{
|
{
|
||||||
TRACE( "%s -> %s\n", debugstr_us(nameW), debugstr_a(unix_name) );
|
TRACE( "%s -> %s\n", debugstr_us(nameW), debugstr_a(unix_name) );
|
||||||
|
|
Loading…
Reference in New Issue