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:
Alexandre Julliard 2004-04-27 02:15:52 +00:00
parent 1c279bfd89
commit cf67839bc4
5 changed files with 82 additions and 59 deletions

View File

@ -826,7 +826,7 @@ BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag )
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
NTSTATUS status; NTSTATUS status;
HANDLE source_handle = 0, dest_handle; 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); 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 ); SetLastError( ERROR_PATH_NOT_FOUND );
return FALSE; return FALSE;
} }
source_unix.Buffer = NULL;
dest_unix.Buffer = NULL;
attr.Length = sizeof(attr); attr.Length = sizeof(attr);
attr.RootDirectory = 0; attr.RootDirectory = 0;
attr.Attributes = OBJ_CASE_INSENSITIVE; attr.Attributes = OBJ_CASE_INSENSITIVE;
@ -851,6 +853,8 @@ BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag )
attr.SecurityQualityOfService = NULL; attr.SecurityQualityOfService = NULL;
status = NtOpenFile( &source_handle, 0, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT ); 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 ); RtlFreeUnicodeString( &nt_name );
if (status != STATUS_SUCCESS) if (status != STATUS_SUCCESS)
{ {
@ -864,12 +868,6 @@ BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag )
goto error; 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 (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{ {
if (flag & MOVEFILE_REPLACE_EXISTING) /* cannot replace 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, status = NtOpenFile( &dest_handle, GENERIC_READ | GENERIC_WRITE, &attr, &io, 0,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
RtlFreeUnicodeString( &nt_name );
if (status == STATUS_SUCCESS) if (status == STATUS_SUCCESS)
{ {
NtClose( dest_handle ); NtClose( dest_handle );
if (!(flag & MOVEFILE_REPLACE_EXISTING)) if (!(flag & MOVEFILE_REPLACE_EXISTING))
{ {
SetLastError( ERROR_ALREADY_EXISTS ); SetLastError( ERROR_ALREADY_EXISTS );
RtlFreeUnicodeString( &nt_name );
goto error; goto error;
} }
} }
else if (status != STATUS_OBJECT_NAME_NOT_FOUND) else if (status != STATUS_OBJECT_NAME_NOT_FOUND)
{ {
SetLastError( RtlNtStatusToDosError(status) ); SetLastError( RtlNtStatusToDosError(status) );
RtlFreeUnicodeString( &nt_name );
goto error; 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; goto error;
} }
/* now perform the rename */ /* 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)) if (errno == EXDEV && (flag & MOVEFILE_COPY_ALLOWED))
{ {
NtClose( source_handle ); NtClose( source_handle );
HeapFree( GetProcessHeap(), 0, source_unix ); RtlFreeAnsiString( &source_unix );
HeapFree( GetProcessHeap(), 0, dest_unix ); RtlFreeAnsiString( &dest_unix );
return (CopyFileW( source, dest, TRUE ) && DeleteFileW( source )); return (CopyFileW( source, dest, TRUE ) && DeleteFileW( source ));
} }
FILE_SetDosError(); FILE_SetDosError();
/* if we created the destination, remove it */ /* 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; goto error;
} }
@ -932,26 +934,26 @@ BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag )
if (is_executable( source ) != is_executable( dest )) if (is_executable( source ) != is_executable( dest ))
{ {
struct stat fstat; struct stat fstat;
if (stat( dest_unix, &fstat ) != -1) if (stat( dest_unix.Buffer, &fstat ) != -1)
{ {
if (is_executable( dest )) if (is_executable( dest ))
/* set executable bit where read bit is set */ /* set executable bit where read bit is set */
fstat.st_mode |= (fstat.st_mode & 0444) >> 2; fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
else else
fstat.st_mode &= ~0111; fstat.st_mode &= ~0111;
chmod( dest_unix, fstat.st_mode ); chmod( dest_unix.Buffer, fstat.st_mode );
} }
} }
NtClose( source_handle ); NtClose( source_handle );
HeapFree( GetProcessHeap(), 0, source_unix ); RtlFreeAnsiString( &source_unix );
HeapFree( GetProcessHeap(), 0, dest_unix ); RtlFreeAnsiString( &dest_unix );
return TRUE; return TRUE;
error: error:
if (source_handle) NtClose( source_handle ); if (source_handle) NtClose( source_handle );
if (source_unix) HeapFree( GetProcessHeap(), 0, source_unix ); RtlFreeAnsiString( &source_unix );
if (dest_unix) HeapFree( GetProcessHeap(), 0, dest_unix ); RtlFreeAnsiString( &dest_unix );
return FALSE; return FALSE;
} }
@ -1014,7 +1016,7 @@ char *wine_get_unix_file_name( LPCWSTR dosW )
NTSTATUS status; NTSTATUS status;
if (!RtlDosPathNameToNtPathName_U( dosW, &nt_name, NULL, NULL )) return NULL; 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 ); RtlFreeUnicodeString( &nt_name );
if (status && status != STATUS_NO_SUCH_FILE) return NULL; if (status && status != STATUS_NO_SUCH_FILE) return NULL;
return unix_name.Buffer; return unix_name.Buffer;

