Commit cf67839b authored by Alexandre Julliard's avatar Alexandre Julliard

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.
parent 1c279bfd
......@@ -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 );
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 )) goto done;
}
while (name_len && IS_SEPARATOR(*name))
if (!stat( unix_name, &st ))
{
name++;
name_len--;
/* 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment