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.
This commit is contained in:
parent
1c279bfd89
commit
cf67839bc4
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,10 +1071,12 @@ 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)
|
||||
{
|
||||
if (status == STATUS_OBJECT_PATH_NOT_FOUND)
|
||||
{
|
||||
status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
if (!check_last)
|
||||
if (disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
|
||||
{
|
||||
ret = ntdll_wcstoumbs( 0, name, end - name, unix_name + pos + 1,
|
||||
MAX_DIR_ENTRY_LEN, NULL, &used_default );
|
||||
|
@ -1079,6 +1089,11 @@ NTSTATUS wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *un
|
|||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue