ntdll: Use unix_to_nt_file_name() to convert Unix paths in RtlGetFullPathName_U().

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
master
Alexandre Julliard 2020-06-20 14:36:18 +02:00
parent 339dbc586a
commit c468a36903
3 changed files with 19 additions and 248 deletions

View File

@ -25,76 +25,11 @@
#include <assert.h>
#include <sys/types.h>
#ifdef HAVE_DIRENT_H
# include <dirent.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
#endif
#ifdef HAVE_SYS_ATTR_H
#include <sys/attr.h>
#endif
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
#elif defined(MAJOR_IN_SYSMACROS)
# include <sys/sysmacros.h>
#endif
#ifdef HAVE_SYS_VNODE_H
# ifdef HAVE_STDINT_H
# include <stdint.h> /* needed for kfreebsd */
# endif
/* Work around a conflict with Solaris' system list defined in sys/list.h. */
#define list SYSLIST
#define list_next SYSLIST_NEXT
#define list_prev SYSLIST_PREV
#define list_head SYSLIST_HEAD
#define list_tail SYSLIST_TAIL
#define list_move_tail SYSLIST_MOVE_TAIL
#define list_remove SYSLIST_REMOVE
#include <sys/vnode.h>
#undef list
#undef list_next
#undef list_prev
#undef list_head
#undef list_tail
#undef list_move_tail
#undef list_remove
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_LINUX_IOCTL_H
#include <linux/ioctl.h>
#endif
#ifdef HAVE_LINUX_MAJOR_H
# include <linux/major.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#include <time.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
@ -110,73 +45,9 @@
#include "wine/exception.h"
#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
#define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/')
static BOOL show_dot_files;
static RTL_CRITICAL_SECTION dir_section;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &dir_section,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": dir_section") }
};
static RTL_CRITICAL_SECTION dir_section = { &critsect_debug, -1, 0, 0, 0, 0 };
/***********************************************************************
* DIR_get_drives_info
*
* Retrieve device/inode number for all the drives. Helper for find_drive_root.
*/
unsigned int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES] )
{
static struct drive_info cache[MAX_DOS_DRIVES];
static time_t last_update;
static unsigned int nb_drives;
unsigned int ret;
time_t now = time(NULL);
RtlEnterCriticalSection( &dir_section );
if (now != last_update)
{
char *buffer, *p;
struct stat st;
unsigned int i;
if ((buffer = RtlAllocateHeap( GetProcessHeap(), 0,
strlen(config_dir) + sizeof("/dosdevices/a:") )))
{
strcpy( buffer, config_dir );
strcat( buffer, "/dosdevices/a:" );
p = buffer + strlen(buffer) - 2;
for (i = nb_drives = 0; i < MAX_DOS_DRIVES; i++)
{
*p = 'a' + i;
if (!stat( buffer, &st ))
{
cache[i].dev = st.st_dev;
cache[i].ino = st.st_ino;
nb_drives++;
}
else
{
cache[i].dev = 0;
cache[i].ino = 0;
}
}
RtlFreeHeap( GetProcessHeap(), 0, buffer );
}
last_update = now;
}
memcpy( info, cache, sizeof(cache) );
ret = nb_drives;
RtlLeaveCriticalSection( &dir_section );
return ret;
}
/***********************************************************************
* init_directories
*/

View File