View File

@ -165,7 +165,7 @@ static BOOL open_device_root( LPCWSTR root, HANDLE *handle )
/* fetch the type of a drive from the registry */ /* 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; OBJECT_ATTRIBUTES attr;
UNICODE_STRING nameW; UNICODE_STRING nameW;
@ -173,11 +173,18 @@ static UINT get_registry_drive_type( int drive )
DWORD dummy; DWORD dummy;
UINT ret = DRIVE_UNKNOWN; UINT ret = DRIVE_UNKNOWN;
char tmp[32 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; 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','\\', 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','\\', 'W','i','n','e','\\','W','i','n','e','\\',
'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0}; 'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0};
static const WCHAR TypeW[] = {'T','y','p','e',0}; static const WCHAR TypeW[] = {'T','y','p','e',0};
if (!root)
{
GetCurrentDirectoryW( MAX_PATH, path );
root = path;
}
attr.Length = sizeof(attr); attr.Length = sizeof(attr);
attr.RootDirectory = 0; attr.RootDirectory = 0;
attr.ObjectName = &nameW; attr.ObjectName = &nameW;
@ -185,7 +192,7 @@ static UINT get_registry_drive_type( int drive )
attr.SecurityDescriptor = NULL; attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL; attr.SecurityQualityOfService = NULL;
RtlInitUnicodeString( &nameW, driveW ); 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; if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) return DRIVE_UNKNOWN;
RtlInitUnicodeString( &nameW, TypeW ); RtlInitUnicodeString( &nameW, TypeW );
@ -1091,7 +1098,7 @@ DWORD WINAPI QueryDosDeviceW( LPCWSTR devname, LPWSTR target, DWORD bufsize )
nt_buffer[3] = '\\'; nt_buffer[3] = '\\';
strcpyW( nt_buffer + 4, name ); strcpyW( nt_buffer + 4, name );
RtlInitUnicodeString( &nt_name, nt_buffer ); 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) ); if (status) SetLastError( RtlNtStatusToDosError(status) );
else else
{ {
@ -1132,7 +1139,7 @@ DWORD WINAPI QueryDosDeviceW( LPCWSTR devname, LPWSTR target, DWORD bufsize )
for (i = 1; i <= 9; i++) for (i = 1; i <= 9; i++)
{ {
nt_buffer[7] = '0' + 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 ); RtlFreeAnsiString( &unix_name );
if (p + 5 >= target + bufsize) if (p + 5 >= target + bufsize)
@ -1150,7 +1157,7 @@ DWORD WINAPI QueryDosDeviceW( LPCWSTR devname, LPWSTR target, DWORD bufsize )
for (i = 1; i <= 9; i++) for (i = 1; i <= 9; i++)
{ {
nt_buffer[7] = '0' + 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 ); RtlFreeAnsiString( &unix_name );
if (p + 5 >= target + bufsize) if (p + 5 >= target + bufsize)
@ -1171,7 +1178,7 @@ DWORD WINAPI QueryDosDeviceW( LPCWSTR devname, LPWSTR target, DWORD bufsize )
for (i = 0; i < 26; i++) for (i = 0; i < 26; i++)
{ {
nt_buffer[4] = 'a' + 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 ); RtlFreeAnsiString( &unix_name );
if (p + 3 >= target + bufsize) if (p + 3 >= target + bufsize)
@ -1337,7 +1344,7 @@ UINT WINAPI GetDriveTypeW(LPCWSTR root) /* [in] String describing drive */
SetLastError( RtlNtStatusToDosError(status) ); SetLastError( RtlNtStatusToDosError(status) );
ret = DRIVE_UNKNOWN; 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) switch (info.DeviceType)
{ {

View File

@ -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. * Convert a file name from NT namespace to Unix namespace.
* *
* If check_last is 0, the last path element doesn't have to exist; * If disposition is not FILE_OPEN or FILE_OVERWRITTE, the last path
* in that case STATUS_NO_SUCH_FILE is returned, but the * element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is
* unix name is still filled in properly. * 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, 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 uncW[] = {'U','N','C','\\'};
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 }; 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, ret = ntdll_wcstoumbs( 0, name, name_len, unix_name + pos, unix_len - pos - 1,
NULL, &used_default ); 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)) while (name_len && IS_SEPARATOR(*name))
{ {
name++; name++;
name_len--; 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 */ if (!name_len) /* empty name -> drive root doesn't exist */
{ {
RtlFreeHeap( GetProcessHeap(), 0, unix_name ); RtlFreeHeap( GetProcessHeap(), 0, unix_name );
return STATUS_OBJECT_PATH_NOT_FOUND; 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 ); RtlFreeHeap( GetProcessHeap(), 0, unix_name );
return STATUS_OBJECT_NAME_NOT_FOUND; 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 ); 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 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 (status == STATUS_OBJECT_PATH_NOT_FOUND)
if (!check_last)
{ {
ret = ntdll_wcstoumbs( 0, name, end - name, unix_name + pos + 1, status = STATUS_OBJECT_NAME_NOT_FOUND;
MAX_DIR_ENTRY_LEN, NULL, &used_default ); if (disposition != FILE_OPEN && disposition != FILE_OVERWRITE)
if (ret > 0 && !used_default)
{ {
unix_name[pos] = '/'; ret = ntdll_wcstoumbs( 0, name, end - name, unix_name + pos + 1,
unix_name[pos + 1 + ret] = 0; MAX_DIR_ENTRY_LEN, NULL, &used_default );
status = STATUS_NO_SUCH_FILE; if (ret > 0 && !used_default)
break; {
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) if (status != STATUS_SUCCESS)
@ -1114,7 +1129,7 @@ BOOLEAN WINAPI RtlDoesFileExists_U(LPCWSTR file_name)
BOOLEAN ret; BOOLEAN ret;
if (!RtlDosPathNameToNtPathName_U( file_name, &nt_name, NULL, NULL )) return FALSE; 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 ); if (ret) RtlFreeAnsiString( &unix_name );
RtlFreeUnicodeString( &nt_name ); RtlFreeUnicodeString( &nt_name );
return ret; return ret;

View File

@ -131,7 +131,7 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB
ULONG options, PVOID ea_buffer, ULONG ea_length ) ULONG options, PVOID ea_buffer, ULONG ea_length )
{ {
ANSI_STRING unix_name; 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" 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", "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" ); 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, disposition,
io->u.Status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, check_last,
!(attr->Attributes & OBJ_CASE_INSENSITIVE) ); !(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; created = TRUE;
io->u.Status = STATUS_SUCCESS; io->u.Status = STATUS_SUCCESS;
@ -1025,8 +1024,8 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
ANSI_STRING unix_name; ANSI_STRING unix_name;
NTSTATUS status; NTSTATUS status;
if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN,
TRUE, !(attr->Attributes & OBJ_CASE_INSENSITIVE) ))) !(attr->Attributes & OBJ_CASE_INSENSITIVE) )))
{ {
struct stat st; struct stat st;

View File

@ -1514,7 +1514,7 @@ NTSTATUS WINAPI RtlpUnWaitCriticalSection(RTL_CRITICAL_SECTION *);
/* Wine internal functions */ /* Wine internal functions */
extern NTSTATUS wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret, 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 * Inline functions