Added a wine_unix_to_nt_file_name function to do proper pathname
conversions instead of relying on GetFullPathName hacks.
This commit is contained in:
parent
caf18a640e
commit
5617b716e7
|
@ -59,6 +59,7 @@
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winnt.h"
|
#include "winnt.h"
|
||||||
#include "ntstatus.h"
|
#include "ntstatus.h"
|
||||||
|
#include "thread.h"
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
#include "ntdll_misc.h"
|
#include "ntdll_misc.h"
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
|
@ -1575,3 +1576,86 @@ BOOLEAN WINAPI RtlDoesFileExists_U(LPCWSTR file_name)
|
||||||
RtlFreeUnicodeString( &nt_name );
|
RtlFreeUnicodeString( &nt_name );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* DIR_get_unix_cwd
|
||||||
|
*
|
||||||
|
* Retrieve the Unix name of the current directory; helper for wine_unix_to_nt_file_name.
|
||||||
|
* Returned value must be freed by caller.
|
||||||
|
*/
|
||||||
|
NTSTATUS DIR_get_unix_cwd( char **cwd )
|
||||||
|
{
|
||||||
|
int old_cwd, unix_fd;
|
||||||
|
CURDIR *curdir;
|
||||||
|
HANDLE handle;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
RtlAcquirePebLock();
|
||||||
|
|
||||||
|
if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */
|
||||||
|
curdir = &((WIN16_SUBSYSTEM_TIB *)NtCurrentTeb()->Tib.SubSystemTib)->curdir;
|
||||||
|
else
|
||||||
|
curdir = &NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory;
|
||||||
|
|
||||||
|
if (!(handle = curdir->Handle))
|
||||||
|
{
|
||||||
|
UNICODE_STRING dirW;
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
|
||||||
|
if (!RtlDosPathNameToNtPathName_U( curdir->DosPath.Buffer, &dirW, NULL, NULL ))
|
||||||
|
{
|
||||||
|
status = STATUS_OBJECT_NAME_INVALID;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
attr.Length = sizeof(attr);
|
||||||
|
attr.RootDirectory = 0;
|
||||||
|
attr.Attributes = OBJ_CASE_INSENSITIVE;
|
||||||
|
attr.ObjectName = &dirW;
|
||||||
|
attr.SecurityDescriptor = NULL;
|
||||||
|
attr.SecurityQualityOfService = NULL;
|
||||||
|
|
||||||
|
status = NtOpenFile( &handle, 0, &attr, &io, 0,
|
||||||
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
|
||||||
|
RtlFreeUnicodeString( &dirW );
|
||||||
|
if (status != STATUS_SUCCESS) goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status = wine_server_handle_to_fd( handle, 0, &unix_fd, NULL )) == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
RtlEnterCriticalSection( &dir_section );
|
||||||
|
|
||||||
|
if ((old_cwd = open(".", O_RDONLY)) != -1 && fchdir( unix_fd ) != -1)
|
||||||
|
{
|
||||||
|
unsigned int size = 512;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (!(*cwd = RtlAllocateHeap( GetProcessHeap(), 0, size )))
|
||||||
|
{
|
||||||
|
status = STATUS_NO_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (getcwd( *cwd, size )) break;
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, *cwd );
|
||||||
|
if (errno != ERANGE)
|
||||||
|
{
|
||||||
|
status = STATUS_OBJECT_PATH_INVALID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size *= 2;
|
||||||
|
}
|
||||||
|
if (fchdir( old_cwd ) == -1) chdir( "/" );
|
||||||
|
}
|
||||||
|
else status = FILE_GetNtStatus();
|
||||||
|
|
||||||
|
RtlLeaveCriticalSection( &dir_section );
|
||||||
|
wine_server_release_fd( handle, unix_fd );
|
||||||
|
}
|
||||||
|
if (!curdir->Handle) NtClose( handle );
|
||||||
|
|
||||||
|
done:
|
||||||
|
RtlReleasePebLock();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
|
@ -1393,6 +1393,7 @@
|
||||||
|
|
||||||
# Filesystem
|
# Filesystem
|
||||||
@ cdecl wine_nt_to_unix_file_name(ptr ptr long long)
|
@ cdecl wine_nt_to_unix_file_name(ptr ptr long long)
|
||||||
|
@ cdecl wine_unix_to_nt_file_name(ptr ptr)
|
||||||
@ cdecl __wine_init_windows_dir(wstr wstr)
|
@ cdecl __wine_init_windows_dir(wstr wstr)
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
@ -88,6 +88,7 @@ extern NTSTATUS CDROM_DeviceIoControl(HANDLE hDevice,
|
||||||
/* file I/O */
|
/* file I/O */
|
||||||
extern NTSTATUS FILE_GetNtStatus(void);
|
extern NTSTATUS FILE_GetNtStatus(void);
|
||||||
extern BOOL DIR_is_hidden_file( const UNICODE_STRING *name );
|
extern BOOL DIR_is_hidden_file( const UNICODE_STRING *name );
|
||||||
|
extern NTSTATUS DIR_get_unix_cwd( char **cwd );
|
||||||
|
|
||||||
/* virtual memory */
|
/* virtual memory */
|
||||||
extern NTSTATUS VIRTUAL_alloc_teb( void **ret, size_t size, BOOL first );
|
extern NTSTATUS VIRTUAL_alloc_teb( void **ret, size_t size, BOOL first );
|
||||||
|
|
|
@ -24,9 +24,13 @@
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <errno.h>
|
||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winioctl.h"
|
#include "winioctl.h"
|
||||||
|
@ -91,11 +95,102 @@ static inline int get_drives_info( struct drive_info info[MAX_DOS_DRIVES] )
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* remove_last_component
|
* remove_last_componentA
|
||||||
*
|
*
|
||||||
* Remove the last component of the path. Helper for find_drive_root.
|
* Remove the last component of the path. Helper for find_drive_rootA.
|
||||||
*/
|
*/
|
||||||
static inline int remove_last_component( const WCHAR *path, int len )
|
static inline unsigned int remove_last_componentA( const char *path, unsigned int len )
|
||||||
|
{
|
||||||
|
int level = 0;
|
||||||
|
|
||||||
|
while (level < 1)
|
||||||
|
{
|
||||||
|
/* find start of the last path component */
|
||||||
|
unsigned int prev = len;
|
||||||
|
if (prev <= 1) break; /* reached root */
|
||||||
|
while (prev > 1 && path[prev - 1] != '/') prev--;
|
||||||
|
/* does removing it take us up a level? */
|
||||||
|
if (len - prev != 1 || path[prev] != '.') /* not '.' */
|
||||||
|
{
|
||||||
|
if (len - prev == 2 && path[prev] == '.' && path[prev+1] == '.') /* is it '..'? */
|
||||||
|
level--;
|
||||||
|
else
|
||||||
|
level++;
|
||||||
|
}
|
||||||
|
/* strip off trailing slashes */
|
||||||
|
while (prev > 1 && path[prev - 1] == '/') prev--;
|
||||||
|
len = prev;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* find_drive_rootA
|
||||||
|
*
|
||||||
|
* Find a drive for which the root matches the beginning of the given path.
|
||||||
|
* This can be used to translate a Unix path into a drive + DOS path.
|
||||||
|
* Return value is the drive, or -1 on error. On success, ppath is modified
|
||||||
|
* to point to the beginning of the DOS path.
|
||||||
|
*/
|
||||||
|
static NTSTATUS find_drive_rootA( LPCSTR *ppath, unsigned int len, int *drive_ret )
|
||||||
|
{
|
||||||
|
/* Starting with the full path, check if the device and inode match any of
|
||||||
|
* the wine 'drives'. If not then remove the last path component and try
|
||||||
|
* again. If the last component was a '..' then skip a normal component
|
||||||
|
* since it's a directory that's ascended back out of.
|
||||||
|
*/
|
||||||
|
int drive;
|
||||||
|
char *buffer;
|
||||||
|
const char *path = *ppath;
|
||||||
|
struct stat st;
|
||||||
|
struct drive_info info[MAX_DOS_DRIVES];
|
||||||
|
|
||||||
|
/* get device and inode of all drives */
|
||||||
|
if (!get_drives_info( info )) return STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
|
|
||||||
|
/* strip off trailing slashes */
|
||||||
|
while (len > 1 && path[len - 1] == '/') len--;
|
||||||
|
|
||||||
|
/* make a copy of the path */
|
||||||
|
if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, len + 1 ))) return STATUS_NO_MEMORY;
|
||||||
|
memcpy( buffer, path, len );
|
||||||
|
buffer[len] = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (!stat( buffer, &st ) && S_ISDIR( st.st_mode ))
|
||||||
|
{
|
||||||
|
/* Find the drive */
|
||||||
|
for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
|
||||||
|
{
|
||||||
|
if ((info[drive].dev == st.st_dev) && (info[drive].ino == st.st_ino))
|
||||||
|
{
|
||||||
|
if (len == 1) len = 0; /* preserve root slash in returned path */
|
||||||
|
TRACE( "%s -> drive %c:, root=%s, name=%s\n",
|
||||||
|
debugstr_a(path), 'A' + drive, debugstr_a(buffer), debugstr_a(path + len));
|
||||||
|
*ppath += len;
|
||||||
|
*drive_ret = drive;
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, buffer );
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len <= 1) break; /* reached root */
|
||||||
|
len = remove_last_componentA( buffer, len );
|
||||||
|
buffer[len] = 0;
|
||||||
|
}
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, buffer );
|
||||||
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* remove_last_componentW
|
||||||
|
*
|
||||||
|
* Remove the last component of the path. Helper for find_drive_rootW.
|
||||||
|
*/
|
||||||
|
static inline int remove_last_componentW( const WCHAR *path, int len )
|
||||||
{
|
{
|
||||||
int level = 0;
|
int level = 0;
|
||||||
|
|
||||||
|
@ -122,14 +217,14 @@ static inline int remove_last_component( const WCHAR *path, int len )
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* find_drive_root
|
* find_drive_rootW
|
||||||
*
|
*
|
||||||
* Find a drive for which the root matches the beginning of the given path.
|
* Find a drive for which the root matches the beginning of the given path.
|
||||||
* This can be used to translate a Unix path into a drive + DOS path.
|
* This can be used to translate a Unix path into a drive + DOS path.
|
||||||
* Return value is the drive, or -1 on error. On success, ppath is modified
|
* Return value is the drive, or -1 on error. On success, ppath is modified
|
||||||
* to point to the beginning of the DOS path.
|
* to point to the beginning of the DOS path.
|
||||||
*/
|
*/
|
||||||
static int find_drive_root( LPCWSTR *ppath )
|
static int find_drive_rootW( LPCWSTR *ppath )
|
||||||
{
|
{
|
||||||
/* Starting with the full path, check if the device and inode match any of
|
/* Starting with the full path, check if the device and inode match any of
|
||||||
* the wine 'drives'. If not then remove the last path component and try
|
* the wine 'drives'. If not then remove the last path component and try
|
||||||
|
@ -175,7 +270,7 @@ static int find_drive_root( LPCWSTR *ppath )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lenW <= 1) break; /* reached root */
|
if (lenW <= 1) break; /* reached root */
|
||||||
lenW = remove_last_component( path, lenW );
|
lenW = remove_last_componentW( path, lenW );
|
||||||
|
|
||||||
/* we only need the new length, buffer already contains the converted string */
|
/* we only need the new length, buffer already contains the converted string */
|
||||||
lenA = ntdll_wcstoumbs( 0, path, lenW, NULL, 0, NULL, NULL );
|
lenA = ntdll_wcstoumbs( 0, path, lenW, NULL, 0, NULL, NULL );
|
||||||
|
@ -642,7 +737,7 @@ static ULONG get_full_path_helper(LPCWSTR name, LPWSTR buffer, ULONG size)
|
||||||
if (name[0] == '/') /* may be a Unix path */
|
if (name[0] == '/') /* may be a Unix path */
|
||||||
{
|
{
|
||||||
const WCHAR *ptr = name;
|
const WCHAR *ptr = name;
|
||||||
int drive = find_drive_root( &ptr );
|
int drive = find_drive_rootW( &ptr );
|
||||||
if (drive != -1)
|
if (drive != -1)
|
||||||
{
|
{
|
||||||
reqsize = 3 * sizeof(WCHAR);
|
reqsize = 3 * sizeof(WCHAR);
|
||||||
|
@ -965,3 +1060,72 @@ NTSTATUS WINAPI RtlSetCurrentDirectory_U(const UNICODE_STRING* dir)
|
||||||
RtlReleasePebLock();
|
RtlReleasePebLock();
|
||||||
return nts;
|
return nts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* wine_unix_to_nt_file_name (NTDLL.@) Not a Windows API
|
||||||
|
*/
|
||||||
|
NTSTATUS wine_unix_to_nt_file_name( const ANSI_STRING *name, UNICODE_STRING *nt )
|
||||||
|
{
|
||||||
|
static const WCHAR prefixW[] = {'\\','?','?','\\','a',':','\\'};
|
||||||
|
unsigned int lenW, lenA = name->Length;
|
||||||
|
const char *path = name->Buffer;
|
||||||
|
char *cwd;
|
||||||
|
WCHAR *p;
|
||||||
|
NTSTATUS status;
|
||||||
|
int drive;
|
||||||
|
|
||||||
|
if (!lenA || path[0] != '/')
|
||||||
|
{
|
||||||
|
char *newcwd, *end;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if ((status = DIR_get_unix_cwd( &cwd )) != STATUS_SUCCESS) return status;
|
||||||
|
|
||||||
|
size = strlen(cwd) + lenA + 1;
|
||||||
|
if (!(newcwd = RtlReAllocateHeap( GetProcessHeap(), 0, cwd, size )))
|
||||||
|
{
|
||||||
|
status = STATUS_NO_MEMORY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cwd = newcwd;
|
||||||
|
end = cwd + strlen(cwd);
|
||||||
|
if (end > cwd && end[-1] != '/') *end++ = '/';
|
||||||
|
memcpy( end, path, lenA );
|
||||||
|
lenA += end - cwd;
|
||||||
|
path = cwd;
|
||||||
|
|
||||||
|
status = find_drive_rootA( &path, lenA, &drive );
|
||||||
|
lenA -= (path - cwd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cwd = NULL;
|
||||||
|
status = find_drive_rootA( &path, lenA, &drive );
|
||||||
|
lenA -= (path - name->Buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != STATUS_SUCCESS) goto done;
|
||||||
|
while (lenA && path[0] == '/') { lenA--; path++; }
|
||||||
|
|
||||||
|
lenW = ntdll_umbstowcs( 0, path, lenA, NULL, 0 );
|
||||||
|
if (!(nt->Buffer = RtlAllocateHeap( GetProcessHeap(), 0,
|
||||||
|
(lenW + 1) * sizeof(WCHAR) + sizeof(prefixW) )))
|
||||||
|
{
|
||||||
|
status = STATUS_NO_MEMORY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy( nt->Buffer, prefixW, sizeof(prefixW) );
|
||||||
|
nt->Buffer[4] += drive;
|
||||||
|
ntdll_umbstowcs( 0, path, lenA, nt->Buffer + sizeof(prefixW)/sizeof(WCHAR), lenW );
|
||||||
|
lenW += sizeof(prefixW)/sizeof(WCHAR);
|
||||||
|
nt->Buffer[lenW] = 0;
|
||||||
|
nt->Length = lenW * sizeof(WCHAR);
|
||||||
|
nt->MaximumLength = nt->Length + sizeof(WCHAR);
|
||||||
|
for (p = nt->Buffer + sizeof(prefixW)/sizeof(WCHAR); *p; p++) if (*p == '/') *p = '\\';
|
||||||
|
|
||||||
|
done:
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, cwd );
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
|
@ -2187,6 +2187,8 @@ NTSTATUS WINAPI vDbgPrintExWithPrefix(LPCSTR,ULONG,ULONG,LPCSTR,va_list);
|
||||||
|
|
||||||
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,
|
||||||
UINT disposition, BOOLEAN check_case );
|
UINT disposition, BOOLEAN check_case );
|
||||||
|
extern NTSTATUS wine_unix_to_nt_file_name( const ANSI_STRING *name, UNICODE_STRING *nt );
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Inline functions
|
* Inline functions
|
||||||
|
|
Loading…
Reference in New Issue