diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index 6bb5a993ebf..4d892fbdaa7 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -306,58 +306,3 @@ BOOLEAN WINAPI RtlDoesFileExists_U(LPCWSTR file_name) RtlFreeUnicodeString( &nt_name ); 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 ) -{ - CURDIR *curdir; - HANDLE handle; - NTSTATUS status; - ANSI_STRING name; - - 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, SYNCHRONIZE, &attr, &io, 0, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); - RtlFreeUnicodeString( &dirW ); - if (status != STATUS_SUCCESS) goto done; - } - - status = server_get_unix_name( handle, &name ); - if (!status) *cwd = name.Buffer; - - if (!curdir->Handle) NtClose( handle ); - -done: - RtlReleasePebLock(); - return status; -} diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c index 992ec19fae5..38f65c89d37 100644 --- a/dlls/ntdll/env.c +++ b/dlls/ntdll/env.c @@ -574,69 +574,13 @@ char **build_envp( const WCHAR *envW ) */ static void get_current_directory( UNICODE_STRING *dir ) { - const char *pwd; - char *cwd; - int size; - - dir->Length = 0; - - /* try to get it from the Unix cwd */ - - for (size = 1024; ; size *= 2) - { - if (!(cwd = RtlAllocateHeap( GetProcessHeap(), 0, size ))) break; - if (getcwd( cwd, size )) break; - RtlFreeHeap( GetProcessHeap(), 0, cwd ); - if (errno == ERANGE) continue; - cwd = NULL; - break; - } - - /* try to use PWD if it is valid, so that we don't resolve symlinks */ - - pwd = getenv( "PWD" ); - if (cwd) - { - struct stat st1, st2; - - if (!pwd || stat( pwd, &st1 ) == -1 || - (!stat( cwd, &st2 ) && (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino))) - pwd = cwd; - } - - if (pwd) - { - ANSI_STRING unix_name; - UNICODE_STRING nt_name; - - RtlInitAnsiString( &unix_name, pwd ); - if (!wine_unix_to_nt_file_name( &unix_name, &nt_name )) - { - /* skip the \??\ prefix */ - if (nt_name.Length > 6 * sizeof(WCHAR) && nt_name.Buffer[5] == ':') - { - dir->Length = nt_name.Length - 4 * sizeof(WCHAR); - memcpy( dir->Buffer, nt_name.Buffer + 4, dir->Length ); - } - else /* change \??\ to \\?\ */ - { - dir->Length = nt_name.Length; - memcpy( dir->Buffer, nt_name.Buffer, dir->Length ); - dir->Buffer[1] = '\\'; - } - RtlFreeUnicodeString( &nt_name ); - } - } + unix_funcs->get_initial_directory( dir ); if (!dir->Length) /* still not initialized */ { - MESSAGE("Warning: could not find DOS drive for current working directory '%s', " - "starting in the Windows directory.\n", cwd ? cwd : "" ); dir->Length = wcslen( windows_dir ) * sizeof(WCHAR); memcpy( dir->Buffer, windows_dir, dir->Length ); } - RtlFreeHeap( GetProcessHeap(), 0, cwd ); - /* add trailing backslash */ if (dir->Buffer[dir->Length / sizeof(WCHAR) - 1] != '\\') { @@ -1550,6 +1494,5 @@ done: RtlInitUnicodeString( &curdir, windows_dir ); RtlSetCurrentDirectory_U( &curdir ); } - if (!params->CurrentDirectory.Handle) chdir("/"); /* avoid locking removable devices */ set_wow64_environment( ¶ms->Environment ); } diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 2de9553f5c4..0c2941f0856 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -118,7 +118,6 @@ extern const struct unix_funcs *unix_funcs DECLSPEC_HIDDEN; extern NTSTATUS FILE_GetNtStatus(void) DECLSPEC_HIDDEN; extern NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) DECLSPEC_HIDDEN; extern void init_directories(void) DECLSPEC_HIDDEN; -extern NTSTATUS DIR_get_unix_cwd( char **cwd ) DECLSPEC_HIDDEN; extern unsigned int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES] ) DECLSPEC_HIDDEN; /* virtual memory */ diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 8b37d3dccac..de03bb566d3 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -854,6 +854,75 @@ NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *siz } +/************************************************************************* + * get_initial_directory + * + * Get the current directory at startup. + */ +void CDECL get_initial_directory( UNICODE_STRING *dir ) +{ + const char *pwd; + char *cwd; + int size; + + dir->Length = 0; + + /* try to get it from the Unix cwd */ + + for (size = 1024; ; size *= 2) + { + if (!(cwd = malloc( size ))) break; + if (getcwd( cwd, size )) break; + free( cwd ); + if (errno == ERANGE) continue; + cwd = NULL; + break; + } + + /* try to use PWD if it is valid, so that we don't resolve symlinks */ + + pwd = getenv( "PWD" ); + if (cwd) + { + struct stat st1, st2; + + if (!pwd || stat( pwd, &st1 ) == -1 || + (!stat( cwd, &st2 ) && (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino))) + pwd = cwd; + } + + if (pwd) + { + ANSI_STRING unix_name; + UNICODE_STRING nt_name; + + RtlInitAnsiString( &unix_name, pwd ); + if (!unix_to_nt_file_name( &unix_name, &nt_name )) + { + /* skip the \??\ prefix */ + if (nt_name.Length > 6 * sizeof(WCHAR) && nt_name.Buffer[5] == ':') + { + dir->Length = nt_name.Length - 4 * sizeof(WCHAR); + memcpy( dir->Buffer, nt_name.Buffer + 4, dir->Length ); + } + else /* change \??\ to \\?\ */ + { + dir->Length = nt_name.Length; + memcpy( dir->Buffer, nt_name.Buffer, dir->Length ); + dir->Buffer[1] = '\\'; + } + RtlFreeUnicodeString( &nt_name ); + } + } + + if (!dir->Length) /* still not initialized */ + MESSAGE("Warning: could not find DOS drive for current working directory '%s', " + "starting in the Windows directory.\n", cwd ? cwd : "" ); + free( cwd ); + chdir( "/" ); /* avoid locking removable devices */ +} + + /************************************************************************* * get_unix_codepage * diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index cbed3753ceb..4db78fec823 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -951,6 +951,7 @@ static struct unix_funcs unix_funcs = fast_RtlWakeConditionVariable, get_main_args, get_initial_environment, + get_initial_directory, get_paths, get_dll_path, get_unix_codepage, diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index cca6c2747bf..ddd5b4fa4c0 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -481,18 +481,26 @@ static ULONG get_env_size( const RTL_USER_PROCESS_PARAMETERS *params, char **win /*********************************************************************** * get_unix_curdir */ -static char *get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params ) +static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params ) { UNICODE_STRING nt_name; - ANSI_STRING unix_name; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; NTSTATUS status; + HANDLE handle; + int fd = -1; if (!RtlDosPathNameToNtPathName_U( params->CurrentDirectory.DosPath.Buffer, &nt_name, NULL, NULL )) - return NULL; - status = nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN_IF, FALSE ); + return -1; + InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL ); + status = NtOpenFile( &handle, FILE_TRAVERSE | SYNCHRONIZE, &attr, &io, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); RtlFreeUnicodeString( &nt_name ); - if (status && status != STATUS_NO_SUCH_FILE) return NULL; - return unix_name.Buffer; + if (status) return -1; + server_handle_to_fd( handle, FILE_TRAVERSE, &fd, NULL ); + NtClose( handle ); + return fd; } @@ -519,8 +527,8 @@ static void set_stdio_fd( int stdin_fd, int stdout_fd ) /*********************************************************************** * spawn_process */ -NTSTATUS CDECL spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd, - const char *unixdir, char *winedebug, const pe_image_info_t *pe_info ) +static NTSTATUS spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd, + int unixdir, char *winedebug, const pe_image_info_t *pe_info ) { const int is_child_64bit = (pe_info->cpu == CPU_x86_64 || pe_info->cpu == CPU_ARM64); NTSTATUS status = STATUS_SUCCESS; @@ -548,8 +556,11 @@ NTSTATUS CDECL spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int soc if (stdout_fd != -1) close( stdout_fd ); if (winedebug) putenv( winedebug ); - if (unixdir) chdir( unixdir ); - + if (unixdir != -1) + { + fchdir( unixdir ); + close( unixdir ); + } argv = build_argv( ¶ms->CommandLine, 2 ); exec_wineloader( argv, socketfd, is_child_64bit, @@ -630,7 +641,7 @@ NTSTATUS CDECL exec_process( const UNICODE_STRING *cmdline, const pe_image_info_ * * Fork and exec a new Unix binary, checking for errors. */ -static NTSTATUS fork_and_exec( UNICODE_STRING *path, const char *unix_dir, +static NTSTATUS fork_and_exec( UNICODE_STRING *path, int unixdir, const RTL_USER_PROCESS_PARAMETERS *params ) { pid_t pid; @@ -681,8 +692,11 @@ static NTSTATUS fork_and_exec( UNICODE_STRING *path, const char *unix_dir, argv = build_argv( ¶ms->CommandLine, 0 ); envp = build_envp( params->Environment ); - if (unix_dir) chdir( unix_dir ); - + if (unixdir != -1) + { + fchdir( unixdir ); + close( unixdir ); + } execve( unix_name.Buffer, argv, envp ); } @@ -741,10 +755,10 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_ HANDLE file_handle, process_info = 0, process_handle = 0, thread_handle = 0; struct object_attributes *objattr; data_size_t attr_len; - char *unixdir = NULL, *winedebug = NULL; + char *winedebug = NULL; startup_info_t *startup_info = NULL; ULONG startup_info_size, env_size; - int socketfd[2] = { -1, -1 }; + int unixdir, socketfd[2] = { -1, -1 }; pe_image_info_t pe_info; CLIENT_ID id; HANDLE parent = 0, debug = 0, token = 0; @@ -943,9 +957,9 @@ done: if (process_handle) NtClose( process_handle ); if (thread_handle) NtClose( thread_handle ); if (socketfd[0] != -1) close( socketfd[0] ); + if (unixdir != -1) close( unixdir ); RtlFreeHeap( GetProcessHeap(), 0, startup_info ); RtlFreeHeap( GetProcessHeap(), 0, winedebug ); - RtlFreeHeap( GetProcessHeap(), 0, unixdir ); return status; } diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index d8390b2f345..95d4e2c2441 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -85,6 +85,7 @@ int CDECL mmap_enum_reserved_areas( int (CDECL *enum_func)(void *base, SIZE_T s int top_down ) DECLSPEC_HIDDEN; extern void CDECL get_main_args( int *argc, char **argv[], char **envp[] ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *size ) DECLSPEC_HIDDEN; +extern void CDECL get_initial_directory( UNICODE_STRING *dir ) DECLSPEC_HIDDEN; extern void CDECL get_unix_codepage( CPTABLEINFO *table ) DECLSPEC_HIDDEN; extern void CDECL get_locales( WCHAR *sys, WCHAR *user ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zero_bits_64, SIZE_T commit_size, diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 7fd483dcabe..4169e3e8ece 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -28,7 +28,7 @@ struct ldt_copy; struct msghdr; /* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 51 +#define NTDLL_UNIXLIB_VERSION 52 struct unix_funcs { @@ -259,6 +259,7 @@ struct unix_funcs /* environment functions */ void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] ); NTSTATUS (CDECL *get_initial_environment)( WCHAR **wargv[], WCHAR *env, SIZE_T *size ); + void (CDECL *get_initial_directory)( UNICODE_STRING *dir ); void (CDECL *get_paths)( const char **builddir, const char **datadir, const char **configdir ); void (CDECL *get_dll_path)( const char ***paths, SIZE_T *maxlen ); void (CDECL *get_unix_codepage)( CPTABLEINFO *table );