ntdll: Reimplement file system redirection using NT pathname comparisons.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-04-15 12:58:22 +02:00
parent 8e7c6422e5
commit 7ef35b3393
5 changed files with 238 additions and 181 deletions

View File

@ -2133,16 +2133,21 @@ void init_startup_info(void)
/*********************************************************************** /***********************************************************************
* create_startup_info * create_startup_info
*/ */
void *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *params, DWORD *info_size ) void *create_startup_info( const UNICODE_STRING *nt_image, const RTL_USER_PROCESS_PARAMETERS *params,
DWORD *info_size )
{ {
startup_info_t *info; startup_info_t *info;
UNICODE_STRING dos_image = *nt_image;
DWORD size; DWORD size;
void *ptr; void *ptr;
dos_image.Buffer = get_dos_path( nt_image->Buffer );
dos_image.Length = nt_image->Length - (dos_image.Buffer - nt_image->Buffer) * sizeof(WCHAR);
size = sizeof(*info); size = sizeof(*info);
size += params->CurrentDirectory.DosPath.Length; size += params->CurrentDirectory.DosPath.Length;
size += params->DllPath.Length; size += params->DllPath.Length;
size += params->ImagePathName.Length; size += dos_image.Length;
size += params->CommandLine.Length; size += params->CommandLine.Length;
size += params->WindowTitle.Length; size += params->WindowTitle.Length;
size += params->Desktop.Length; size += params->Desktop.Length;
@ -2172,7 +2177,7 @@ void *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *params, DWORD *inf
ptr = info + 1; ptr = info + 1;
info->curdir_len = append_string( &ptr, params, &params->CurrentDirectory.DosPath ); info->curdir_len = append_string( &ptr, params, &params->CurrentDirectory.DosPath );
info->dllpath_len = append_string( &ptr, params, &params->DllPath ); info->dllpath_len = append_string( &ptr, params, &params->DllPath );
info->imagepath_len = append_string( &ptr, params, &params->ImagePathName ); info->imagepath_len = append_string( &ptr, params, &dos_image );
info->cmdline_len = append_string( &ptr, params, &params->CommandLine ); info->cmdline_len = append_string( &ptr, params, &params->CommandLine );
info->title_len = append_string( &ptr, params, &params->WindowTitle ); info->title_len = append_string( &ptr, params, &params->WindowTitle );
info->desktop_len = append_string( &ptr, params, &params->Desktop ); info->desktop_len = append_string( &ptr, params, &params->Desktop );

View File

@ -241,8 +241,6 @@ static mode_t start_umask;
/* at some point we may want to allow Winelib apps to set this */ /* at some point we may want to allow Winelib apps to set this */
static const BOOL is_case_sensitive = FALSE; static const BOOL is_case_sensitive = FALSE;
static struct file_identity windir;
static pthread_mutex_t dir_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t dir_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mnt_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t mnt_mutex = PTHREAD_MUTEX_INITIALIZER;
@ -2477,7 +2475,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event, PIO_APC_ROUTI
* There must be at least MAX_DIR_ENTRY_LEN+2 chars available at pos. * There must be at least MAX_DIR_ENTRY_LEN+2 chars available at pos.
*/ */
static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, int length, static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, int length,
BOOLEAN check_case, BOOLEAN *is_win_dir ) BOOLEAN check_case )
{ {
WCHAR buffer[MAX_DIR_ENTRY_LEN]; WCHAR buffer[MAX_DIR_ENTRY_LEN];
BOOLEAN is_name_8_dot_3; BOOLEAN is_name_8_dot_3;
@ -2493,11 +2491,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
if (ret >= 0 && ret <= MAX_DIR_ENTRY_LEN) if (ret >= 0 && ret <= MAX_DIR_ENTRY_LEN)
{ {
unix_name[pos + ret] = 0; unix_name[pos + ret] = 0;
if (!stat( unix_name, &st )) if (!stat( unix_name, &st )) return STATUS_SUCCESS;
{
if (is_win_dir) *is_win_dir = is_same_file( &windir, &st );
return STATUS_SUCCESS;
}
} }
if (check_case) goto not_found; /* we want an exact match */ if (check_case) goto not_found; /* we want an exact match */
@ -2536,7 +2530,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
{ {
strcpy( unix_name + pos, kde[1].d_name ); strcpy( unix_name + pos, kde[1].d_name );
close( fd ); close( fd );
goto success; return STATUS_SUCCESS;
} }
} }
ret = ntdll_umbstowcs( kde[0].d_name, strlen(kde[0].d_name), ret = ntdll_umbstowcs( kde[0].d_name, strlen(kde[0].d_name),
@ -2546,7 +2540,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
strcpy( unix_name + pos, strcpy( unix_name + pos,
kde[1].d_name[0] ? kde[1].d_name : kde[0].d_name ); kde[1].d_name[0] ? kde[1].d_name : kde[0].d_name );
close( fd ); close( fd );
goto success; return STATUS_SUCCESS;
} }
if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)kde ) == -1) if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)kde ) == -1)
{ {
@ -2573,7 +2567,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
{ {
strcpy( unix_name + pos, de->d_name ); strcpy( unix_name + pos, de->d_name );
closedir( dir ); closedir( dir );
goto success; return STATUS_SUCCESS;
} }
if (!is_name_8_dot_3) continue; if (!is_name_8_dot_3) continue;
@ -2586,7 +2580,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
{ {
strcpy( unix_name + pos, de->d_name ); strcpy( unix_name + pos, de->d_name );
closedir( dir ); closedir( dir );
goto success; return STATUS_SUCCESS;
} }
} }
} }
@ -2595,10 +2589,6 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
not_found: not_found:
unix_name[pos - 1] = 0; unix_name[pos - 1] = 0;
return STATUS_OBJECT_PATH_NOT_FOUND; return STATUS_OBJECT_PATH_NOT_FOUND;
success:
if (is_win_dir && !stat( unix_name, &st )) *is_win_dir = is_same_file( &windir, &st );
return STATUS_SUCCESS;
} }
@ -2611,116 +2601,164 @@ static const WCHAR driversetcW[] = {'s','y','s','t','e','m','3','2','\\','d','r'
static const WCHAR logfilesW[] = {'s','y','s','t','e','m','3','2','\\','l','o','g','f','i','l','e','s',0}; static const WCHAR logfilesW[] = {'s','y','s','t','e','m','3','2','\\','l','o','g','f','i','l','e','s',0};
static const WCHAR spoolW[] = {'s','y','s','t','e','m','3','2','\\','s','p','o','o','l',0}; static const WCHAR spoolW[] = {'s','y','s','t','e','m','3','2','\\','s','p','o','o','l',0};
static const WCHAR system32W[] = {'s','y','s','t','e','m','3','2',0}; static const WCHAR system32W[] = {'s','y','s','t','e','m','3','2',0};
static const WCHAR syswow64W[] = {'s','y','s','w','o','w','6','4',0};
static const WCHAR sysnativeW[] = {'s','y','s','n','a','t','i','v','e',0}; static const WCHAR sysnativeW[] = {'s','y','s','n','a','t','i','v','e',0};
static const WCHAR regeditW[] = {'r','e','g','e','d','i','t','.','e','x','e',0}; static const WCHAR regeditW[] = {'r','e','g','e','d','i','t','.','e','x','e',0};
static const WCHAR syswow64_regeditW[] = {'s','y','s','w','o','w','6','4','\\','r','e','g','e','d','i','t','.','e','x','e',0};
static const WCHAR windirW[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',0};
static const WCHAR syswow64dirW[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','w','o','w','6','4','\\'};
static struct static const WCHAR * const no_redirect[] =
{ {
const WCHAR *source; catrootW,
const char *unix_target; catroot2W,
} redirects[] = driversstoreW,
{ driversetcW,
{ catrootW, NULL }, logfilesW,
{ catroot2W, NULL }, spoolW
{ driversstoreW, NULL },
{ driversetcW, NULL },
{ logfilesW, NULL },
{ spoolW, NULL },
{ system32W, "syswow64" },
{ sysnativeW, "system32" },
{ regeditW, "syswow64/regedit.exe" }
}; };
static unsigned int nb_redirects; static struct file_identity windir, sysdir;
static inline ULONG starts_with_path( const WCHAR *name, ULONG name_len, const WCHAR *prefix )
{
ULONG len = wcslen( prefix );
if (name_len < len) return 0;
if (wcsnicmp( name, prefix, len )) return 0;
if (name_len > len && name[len] != '\\') return 0;
return len;
}
static BOOL replace_path( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *str, ULONG prefix_len,
const WCHAR *match, const WCHAR *replace )
{
const WCHAR *name = attr->ObjectName->Buffer;
ULONG match_len, replace_len, len = attr->ObjectName->Length / sizeof(WCHAR);
WCHAR *p;
if (!starts_with_path( name + prefix_len, len - prefix_len, match )) return FALSE;
match_len = wcslen( match );
replace_len = wcslen( replace );
str->Length = (len + replace_len - match_len) * sizeof(WCHAR);
str->MaximumLength = str->Length + sizeof(WCHAR);
if (!(p = str->Buffer = malloc( str->MaximumLength ))) return FALSE;
memcpy( p, name, prefix_len * sizeof(WCHAR) );
p += prefix_len;
memcpy( p, replace, replace_len * sizeof(WCHAR) );
p += replace_len;
name += prefix_len + match_len;
len -= prefix_len + match_len;
memcpy( p, name, len * sizeof(WCHAR) );
p[len] = 0;
attr->ObjectName = str;
return TRUE;
}
/*********************************************************************** /***********************************************************************
* init_redirects * init_redirects
*/ */
static void init_redirects(void) static void init_redirects(void)
{ {
static const char windows_dir[] = "/dosdevices/c:/windows"; static const char system_dir[] = "/dosdevices/c:/windows/system32";
char *dir; char *dir;
struct stat st; struct stat st;
if (!(dir = malloc( strlen(config_dir) + sizeof(windows_dir) ))) return; if (!(dir = malloc( strlen(config_dir) + sizeof(system_dir) ))) return;
strcpy( dir, config_dir ); strcpy( dir, config_dir );
strcat( dir, windows_dir ); strcat( dir, system_dir );
if (!stat( dir, &st ))
{
sysdir.dev = st.st_dev;
sysdir.ino = st.st_ino;
}
*strrchr( dir, '/' ) = 0;
if (!stat( dir, &st )) if (!stat( dir, &st ))
{ {
windir.dev = st.st_dev; windir.dev = st.st_dev;
windir.ino = st.st_ino; windir.ino = st.st_ino;
nb_redirects = ARRAY_SIZE( redirects );
} }
else ERR( "%s: %s\n", dir, strerror(errno) ); else ERR( "%s: %s\n", dir, strerror(errno) );
free( dir ); free( dir );
} }
/*********************************************************************** /***********************************************************************
* match_redirect * get_redirect
*
* Check if path matches a redirect name. If yes, return matched length.
*/ */
static int match_redirect( const WCHAR *path, int len, const WCHAR *redir, BOOLEAN check_case ) BOOL get_redirect( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *redir )
{ {
int i = 0; const WCHAR *name = attr->ObjectName->Buffer;
unsigned int i, prefix_len = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
while (i < len) redir->Buffer = NULL;
if (!NtCurrentTeb64()) return FALSE;
if (!len) return FALSE;
if (!attr->RootDirectory)
{ {
int start = i; prefix_len = wcslen( windirW );
while (i < len && !IS_SEPARATOR(path[i])) i++; if (len < prefix_len || wcsnicmp( name, windirW, prefix_len )) return FALSE;
if (check_case)
{
if (wcsncmp( path + start, redir, i - start )) return 0;
} }
else else
{ {
if (wcsnicmp( path + start, redir, i - start )) return 0; int fd, needs_close;
struct stat st;
if (server_get_unix_fd( attr->RootDirectory, 0, &fd, &needs_close, NULL, NULL )) return FALSE;
fstat( fd, &st );
if (needs_close) close( fd );
if (!is_same_file( &windir, &st ))
{
if (!is_same_file( &sysdir, &st )) return FALSE;
if (NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR]) return FALSE;
if (name[0] == '\\') return FALSE;
/* only check for paths that should NOT be redirected */
for (i = 0; i < ARRAY_SIZE( no_redirect ); i++)
if (starts_with_path( name, len, no_redirect[i] + 9 /* "system32\\" */)) return FALSE;
/* redirect everything else */
redir->Length = sizeof(syswow64dirW) + len * sizeof(WCHAR);
redir->MaximumLength = redir->Length + sizeof(WCHAR);
if (!(redir->Buffer = malloc( redir->MaximumLength ))) return FALSE;
memcpy( redir->Buffer, syswow64dirW, sizeof(syswow64dirW) );
memcpy( redir->Buffer + ARRAY_SIZE(syswow64dirW), name, len * sizeof(WCHAR) );
redir->Buffer[redir->Length / sizeof(WCHAR)] = 0;
attr->RootDirectory = 0;
attr->ObjectName = redir;
return TRUE;
} }
redir += i - start;
while (i < len && IS_SEPARATOR(path[i])) i++;
if (!*redir) return i;
if (*redir++ != '\\') return 0;
}
return 0;
} }
/* sysnative is redirected even when redirection is disabled */
/*********************************************************************** if (replace_path( attr, redir, prefix_len, sysnativeW, system32W )) return TRUE;
* get_redirect_path
*
* Retrieve the Unix path corresponding to a redirected path if any.
*/
static int get_redirect_path( char *unix_name, int pos, const WCHAR *name, int length, BOOLEAN check_case )
{
unsigned int i;
int len;
for (i = 0; i < nb_redirects; i++) if (NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR]) return FALSE;
{
if ((len = match_redirect( name, length, redirects[i].source, check_case ))) for (i = 0; i < ARRAY_SIZE( no_redirect ); i++)
{ if (starts_with_path( name + prefix_len, len - prefix_len, no_redirect[i] )) return FALSE;
if (!redirects[i].unix_target) break;
unix_name[pos++] = '/'; if (replace_path( attr, redir, prefix_len, system32W, syswow64W )) return TRUE;
strcpy( unix_name + pos, redirects[i].unix_target ); if (replace_path( attr, redir, prefix_len, regeditW, syswow64_regeditW )) return TRUE;
return len; return FALSE;
}
}
return 0;
} }
#else /* _WIN64 */ #else /* _WIN64 */
/* there are no redirects on 64-bit */ /* there are no redirects on 64-bit */
static int get_redirect_path( char *unix_name, int pos, const WCHAR *name, int length, BOOLEAN check_case ) BOOL get_redirect( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *redir )
{ {
return 0; redir->Buffer = NULL;
return FALSE;
} }
#endif #endif
#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
/*********************************************************************** /***********************************************************************
@ -3018,6 +3056,7 @@ static NTSTATUS file_id_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char *
ULONGLONG file_id; ULONGLONG file_id;
struct stat st, root_st; struct stat st, root_st;
nt_name->Buffer = NULL;
if (attr->ObjectName->Length != sizeof(ULONGLONG)) return STATUS_OBJECT_PATH_SYNTAX_BAD; if (attr->ObjectName->Length != sizeof(ULONGLONG)) return STATUS_OBJECT_PATH_SYNTAX_BAD;
if (!attr->RootDirectory) return STATUS_INVALID_PARAMETER; if (!attr->RootDirectory) return STATUS_INVALID_PARAMETER;
memcpy( &file_id, attr->ObjectName->Buffer, sizeof(file_id) ); memcpy( &file_id, attr->ObjectName->Buffer, sizeof(file_id) );
@ -3093,11 +3132,10 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
{ {
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, '/', 0 }; static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, '/', 0 };
NTSTATUS status; NTSTATUS status;
int ret, len; int ret;
struct stat st; struct stat st;
char *unix_name = *buffer; char *unix_name = *buffer;
const WCHAR *ptr, *end; const WCHAR *ptr, *end;
const BOOL redirect = NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR];
/* check syntax of individual components */ /* check syntax of individual components */
@ -3132,20 +3170,16 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
char *p; char *p;
unix_name[pos + 1 + ret] = 0; unix_name[pos + 1 + ret] = 0;
for (p = unix_name + pos ; *p; p++) if (*p == '\\') *p = '/'; for (p = unix_name + pos ; *p; p++) if (*p == '\\') *p = '/';
if (!name_len || !redirect || (!strstr( unix_name, "/windows/") && strncmp( unix_name, "windows/", 8 )))
{
if (!stat( unix_name, &st )) if (!stat( unix_name, &st ))
{ {
if (disposition == FILE_CREATE) if (disposition == FILE_CREATE) return STATUS_OBJECT_NAME_COLLISION;
return STATUS_OBJECT_NAME_COLLISION;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
} }
}
if (!name_len) /* empty name -> drive root doesn't exist */ if (!name_len) /* empty name -> drive root doesn't exist */
return STATUS_OBJECT_PATH_NOT_FOUND; return STATUS_OBJECT_PATH_NOT_FOUND;
if (is_unix && !redirect && (disposition == FILE_OPEN || disposition == FILE_OVERWRITE)) if (is_unix && (disposition == FILE_OPEN || disposition == FILE_OVERWRITE))
return STATUS_OBJECT_NAME_NOT_FOUND; return STATUS_OBJECT_NAME_NOT_FOUND;
/* now do it component by component */ /* now do it component by component */
@ -3153,7 +3187,6 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
while (name_len) while (name_len)
{ {
const WCHAR *end, *next; const WCHAR *end, *next;
BOOLEAN is_win_dir = FALSE;
end = name; end = name;
while (end < name + name_len && *end != '\\') end++; while (end < name + name_len && *end != '\\') end++;
@ -3171,8 +3204,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
unix_name = *buffer = new_name; unix_name = *buffer = new_name;
} }
status = find_file_in_dir( unix_name, pos, name, end - name, status = find_file_in_dir( unix_name, pos, name, end - name, is_unix );
is_unix, redirect ? &is_win_dir : NULL );
/* 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) if (!name_len)
@ -3202,14 +3234,6 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
pos += strlen( unix_name + pos ); pos += strlen( unix_name + pos );
name = next; name = next;
if (is_win_dir && (len = get_redirect_path( unix_name, pos, name, name_len, is_unix )))
{
name += len;
name_len -= len;
pos += strlen( unix_name + pos );
TRACE( "redirecting -> %s + %s\n", debugstr_a(unix_name), debugstr_w(name) );
}
} }
return status; return status;
@ -3220,7 +3244,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
* nt_to_unix_file_name_no_root * nt_to_unix_file_name_no_root
*/ */
static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char **unix_name_ret, static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char **unix_name_ret,
UNICODE_STRING *nt_name, UINT disposition ) UINT disposition )
{ {
static const WCHAR unixW[] = {'u','n','i','x'}; static const WCHAR unixW[] = {'u','n','i','x'};
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 }; static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 };
@ -3313,7 +3337,6 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
{ {
TRACE( "%s -> %s\n", debugstr_us(nameW), debugstr_a(unix_name) ); TRACE( "%s -> %s\n", debugstr_us(nameW), debugstr_a(unix_name) );
*unix_name_ret = unix_name; *unix_name_ret = unix_name;
if (nt_name) rebuild_nt_name( nameW, name - nameW->Buffer, unix_name + pos, nt_name );
} }
else else
{ {
@ -3333,8 +3356,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
* element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is * element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is
* returned, but the unix name is still filled in properly. * returned, but the unix name is still filled in properly.
*/ */
NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition )
UNICODE_STRING *nt_name, UINT disposition )
{ {
enum server_fd_type type; enum server_fd_type type;
int old_cwd, root_fd, needs_close; int old_cwd, root_fd, needs_close;
@ -3344,7 +3366,7 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret,
NTSTATUS status; NTSTATUS status;
if (!attr->RootDirectory) /* without root dir fall back to normal lookup */ if (!attr->RootDirectory) /* without root dir fall back to normal lookup */
return nt_to_unix_file_name_no_root( attr->ObjectName, name_ret, nt_name, disposition ); return nt_to_unix_file_name_no_root( attr->ObjectName, name_ret, disposition );
name = attr->ObjectName->Buffer; name = attr->ObjectName->Buffer;
name_len = attr->ObjectName->Length / sizeof(WCHAR); name_len = attr->ObjectName->Length / sizeof(WCHAR);
@ -3382,7 +3404,6 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret,
{ {
TRACE( "%s -> %s\n", debugstr_us(attr->ObjectName), debugstr_a(unix_name) ); TRACE( "%s -> %s\n", debugstr_us(attr->ObjectName), debugstr_a(unix_name) );
*name_ret = unix_name; *name_ret = unix_name;
if (nt_name) rebuild_nt_name( attr->ObjectName, 0, unix_name, nt_name );
} }
else else
{ {
@ -3407,10 +3428,12 @@ NTSTATUS CDECL wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, char *nam
{ {
char *buffer = NULL; char *buffer = NULL;
NTSTATUS status; NTSTATUS status;
UNICODE_STRING redir;
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
InitializeObjectAttributes( &attr, (UNICODE_STRING *)nameW, OBJ_CASE_INSENSITIVE, 0, NULL ); InitializeObjectAttributes( &attr, (UNICODE_STRING *)nameW, OBJ_CASE_INSENSITIVE, 0, NULL );
status = nt_to_unix_file_name( &attr, &buffer, NULL, disposition ); get_redirect( &attr, &redir );
status = nt_to_unix_file_name( &attr, &buffer, disposition );
if (buffer) if (buffer)
{ {
@ -3419,6 +3442,7 @@ NTSTATUS CDECL wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, char *nam
*size = strlen(buffer) + 1; *size = strlen(buffer) + 1;
free( buffer ); free( buffer );
} }
free( redir.Buffer );
return status; return status;
} }
@ -3703,7 +3727,8 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU
ULONG attributes, ULONG sharing, ULONG disposition, ULONG attributes, ULONG sharing, ULONG disposition,
ULONG options, void *ea_buffer, ULONG ea_length ) ULONG options, void *ea_buffer, ULONG ea_length )
{ {
UNICODE_STRING nt_name = { 0 }; OBJECT_ATTRIBUTES new_attr;
UNICODE_STRING nt_name;
char *unix_name; char *unix_name;
BOOL created = FALSE; BOOL created = FALSE;
@ -3717,10 +3742,17 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU
if (alloc_size) FIXME( "alloc_size not supported\n" ); if (alloc_size) FIXME( "alloc_size not supported\n" );
new_attr = *attr;
if (options & FILE_OPEN_BY_FILE_ID) if (options & FILE_OPEN_BY_FILE_ID)
io->u.Status = file_id_to_unix_file_name( attr, &unix_name, &nt_name ); {
io->u.Status = file_id_to_unix_file_name( &new_attr, &unix_name, &nt_name );
if (!io->u.Status) new_attr.ObjectName = &nt_name;
}
else else
io->u.Status = nt_to_unix_file_name( attr, &unix_name, &nt_name, disposition ); {
get_redirect( &new_attr, &nt_name );
io->u.Status = nt_to_unix_file_name( &new_attr, &unix_name, disposition );
}
if (io->u.Status == STATUS_BAD_DEVICE_TYPE) if (io->u.Status == STATUS_BAD_DEVICE_TYPE)
{ {
@ -3731,12 +3763,13 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU
req->rootdir = wine_server_obj_handle( attr->RootDirectory ); req->rootdir = wine_server_obj_handle( attr->RootDirectory );
req->sharing = sharing; req->sharing = sharing;
req->options = options; req->options = options;
wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length ); wine_server_add_data( req, new_attr.ObjectName->Buffer, new_attr.ObjectName->Length );
io->u.Status = wine_server_call( req ); io->u.Status = wine_server_call( req );
*handle = wine_server_ptr_handle( reply->handle ); *handle = wine_server_ptr_handle( reply->handle );
} }
SERVER_END_REQ; SERVER_END_REQ;
if (io->u.Status == STATUS_SUCCESS) io->Information = FILE_OPENED; if (io->u.Status == STATUS_SUCCESS) io->Information = FILE_OPENED;
free( nt_name.Buffer );
return io->u.Status; return io->u.Status;
} }
@ -3748,12 +3781,8 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU
if (io->u.Status == STATUS_SUCCESS) if (io->u.Status == STATUS_SUCCESS)
{ {
OBJECT_ATTRIBUTES nt_attr = *attr; io->u.Status = open_unix_file( handle, unix_name, access, &new_attr, attributes,
if (nt_name.Buffer) nt_attr.ObjectName = &nt_name;
io->u.Status = open_unix_file( handle, unix_name, access, &nt_attr, attributes,
sharing, disposition, options, ea_buffer, ea_length ); sharing, disposition, options, ea_buffer, ea_length );
free( nt_name.Buffer );
free( unix_name ); free( unix_name );
} }
else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status ); else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
@ -3785,6 +3814,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU
if (!once++) ERR_(winediag)( "Too many open files, ulimit -n probably needs to be increased\n" ); if (!once++) ERR_(winediag)( "Too many open files, ulimit -n probably needs to be increased\n" );
} }
free( nt_name.Buffer );
return io->u.Status; return io->u.Status;
} }
@ -3906,8 +3936,11 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
{ {
char *unix_name; char *unix_name;
NTSTATUS status; NTSTATUS status;
UNICODE_STRING redir;
OBJECT_ATTRIBUTES new_attr = *attr;
if (!(status = nt_to_unix_file_name( attr, &unix_name, NULL, FILE_OPEN ))) get_redirect( &new_attr, &redir );
if (!(status = nt_to_unix_file_name( &new_attr, &unix_name, FILE_OPEN )))
{ {
ULONG attributes; ULONG attributes;
struct stat st; struct stat st;
@ -3936,6 +3969,7 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
free( unix_name ); free( unix_name );
} }
else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status ); else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
free( redir.Buffer );
return status; return status;
} }
@ -3947,8 +3981,11 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC
{ {
char *unix_name; char *unix_name;
NTSTATUS status; NTSTATUS status;
UNICODE_STRING redir;
OBJECT_ATTRIBUTES new_attr = *attr;
if (!(status = nt_to_unix_file_name( attr, &unix_name, NULL, FILE_OPEN ))) get_redirect( &new_attr, &redir );
if (!(status = nt_to_unix_file_name( &new_attr, &unix_name, FILE_OPEN )))
{ {
ULONG attributes; ULONG attributes;
struct stat st; struct stat st;
@ -3965,6 +4002,7 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC
free( unix_name ); free( unix_name );
} }
else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status ); else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
free( redir.Buffer );
return status; return status;
} }
@ -4497,38 +4535,35 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
if (len >= sizeof(FILE_RENAME_INFORMATION)) if (len >= sizeof(FILE_RENAME_INFORMATION))
{ {
FILE_RENAME_INFORMATION *info = ptr; FILE_RENAME_INFORMATION *info = ptr;
UNICODE_STRING name_str, nt_name = { 0 }; UNICODE_STRING name_str, redir;
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
char *unix_name; char *unix_name;
name_str.Buffer = info->FileName; name_str.Buffer = info->FileName;
name_str.Length = info->FileNameLength; name_str.Length = info->FileNameLength;
name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR); name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR);
InitializeObjectAttributes( &attr, &name_str, OBJ_CASE_INSENSITIVE, info->RootDirectory, NULL );
get_redirect( &attr, &redir );
attr.Length = sizeof(attr); io->u.Status = nt_to_unix_file_name( &attr, &unix_name, FILE_OPEN_IF );
attr.ObjectName = &name_str; if (io->u.Status == STATUS_SUCCESS || io->u.Status == STATUS_NO_SUCH_FILE)
attr.RootDirectory = info->RootDirectory; {
attr.Attributes = OBJ_CASE_INSENSITIVE;
io->u.Status = nt_to_unix_file_name( &attr, &unix_name, &nt_name, FILE_OPEN_IF );
if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE)
break;
SERVER_START_REQ( set_fd_name_info ) SERVER_START_REQ( set_fd_name_info )
{ {
req->handle = wine_server_obj_handle( handle ); req->handle = wine_server_obj_handle( handle );
req->rootdir = wine_server_obj_handle( attr.RootDirectory ); req->rootdir = wine_server_obj_handle( attr.RootDirectory );
req->namelen = nt_name.Length; req->namelen = attr.ObjectName->Length;
req->link = FALSE; req->link = FALSE;
req->replace = info->ReplaceIfExists; req->replace = info->ReplaceIfExists;
wine_server_add_data( req, nt_name.Buffer, nt_name.Length ); wine_server_add_data( req, attr.ObjectName->Buffer, attr.ObjectName->Length );
wine_server_add_data( req, unix_name, strlen(unix_name) ); wine_server_add_data( req, unix_name, strlen(unix_name) );
io->u.Status = wine_server_call( req ); io->u.Status = wine_server_call( req );
} }
SERVER_END_REQ; SERVER_END_REQ;
free( unix_name ); free( unix_name );
free( nt_name.Buffer ); }
free( redir.Buffer );
} }
else io->u.Status = STATUS_INVALID_PARAMETER_3; else io->u.Status = STATUS_INVALID_PARAMETER_3;
break; break;
@ -4537,38 +4572,35 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
if (len >= sizeof(FILE_LINK_INFORMATION)) if (len >= sizeof(FILE_LINK_INFORMATION))
{ {
FILE_LINK_INFORMATION *info = ptr; FILE_LINK_INFORMATION *info = ptr;
UNICODE_STRING name_str, nt_name = { 0 }; UNICODE_STRING name_str, redir;
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
char *unix_name; char *unix_name;
name_str.Buffer = info->FileName; name_str.Buffer = info->FileName;
name_str.Length = info->FileNameLength; name_str.Length = info->FileNameLength;
name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR); name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR);
InitializeObjectAttributes( &attr, &name_str, OBJ_CASE_INSENSITIVE, info->RootDirectory, NULL );
get_redirect( &attr, &redir );
attr.Length = sizeof(attr); io->u.Status = nt_to_unix_file_name( &attr, &unix_name, FILE_OPEN_IF );
attr.ObjectName = &name_str; if (io->u.Status == STATUS_SUCCESS || io->u.Status == STATUS_NO_SUCH_FILE)
attr.RootDirectory = info->RootDirectory; {
attr.Attributes = OBJ_CASE_INSENSITIVE;
io->u.Status = nt_to_unix_file_name( &attr, &unix_name, &nt_name, FILE_OPEN_IF );
if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE)
break;
SERVER_START_REQ( set_fd_name_info ) SERVER_START_REQ( set_fd_name_info )
{ {
req->handle = wine_server_obj_handle( handle ); req->handle = wine_server_obj_handle( handle );
req->rootdir = wine_server_obj_handle( attr.RootDirectory ); req->rootdir = wine_server_obj_handle( attr.RootDirectory );
req->namelen = nt_name.Length; req->namelen = attr.ObjectName->Length;
req->link = TRUE; req->link = TRUE;
req->replace = info->ReplaceIfExists; req->replace = info->ReplaceIfExists;
wine_server_add_data( req, nt_name.Buffer, nt_name.Length ); wine_server_add_data( req, attr.ObjectName->Buffer, attr.ObjectName->Length );
wine_server_add_data( req, unix_name, strlen(unix_name) ); wine_server_add_data( req, unix_name, strlen(unix_name) );
io->u.Status = wine_server_call( req ); io->u.Status = wine_server_call( req );
} }
SERVER_END_REQ; SERVER_END_REQ;
free( unix_name ); free( unix_name );
free( nt_name.Buffer ); }
free( redir.Buffer );
} }
else io->u.Status = STATUS_INVALID_PARAMETER_3; else io->u.Status = STATUS_INVALID_PARAMETER_3;
break; break;

