From cf67839bc4094678772858727bdfe2d596618bf0 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 27 Apr 2004 02:15:52 +0000 Subject: [PATCH] Pass the creation disposition to wine_nt_to_unix_file_name so that it can return the correct error code in all cases. Changed MoveFileExW to use wine_nt_to_unix_file_name to avoid computing the NT name twice. Fixed crash in GetDriveTypeW with a NULL root. --- dlls/kernel/path.c | 44 +++++++++++++++--------------- dlls/kernel/volume.c | 21 ++++++++++----- dlls/ntdll/directory.c | 61 ++++++++++++++++++++++++++---------------- dlls/ntdll/file.c | 13 +++++---- include/winternl.h | 2 +- 5 files changed, 82 insertions(+), 59 deletions(-) diff --git a/dlls/kernel/path.c b/dlls/kernel/path.c index 249adddac5..a9276314ec 100644 --- a/dlls/kernel/path.c +++ b/dlls/kernel/path.c @@ -826,7 +826,7 @@ BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag ) IO_STATUS_BLOCK io; NTSTATUS status; HANDLE source_handle = 0, dest_handle; - char *source_unix = NULL, *dest_unix = NULL; + ANSI_STRING source_unix, dest_unix; TRACE("(%s,%s,%04lx)\n", debugstr_w(source), debugstr_w(dest), flag); @@ -843,6 +843,8 @@ BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag ) SetLastError( ERROR_PATH_NOT_FOUND ); return FALSE; } + source_unix.Buffer = NULL; + dest_unix.Buffer = NULL; attr.Length = sizeof(attr); attr.RootDirectory = 0; attr.Attributes = OBJ_CASE_INSENSITIVE; @@ -851,6 +853,8 @@ BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag ) attr.SecurityQualityOfService = NULL; status = NtOpenFile( &source_handle, 0, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT ); + if (status == STATUS_SUCCESS) + status = wine_nt_to_unix_file_name( &nt_name, &source_unix, FILE_OPEN, FALSE ); RtlFreeUnicodeString( &nt_name ); if (status != STATUS_SUCCESS) { @@ -864,12 +868,6 @@ BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag ) goto error; } - if (!(source_unix = wine_get_unix_file_name( source ))) /* should not happen */ - { - SetLastError( ERROR_FILE_NOT_FOUND ); - goto error; - } - if (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (flag & MOVEFILE_REPLACE_EXISTING) /* cannot replace directory */ @@ -889,41 +887,45 @@ BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag ) } status = NtOpenFile( &dest_handle, GENERIC_READ | GENERIC_WRITE, &attr, &io, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); - RtlFreeUnicodeString( &nt_name ); if (status == STATUS_SUCCESS) { NtClose( dest_handle ); if (!(flag & MOVEFILE_REPLACE_EXISTING)) { SetLastError( ERROR_ALREADY_EXISTS ); + RtlFreeUnicodeString( &nt_name ); goto error; } } else if (status != STATUS_OBJECT_NAME_NOT_FOUND) { SetLastError( RtlNtStatusToDosError(status) ); + RtlFreeUnicodeString( &nt_name ); goto error; } - if (!(dest_unix = wine_get_unix_file_name( dest ))) /* should not happen */ + + status = wine_nt_to_unix_file_name( &nt_name, &dest_unix, FILE_OPEN_IF, FALSE ); + RtlFreeUnicodeString( &nt_name ); + if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE) { - SetLastError( ERROR_FILE_NOT_FOUND ); + SetLastError( RtlNtStatusToDosError(status) ); goto error; } /* now perform the rename */ - if (rename( source_unix, dest_unix ) == -1) + if (rename( source_unix.Buffer, dest_unix.Buffer ) == -1) { if (errno == EXDEV && (flag & MOVEFILE_COPY_ALLOWED)) { NtClose( source_handle ); - HeapFree( GetProcessHeap(), 0, source_unix ); - HeapFree( GetProcessHeap(), 0, dest_unix ); + RtlFreeAnsiString( &source_unix ); + RtlFreeAnsiString( &dest_unix ); return (CopyFileW( source, dest, TRUE ) && DeleteFileW( source )); } FILE_SetDosError(); /* if we created the destination, remove it */ - if (io.Information == FILE_CREATED) unlink( dest_unix ); + if (io.Information == FILE_CREATED) unlink( dest_unix.Buffer ); goto error; } @@ -932,26 +934,26 @@ BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag ) if (is_executable( source ) != is_executable( dest )) { struct stat fstat; - if (stat( dest_unix, &fstat ) != -1) + if (stat( dest_unix.Buffer, &fstat ) != -1) { if (is_executable( dest )) /* set executable bit where read bit is set */ fstat.st_mode |= (fstat.st_mode & 0444) >> 2; else fstat.st_mode &= ~0111; - chmod( dest_unix, fstat.st_mode ); + chmod( dest_unix.Buffer, fstat.st_mode ); } } NtClose( source_handle ); - HeapFree( GetProcessHeap(), 0, source_unix ); - HeapFree( GetProcessHeap(), 0, dest_unix ); + RtlFreeAnsiString( &source_unix ); + RtlFreeAnsiString( &dest_unix ); return TRUE; error: if (source_handle) NtClose( source_handle ); - if (source_unix) HeapFree( GetProcessHeap(), 0, source_unix ); - if (dest_unix) HeapFree( GetProcessHeap(), 0, dest_unix ); + RtlFreeAnsiString( &source_unix ); + RtlFreeAnsiString( &dest_unix ); return FALSE; } @@ -1014,7 +1016,7 @@ char *wine_get_unix_file_name( LPCWSTR dosW ) NTSTATUS status; if (!RtlDosPathNameToNtPathName_U( dosW, &nt_name, NULL, NULL )) return NULL; - status = wine_nt_to_unix_file_name( &nt_name, &unix_name, FALSE, FALSE ); + status = wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN_IF, FALSE ); RtlFreeUnicodeString( &nt_name ); if (status && status != STATUS_NO_SUCH_FILE) return NULL; return unix_name.Buffer; diff --git a/dlls/kernel/volume.c b/dlls/kernel/volume.c index 8bf82b5897..b13dc685b9 100644 --- a/dlls/kernel/volume.c +++ b/dlls/kernel/volume.c @@ -165,7 +165,7 @@ static BOOL open_device_root( LPCWSTR root, HANDLE *handle ) /* fetch the type of a drive from the registry */ -static UINT get_registry_drive_type( int drive ) +static UINT get_registry_drive_type( const WCHAR *root ) { OBJECT_ATTRIBUTES attr; UNICODE_STRING nameW; @@ -173,11 +173,18 @@ static UINT get_registry_drive_type( int drive ) DWORD dummy; UINT ret = DRIVE_UNKNOWN; char tmp[32 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; + WCHAR path[MAX_PATH]; WCHAR driveW[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\', 'W','i','n','e','\\','W','i','n','e','\\', 'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0}; static const WCHAR TypeW[] = {'T','y','p','e',0}; + + if (!root) + { + GetCurrentDirectoryW( MAX_PATH, path ); + root = path; + } attr.Length = sizeof(attr); attr.RootDirectory = 0; attr.ObjectName = &nameW; @@ -185,7 +192,7 @@ static UINT get_registry_drive_type( int drive ) attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; RtlInitUnicodeString( &nameW, driveW ); - nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + drive; + nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = root[0]; if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) return DRIVE_UNKNOWN; RtlInitUnicodeString( &nameW, TypeW ); @@ -1091,7 +1098,7 @@ DWORD WINAPI QueryDosDeviceW( LPCWSTR devname, LPWSTR target, DWORD bufsize ) nt_buffer[3] = '\\'; strcpyW( nt_buffer + 4, name ); RtlInitUnicodeString( &nt_name, nt_buffer ); - status = wine_nt_to_unix_file_name( &nt_name, &unix_name, TRUE, TRUE ); + status = wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN, TRUE ); if (status) SetLastError( RtlNtStatusToDosError(status) ); else { @@ -1132,7 +1139,7 @@ DWORD WINAPI QueryDosDeviceW( LPCWSTR devname, LPWSTR target, DWORD bufsize ) for (i = 1; i <= 9; i++) { nt_buffer[7] = '0' + i; - if (!wine_nt_to_unix_file_name( &nt_name, &unix_name, TRUE, TRUE )) + if (!wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN, TRUE )) { RtlFreeAnsiString( &unix_name ); if (p + 5 >= target + bufsize) @@ -1150,7 +1157,7 @@ DWORD WINAPI QueryDosDeviceW( LPCWSTR devname, LPWSTR target, DWORD bufsize ) for (i = 1; i <= 9; i++) { nt_buffer[7] = '0' + i; - if (!wine_nt_to_unix_file_name( &nt_name, &unix_name, TRUE, TRUE )) + if (!wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN, TRUE )) { RtlFreeAnsiString( &unix_name ); if (p + 5 >= target + bufsize) @@ -1171,7 +1178,7 @@ DWORD WINAPI QueryDosDeviceW( LPCWSTR devname, LPWSTR target, DWORD bufsize ) for (i = 0; i < 26; i++) { nt_buffer[4] = 'a' + i; - if (!wine_nt_to_unix_file_name( &nt_name, &unix_name, TRUE, TRUE )) + if (!wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN, TRUE )) { RtlFreeAnsiString( &unix_name ); if (p + 3 >= target + bufsize) @@ -1337,7 +1344,7 @@ UINT WINAPI GetDriveTypeW(LPCWSTR root) /* [in] String describing drive */ SetLastError( RtlNtStatusToDosError(status) ); ret = DRIVE_UNKNOWN; } - else if ((ret = get_registry_drive_type( toupperW(root[0]) - 'A' )) == DRIVE_UNKNOWN) + else if ((ret = get_registry_drive_type( root )) == DRIVE_UNKNOWN) { switch (info.DeviceType) { diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index c1729ad044..bf6ac264b1 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -938,12 +938,12 @@ static inline int get_dos_prefix_len( const UNICODE_STRING *name ) * * Convert a file name from NT namespace to Unix namespace. * - * If check_last is 0, the last path element doesn't have to exist; - * in that case STATUS_NO_SUCH_FILE is returned, but the - * unix name is still filled in properly. + * If disposition is not FILE_OPEN or FILE_OVERWRITTE, the last path + * element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is + * returned, but the unix name is still filled in properly. */ NTSTATUS wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret, - BOOLEAN check_last, BOOLEAN check_case ) + UINT disposition, BOOLEAN check_case ) { static const WCHAR uncW[] = {'U','N','C','\\'}; static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 }; @@ -1010,25 +1010,33 @@ NTSTATUS wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *un ret = ntdll_wcstoumbs( 0, name, name_len, unix_name + pos, unix_len - pos - 1, NULL, &used_default ); - if (ret > 0 && !used_default) /* if we used the default char the name didn't convert properly */ - { - char *p; - unix_name[pos + ret] = 0; - for (p = unix_name + pos ; *p; p++) if (*p == '\\') *p = '/'; - if (!stat( unix_name, &st )) goto done; - } while (name_len && IS_SEPARATOR(*name)) { name++; name_len--; } + + if (ret > 0 && !used_default) /* if we used the default char the name didn't convert properly */ + { + char *p; + unix_name[pos + ret] = 0; + for (p = unix_name + pos ; *p; p++) if (*p == '\\') *p = '/'; + if (!stat( unix_name, &st )) + { + /* creation fails with STATUS_ACCESS_DENIED for the root of the drive */ + if (disposition == FILE_CREATE) + return name_len ? STATUS_OBJECT_NAME_COLLISION : STATUS_ACCESS_DENIED; + goto done; + } + } + if (!name_len) /* empty name -> drive root doesn't exist */ { RtlFreeHeap( GetProcessHeap(), 0, unix_name ); return STATUS_OBJECT_PATH_NOT_FOUND; } - if (check_case && check_last) + if (check_case && (disposition == FILE_OPEN || disposition == FILE_OVERWRITE)) { RtlFreeHeap( GetProcessHeap(), 0, unix_name ); return STATUS_OBJECT_NAME_NOT_FOUND; @@ -1063,21 +1071,28 @@ NTSTATUS wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *un status = find_file_in_dir( unix_name, pos, name, end - name, check_case ); /* if this is the last element, not finding it is not necessarily fatal */ - if (!name_len && status == STATUS_OBJECT_PATH_NOT_FOUND) + if (!name_len) { - status = STATUS_OBJECT_NAME_NOT_FOUND; - if (!check_last) + if (status == STATUS_OBJECT_PATH_NOT_FOUND) { - ret = ntdll_wcstoumbs( 0, name, end - name, unix_name + pos + 1, - MAX_DIR_ENTRY_LEN, NULL, &used_default ); - if (ret > 0 && !used_default) + status = STATUS_OBJECT_NAME_NOT_FOUND; + if (disposition != FILE_OPEN && disposition != FILE_OVERWRITE) { - unix_name[pos] = '/'; - unix_name[pos + 1 + ret] = 0; - status = STATUS_NO_SUCH_FILE; - break; + ret = ntdll_wcstoumbs( 0, name, end - name, unix_name + pos + 1, + MAX_DIR_ENTRY_LEN, NULL, &used_default ); + if (ret > 0 && !used_default) + { + unix_name[pos] = '/'; + unix_name[pos + 1 + ret] = 0; + status = STATUS_NO_SUCH_FILE; + break; + } } } + else if (status == STATUS_SUCCESS && disposition == FILE_CREATE) + { + status = STATUS_OBJECT_NAME_COLLISION; + } } if (status != STATUS_SUCCESS) @@ -1114,7 +1129,7 @@ BOOLEAN WINAPI RtlDoesFileExists_U(LPCWSTR file_name) BOOLEAN ret; if (!RtlDosPathNameToNtPathName_U( file_name, &nt_name, NULL, NULL )) return FALSE; - ret = (wine_nt_to_unix_file_name( &nt_name, &unix_name, TRUE, FALSE ) == STATUS_SUCCESS); + ret = (wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN, FALSE ) == STATUS_SUCCESS); if (ret) RtlFreeAnsiString( &unix_name ); RtlFreeUnicodeString( &nt_name ); return ret; diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index fdd4e796e4..b3b8e18b81 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -131,7 +131,7 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB ULONG options, PVOID ea_buffer, ULONG ea_length ) { ANSI_STRING unix_name; - int check_last, created = FALSE; + int created = FALSE; TRACE("handle=%p access=%08lx name=%s objattr=%08lx root=%p sec=%p io=%p alloc_size=%p\n" "attr=%08lx sharing=%08lx disp=%ld options=%08lx ea=%p.0x%08lx\n", @@ -146,12 +146,11 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB } if (alloc_size) FIXME( "alloc_size not supported\n" ); - check_last = (disposition == FILE_OPEN || disposition == FILE_OVERWRITE); - - io->u.Status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, check_last, + io->u.Status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, disposition, !(attr->Attributes & OBJ_CASE_INSENSITIVE) ); - if (!check_last && io->u.Status == STATUS_NO_SUCH_FILE) + if (io->u.Status == STATUS_NO_SUCH_FILE && + disposition != FILE_OPEN && disposition != FILE_OVERWRITE) { created = TRUE; io->u.Status = STATUS_SUCCESS; @@ -1025,8 +1024,8 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, ANSI_STRING unix_name; NTSTATUS status; - if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, - TRUE, !(attr->Attributes & OBJ_CASE_INSENSITIVE) ))) + if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN, + !(attr->Attributes & OBJ_CASE_INSENSITIVE) ))) { struct stat st; diff --git a/include/winternl.h b/include/winternl.h index bb297651ca..272e960e67 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1514,7 +1514,7 @@ NTSTATUS WINAPI RtlpUnWaitCriticalSection(RTL_CRITICAL_SECTION *); /* Wine internal functions */ extern NTSTATUS wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret, - BOOLEAN check_last, BOOLEAN check_case ); + UINT disposition, BOOLEAN check_case ); /*********************************************************************** * Inline functions