@ -40,20 +40,12 @@
#define MAX_NT_PATH_LENGTH 277
#define MAX_DOS_DRIVES 26
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
static const UINT_PTR page_size = 0x1000;
#else
extern UINT_PTR page_size DECLSPEC_HIDDEN;
#endif
struct drive_info
{
dev_t dev;
ino_t ino;
};
extern NTSTATUS close_handle( HANDLE ) DECLSPEC_HIDDEN;
/* exceptions */
@ -114,7 +106,6 @@ extern const struct unix_funcs *unix_funcs DECLSPEC_HIDDEN;
/* file I/O */
extern NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) DECLSPEC_HIDDEN;
extern void init_directories(void) DECLSPEC_HIDDEN;
extern unsigned int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES] ) DECLSPEC_HIDDEN;
/* virtual memory */
extern void virtual_fill_image_information( const pe_image_info_t *pe_info,

View File

@ -24,13 +24,6 @@
#include <stdarg.h>
#include <sys/types.h>
#include <errno.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
@ -48,98 +41,6 @@ static const WCHAR UncPfxW[] = {'U','N','C','\\',0};
#define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/')
/***********************************************************************
* 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;
while (level < 1)
{
/* find start of the last path component */
int prev = len;
if (prev <= 1) break; /* reached root */
while (prev > 1 && !IS_SEPARATOR(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 && IS_SEPARATOR(path[prev - 1])) prev--;
len = prev;
}
return len;
}
/***********************************************************************
* find_drive_rootW
*
* 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 int find_drive_rootW( LPCWSTR *ppath )
{
/* 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, lenA, lenW;
char *buffer, *p;
const WCHAR *path = *ppath;
struct stat st;
struct drive_info info[MAX_DOS_DRIVES];
/* get device and inode of all drives */
if (!DIR_get_drives_info( info )) return -1;
/* strip off trailing slashes */
lenW = wcslen(path);
while (lenW > 1 && IS_SEPARATOR(path[lenW - 1])) lenW--;
/* convert path to Unix encoding */
if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, lenW * 3 + 1 ))) return -1;
for (;;)
{
lenA = ntdll_wcstoumbs( path, lenW, buffer, lenW * 3, FALSE );
buffer[lenA] = 0;
for (p = buffer; *p; p++) if (*p == '\\') *p = '/';
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 (lenW == 1) lenW = 0; /* preserve root slash in returned path */
TRACE( "%s -> drive %c:, root=%s, name=%s\n",
debugstr_w(path), 'A' + drive, debugstr_a(buffer), debugstr_w(path + lenW));
*ppath += lenW;
RtlFreeHeap( GetProcessHeap(), 0, buffer );
return drive;
}
}
}
if (lenW <= 1) break; /* reached root */
lenW = remove_last_componentW( path, lenW );
}
RtlFreeHeap( GetProcessHeap(), 0, buffer );
return -1;
}
/***********************************************************************
* RtlDetermineDosPathNameType_U (NTDLL.@)
*/
@ -639,18 +540,26 @@ static ULONG get_full_path_helper(LPCWSTR name, LPWSTR buffer, ULONG size)
case ABSOLUTE_PATH: /* \xxx */
if (name[0] == '/') /* may be a Unix path */
{
const WCHAR *ptr = name;
int drive = find_drive_rootW( &ptr );
if (drive != -1)
char *unix_name;
ANSI_STRING unix_str;
UNICODE_STRING nt_str;
unix_name = RtlAllocateHeap( GetProcessHeap(), 0, 3 * wcslen(name) + 1 );
ntdll_wcstoumbs( name, wcslen(name) + 1, unix_name, 3 * wcslen(name) + 1, FALSE );
RtlInitAnsiString( &unix_str, unix_name );
unix_funcs->unix_to_nt_file_name( &unix_str, &nt_str );
RtlFreeAnsiString( &unix_str );
if (nt_str.Length > 5 * sizeof(WCHAR) && nt_str.Buffer[5] == ':')
{
reqsize = 3 * sizeof(WCHAR);
tmp[0] = 'A' + drive;
tmp[1] = ':';
tmp[2] = '\\';
ins_str = tmp;
mark = 3;
dep = ptr - name;
break;
reqsize = nt_str.Length - 3 * sizeof(WCHAR);
if (reqsize <= size)
{
memcpy( buffer, nt_str.Buffer + 4, reqsize );
collapse_path( buffer, 3 );
reqsize -= sizeof(WCHAR);
}
RtlFreeUnicodeString( &nt_str );
goto done;
}
}
if (cd->Buffer[1] == ':')