View File

@ -1105,6 +1105,7 @@ static NTSTATUS CDECL load_so_dll( UNICODE_STRING *nt_name, void **module )
{ {
static const WCHAR soW[] = {'.','s','o',0}; static const WCHAR soW[] = {'.','s','o',0};
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
UNICODE_STRING redir;
pe_image_info_t info; pe_image_info_t info;
char *unix_name; char *unix_name;
NTSTATUS status; NTSTATUS status;
@ -1112,7 +1113,13 @@ static NTSTATUS CDECL load_so_dll( UNICODE_STRING *nt_name, void **module )
if (get_load_order( nt_name ) == LO_DISABLED) return STATUS_DLL_NOT_FOUND; if (get_load_order( nt_name ) == LO_DISABLED) return STATUS_DLL_NOT_FOUND;
InitializeObjectAttributes( &attr, nt_name, OBJ_CASE_INSENSITIVE, 0, 0 ); InitializeObjectAttributes( &attr, nt_name, OBJ_CASE_INSENSITIVE, 0, 0 );
if (nt_to_unix_file_name( &attr, &unix_name, NULL, FILE_OPEN )) return STATUS_DLL_NOT_FOUND; get_redirect( &attr, &redir );
if (nt_to_unix_file_name( &attr, &unix_name, FILE_OPEN ))
{
free( redir.Buffer );
return STATUS_DLL_NOT_FOUND;
}
/* remove .so extension from Windows name */ /* remove .so extension from Windows name */
len = nt_name->Length / sizeof(WCHAR); len = nt_name->Length / sizeof(WCHAR);
@ -1120,6 +1127,7 @@ static NTSTATUS CDECL load_so_dll( UNICODE_STRING *nt_name, void **module )
status = dlopen_dll( unix_name, nt_name, module, &info, FALSE ); status = dlopen_dll( unix_name, nt_name, module, &info, FALSE );
free( unix_name ); free( unix_name );
free( redir.Buffer );
return status; return status;
} }
@ -1398,8 +1406,7 @@ BOOL is_builtin_path( const UNICODE_STRING *path, WORD *machine )
if (path->Length > wcslen(system_dir) * sizeof(WCHAR) && if (path->Length > wcslen(system_dir) * sizeof(WCHAR) &&
!wcsnicmp( path->Buffer, system_dir, wcslen(system_dir) )) !wcsnicmp( path->Buffer, system_dir, wcslen(system_dir) ))
{ {
if (NtCurrentTeb64() && NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR]) if (is_wow64) *machine = IMAGE_FILE_MACHINE_AMD64;
*machine = IMAGE_FILE_MACHINE_AMD64;
goto found; goto found;
} }
if ((is_win64 || is_wow64) && path->Length > sizeof(wow64W) && if ((is_win64 || is_wow64) && path->Length > sizeof(wow64W) &&
@ -1439,7 +1446,7 @@ static NTSTATUS open_main_image( WCHAR *image, void **module, SECTION_IMAGE_INFO
init_unicode_string( &nt_name, image ); init_unicode_string( &nt_name, image );
InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL ); InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
if (nt_to_unix_file_name( &attr, &unix_name, NULL, FILE_OPEN )) return STATUS_DLL_NOT_FOUND; if (nt_to_unix_file_name( &attr, &unix_name, FILE_OPEN )) return STATUS_DLL_NOT_FOUND;
status = open_dll_file( unix_name, &attr, &mapping ); status = open_dll_file( unix_name, &attr, &mapping );
if (!status) if (!status)
@ -1536,11 +1543,13 @@ NTSTATUS load_start_exe( WCHAR **image, void **module )
{ {
static const WCHAR startW[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\', static const WCHAR startW[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
's','y','s','t','e','m','3','2','\\','s','t','a','r','t','.','e','x','e',0}; 's','y','s','t','e','m','3','2','\\','s','t','a','r','t','.','e','x','e',0};
static const WCHAR startwow64W[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
's','y','s','w','o','w','6','4','\\','s','t','a','r','t','.','e','x','e',0};
UNICODE_STRING nt_name; UNICODE_STRING nt_name;
NTSTATUS status; NTSTATUS status;
SIZE_T size; SIZE_T size;
init_unicode_string( &nt_name, startW ); init_unicode_string( &nt_name, is_wow64 ? startwow64W : startW );
status = find_builtin_dll( &nt_name, module, &size, &main_image_info, current_machine, FALSE ); status = find_builtin_dll( &nt_name, module, &size, &main_image_info, current_machine, FALSE );
if (status) if (status)
{ {

View File

@ -267,12 +267,18 @@ static NTSTATUS get_pe_file_info( OBJECT_ATTRIBUTES *attr, HANDLE *handle, pe_im
{ {
NTSTATUS status; NTSTATUS status;
HANDLE mapping; HANDLE mapping;
IO_STATUS_BLOCK io; char *unix_name;
*handle = 0; *handle = 0;
memset( info, 0, sizeof(*info) ); memset( info, 0, sizeof(*info) );
if ((status = NtOpenFile( handle, GENERIC_READ, attr, &io, if (!(status = nt_to_unix_file_name( attr, &unix_name, FILE_OPEN )))
FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT ))) {
status = open_unix_file( handle, unix_name, GENERIC_READ, attr, 0,
FILE_SHARE_READ | FILE_SHARE_DELETE,
FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
free( unix_name );
}
if (status)
{ {
if (is_builtin_path( attr->ObjectName, &info->machine )) if (is_builtin_path( attr->ObjectName, &info->machine ))
{ {
@ -479,7 +485,7 @@ static NTSTATUS fork_and_exec( OBJECT_ATTRIBUTES *attr, int unixdir,
char *unix_name; char *unix_name;
NTSTATUS status; NTSTATUS status;
status = nt_to_unix_file_name( attr, &unix_name, NULL, FILE_OPEN ); status = nt_to_unix_file_name( attr, &unix_name, FILE_OPEN );
if (status) return status; if (status) return status;
#ifdef HAVE_PIPE2 #ifdef HAVE_PIPE2
@ -613,7 +619,7 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
pe_image_info_t pe_info; pe_image_info_t pe_info;
CLIENT_ID id; CLIENT_ID id;
HANDLE parent = 0, debug = 0, token = 0; HANDLE parent = 0, debug = 0, token = 0;
UNICODE_STRING path = {0}; UNICODE_STRING redir, path = {0};
OBJECT_ATTRIBUTES attr, empty_attr = { sizeof(empty_attr) }; OBJECT_ATTRIBUTES attr, empty_attr = { sizeof(empty_attr) };
SIZE_T i, attr_count = (ps_attr->TotalLength - sizeof(ps_attr->TotalLength)) / sizeof(PS_ATTRIBUTE); SIZE_T i, attr_count = (ps_attr->TotalLength - sizeof(ps_attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
const PS_ATTRIBUTE *handles_attr = NULL; const PS_ATTRIBUTE *handles_attr = NULL;
@ -655,16 +661,19 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
unixdir = get_unix_curdir( params ); unixdir = get_unix_curdir( params );
InitializeObjectAttributes( &attr, &path, OBJ_CASE_INSENSITIVE, 0, 0 ); InitializeObjectAttributes( &attr, &path, OBJ_CASE_INSENSITIVE, 0, 0 );
get_redirect( &attr, &redir );
if ((status = get_pe_file_info( &attr, &file_handle, &pe_info ))) if ((status = get_pe_file_info( &attr, &file_handle, &pe_info )))
{ {
if (status == STATUS_INVALID_IMAGE_NOT_MZ && !fork_and_exec( &attr, unixdir, params )) if (status == STATUS_INVALID_IMAGE_NOT_MZ && !fork_and_exec( &attr, unixdir, params ))
{ {
memset( info, 0, sizeof(*info) ); memset( info, 0, sizeof(*info) );
free( redir.Buffer );
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
goto done; goto done;
} }
if (!(startup_info = create_startup_info( params, &startup_info_size ))) goto done; if (!(startup_info = create_startup_info( attr.ObjectName, params, &startup_info_size ))) goto done;
env_size = get_env_size( params, &winedebug ); env_size = get_env_size( params, &winedebug );
if ((status = alloc_object_attributes( process_attr, &objattr, &attr_len ))) goto done; if ((status = alloc_object_attributes( process_attr, &objattr, &attr_len ))) goto done;
@ -830,6 +839,7 @@ done:
if (unixdir != -1) close( unixdir ); if (unixdir != -1) close( unixdir );
free( startup_info ); free( startup_info );
free( winedebug ); free( winedebug );
free( redir.Buffer );
return status; return status;
} }

View File

@ -141,7 +141,8 @@ extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN;
extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN;
extern void init_startup_info(void) DECLSPEC_HIDDEN; extern void init_startup_info(void) DECLSPEC_HIDDEN;
extern void *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *params, DWORD *info_size ) DECLSPEC_HIDDEN; extern void *create_startup_info( const UNICODE_STRING *nt_image, const RTL_USER_PROCESS_PARAMETERS *params,
DWORD *info_size ) DECLSPEC_HIDDEN;
extern DWORD ntdll_umbstowcs( const char *src, DWORD srclen, WCHAR *dst, DWORD dstlen ) DECLSPEC_HIDDEN; extern DWORD ntdll_umbstowcs( const char *src, DWORD srclen, WCHAR *dst, DWORD dstlen ) DECLSPEC_HIDDEN;
extern int ntdll_wcstoumbs( const WCHAR *src, DWORD srclen, char *dst, DWORD dstlen, BOOL strict ) DECLSPEC_HIDDEN; extern int ntdll_wcstoumbs( const WCHAR *src, DWORD srclen, char *dst, DWORD dstlen, BOOL strict ) DECLSPEC_HIDDEN;
extern char **build_envp( const WCHAR *envW ) DECLSPEC_HIDDEN; extern char **build_envp( const WCHAR *envW ) DECLSPEC_HIDDEN;
@ -250,8 +251,8 @@ extern NTSTATUS tape_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROUTI
ULONG in_size, void *out_buffer, ULONG out_size ) DECLSPEC_HIDDEN; ULONG in_size, void *out_buffer, ULONG out_size ) DECLSPEC_HIDDEN;
extern NTSTATUS errno_to_status( int err ) DECLSPEC_HIDDEN; extern NTSTATUS errno_to_status( int err ) DECLSPEC_HIDDEN;
extern NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, extern BOOL get_redirect( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *redir ) DECLSPEC_HIDDEN;
UNICODE_STRING *nt_name, UINT disposition ) DECLSPEC_HIDDEN; extern NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition ) DECLSPEC_HIDDEN;
extern NTSTATUS unix_to_nt_file_name( const char *name, WCHAR **nt ) DECLSPEC_HIDDEN; extern NTSTATUS unix_to_nt_file_name( const char *name, WCHAR **nt ) DECLSPEC_HIDDEN;
extern NTSTATUS get_full_path( const WCHAR *name, const WCHAR *curdir, WCHAR **path ) DECLSPEC_HIDDEN; extern NTSTATUS get_full_path( const WCHAR *name, const WCHAR *curdir, WCHAR **path ) DECLSPEC_HIDDEN;
extern NTSTATUS open_unix_file( HANDLE *handle, const char *unix_name, ACCESS_MASK access, extern NTSTATUS open_unix_file( HANDLE *handle, const char *unix_name, ACCESS_MASK access,