Commit 528f9d32 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Set the initial environment and command line in the process parameters on the Unix side.

parent 0d3972ce
......@@ -361,52 +361,6 @@ static void set_wow64_environment( WCHAR **env )
/***********************************************************************
* build_initial_environment
*
* Build the Win32 environment from the Unix environment
*/
static WCHAR *build_initial_environment( WCHAR **wargv[] )
{
SIZE_T size = 1024;
WCHAR *ptr;
for (;;)
{
if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL;
if (!unix_funcs->get_initial_environment( wargv, ptr, &size )) break;
RtlFreeHeap( GetProcessHeap(), 0, ptr );
}
first_prefix_start = set_registry_environment( &ptr, TRUE );
set_additional_environment( &ptr );
return ptr;
}
/***********************************************************************
* get_current_directory
*
* Initialize the current directory from the Unix cwd.
*/
static void get_current_directory( UNICODE_STRING *dir )
{
unix_funcs->get_initial_directory( dir );
if (!dir->Length) /* still not initialized */
{
dir->Length = wcslen( windows_dir ) * sizeof(WCHAR);
memcpy( dir->Buffer, windows_dir, dir->Length );
}
/* add trailing backslash */
if (dir->Buffer[dir->Length / sizeof(WCHAR) - 1] != '\\')
{
dir->Buffer[dir->Length / sizeof(WCHAR)] = '\\';
dir->Length += sizeof(WCHAR);
}
dir->Buffer[dir->Length / sizeof(WCHAR)] = 0;
}
/***********************************************************************
* is_path_prefix
*/
static inline BOOL is_path_prefix( const WCHAR *prefix, const WCHAR *path, const WCHAR *file )
......@@ -422,22 +376,22 @@ static inline BOOL is_path_prefix( const WCHAR *prefix, const WCHAR *path, const
/***********************************************************************
* get_image_path
*/
static void get_image_path( const WCHAR *name, UNICODE_STRING *path )
static void get_image_path( const WCHAR *name, WCHAR *full_name, UINT size )
{
WCHAR *load_path, *file_part, full_name[MAX_PATH];
WCHAR *load_path, *file_part;
DWORD len;
if (RtlDetermineDosPathNameType_U( name ) != RELATIVE_PATH ||
wcschr( name, '/' ) || wcschr( name, '\\' ))
{
len = RtlGetFullPathName_U( name, sizeof(full_name), full_name, &file_part );
if (!len || len > sizeof(full_name)) goto failed;
len = RtlGetFullPathName_U( name, size, full_name, &file_part );
if (!len || len > size) goto failed;
/* try first without extension */
if (RtlDoesFileExists_U( full_name )) goto done;
if (len < (MAX_PATH - 4) * sizeof(WCHAR) && !wcschr( file_part, '.' ))
if (RtlDoesFileExists_U( full_name )) return;
if (len < size - 4 * sizeof(WCHAR) && !wcschr( file_part, '.' ))
{
wcscat( file_part, L".exe" );
if (RtlDoesFileExists_U( full_name )) goto done;
if (RtlDoesFileExists_U( full_name )) return;
}
/* check for builtin path inside system directory */
if (!is_path_prefix( system_dir, full_name, file_part ))
......@@ -449,20 +403,18 @@ static void get_image_path( const WCHAR *name, UNICODE_STRING *path )
else
{
RtlGetExePath( name, &load_path );
len = RtlDosSearchPath_U( load_path, name, L".exe", sizeof(full_name), full_name, &file_part );
len = RtlDosSearchPath_U( load_path, name, L".exe", size, full_name, &file_part );
RtlReleasePath( load_path );
if (!len || len > sizeof(full_name))
if (!len || len > size)
{
/* build builtin path inside system directory */
len = wcslen( system_dir );
if (wcslen( name ) >= MAX_PATH - 4 - len) goto failed;
if (wcslen( name ) >= size/sizeof(WCHAR) - 4 - len) goto failed;
wcscpy( full_name, system_dir );
wcscat( full_name, name );
if (!wcschr( name, '.' )) wcscat( full_name, L".exe" );
}
}
done:
RtlCreateUnicodeString( path, full_name );
return;
failed:
......@@ -471,96 +423,6 @@ failed:
}
/***********************************************************************
* build_command_line
*
* Build the command line of a process from the argv array.
*
* Note that it does NOT necessarily include the file name.
* Sometimes we don't even have any command line options at all.
*
* We must quote and escape characters so that the argv array can be rebuilt
* from the command line:
* - spaces and tabs must be quoted
* 'a b' -> '"a b"'
* - quotes must be escaped
* '"' -> '\"'
* - if '\'s are followed by a '"', they must be doubled and followed by '\"',
* resulting in an odd number of '\' followed by a '"'
* '\"' -> '\\\"'
* '\\"' -> '\\\\\"'
* - '\'s are followed by the closing '"' must be doubled,
* resulting in an even number of '\' followed by a '"'
* ' \' -> '" \\"'
* ' \\' -> '" \\\\"'
* - '\'s that are not followed by a '"' can be left as is
* 'a\b' == 'a\b'
* 'a\\b' == 'a\\b'
*/
static void build_command_line( WCHAR **argv, UNICODE_STRING *cmdline )
{
int len;
WCHAR **arg;
LPWSTR p;
len = 1;
for (arg = argv; *arg; arg++) len += 3 + 2 * wcslen( *arg );
if (!(cmdline->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
p = cmdline->Buffer;
for (arg = argv; *arg; arg++)
{
BOOL has_space, has_quote;
int i, bcount;
WCHAR *a;
/* check for quotes and spaces in this argument */
if (arg == argv || !**arg) has_space = TRUE;
else has_space = wcschr( *arg, ' ' ) || wcschr( *arg, '\t' );
has_quote = wcschr( *arg, '"' ) != NULL;
/* now transfer it to the command line */
if (has_space) *p++ = '"';
if (has_quote || has_space)
{
bcount = 0;
for (a = *arg; *a; a++)
{
if (*a == '\\') bcount++;
else
{
if (*a == '"') /* double all the '\\' preceding this '"', plus one */
for (i = 0; i <= bcount; i++) *p++ = '\\';
bcount = 0;
}
*p++ = *a;
}
}
else
{
wcscpy( p, *arg );
p += wcslen( p );
}
if (has_space)
{
/* Double all the '\' preceding the closing quote */
for (i = 0; i < bcount; i++) *p++ = '\\';
*p++ = '"';
}
*p++ = ' ';
}
if (p > cmdline->Buffer) p--; /* remove last space */
*p = 0;
if (p - cmdline->Buffer >= 32767)
{
ERR( "command line too long (%u)\n", (DWORD)(p - cmdline->Buffer) );
NtTerminateProcess( GetCurrentProcess(), 1 );
}
cmdline->Length = (p - cmdline->Buffer) * sizeof(WCHAR);
cmdline->MaximumLength = cmdline->Length + sizeof(WCHAR);
}
/******************************************************************************
* RtlCreateEnvironment [NTDLL.@]
*/
......@@ -1168,58 +1030,62 @@ wait:
*/
void init_user_process_params(void)
{
WCHAR *env, *load_path, *dummy;
WCHAR *env, *load_path, *dummy, image[MAX_PATH];
SIZE_T env_size;
RTL_USER_PROCESS_PARAMETERS *new_params, *params = NtCurrentTeb()->Peb->ProcessParameters;
UNICODE_STRING curdir, dllpath, cmdline;
WCHAR **wargv;
/* environment needs to be a separate memory block */
env_size = params->EnvironmentSize;
env = params->Environment;
if ((env = RtlAllocateHeap( GetProcessHeap(), 0, max( env_size, sizeof(WCHAR) ))))
{
if (env_size) memcpy( env, params->Environment, env_size );
else env[0] = 0;
params->Environment = env;
}
if (!params->DllPath.MaximumLength) /* not inherited from parent process */
{
WCHAR curdir_buffer[MAX_PATH];
first_prefix_start = set_registry_environment( &params->Environment, TRUE );
set_additional_environment( &params->Environment );
get_image_path( params->ImagePathName.Buffer, image, sizeof(image) );
RtlInitUnicodeString( &params->ImagePathName, image );
cmdline.Length = params->ImagePathName.Length + params->CommandLine.MaximumLength + 3 * sizeof(WCHAR);
cmdline.MaximumLength = cmdline.Length + sizeof(WCHAR);
cmdline.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, cmdline.MaximumLength );
swprintf( cmdline.Buffer, cmdline.MaximumLength / sizeof(WCHAR),
L"\"%s\" %s", params->ImagePathName.Buffer, params->CommandLine.Buffer );
params->Environment = build_initial_environment( &wargv );
curdir.Buffer = curdir_buffer;
curdir.MaximumLength = sizeof(curdir_buffer);
get_current_directory( &curdir );
params->CurrentDirectory.DosPath = curdir;
get_image_path( wargv[0], &params->ImagePathName );
wargv[0] = params->ImagePathName.Buffer;
build_command_line( wargv, &cmdline );
LdrGetDllPath( params->ImagePathName.Buffer, 0, &load_path, &dummy );
RtlInitUnicodeString( &dllpath, load_path );
env = params->Environment;
params->Environment = NULL; /* avoid copying it */
if (RtlCreateProcessParametersEx( &new_params, &params->ImagePathName, &dllpath, &curdir,
if (RtlCreateProcessParametersEx( &new_params, &params->ImagePathName, &dllpath,
&params->CurrentDirectory.DosPath,
&cmdline, NULL, &params->ImagePathName, NULL, NULL, NULL,
PROCESS_PARAMS_FLAG_NORMALIZED ))
return;
new_params->Environment = env;
NtCurrentTeb()->Peb->ProcessParameters = new_params;
RtlFreeUnicodeString( &params->ImagePathName );
new_params->hStdInput = params->hStdInput;
new_params->hStdOutput = params->hStdOutput;
new_params->hStdError = params->hStdError;
new_params->ConsoleHandle = params->ConsoleHandle;
new_params->dwXCountChars = params->dwXCountChars;
new_params->dwYCountChars = params->dwYCountChars;
new_params->wShowWindow = params->wShowWindow;
NtCurrentTeb()->Peb->ProcessParameters = params = new_params;
RtlFreeUnicodeString( &cmdline );
RtlReleasePath( load_path );
params = new_params;
unix_funcs->get_initial_console( params );
params->wShowWindow = 1; /* SW_SHOWNORMAL */
run_wineboot( &params->Environment );
goto done;
}
/* environment needs to be a separate memory block */
env_size = params->EnvironmentSize;
if ((env = RtlAllocateHeap( GetProcessHeap(), 0, max( env_size, sizeof(WCHAR) ))))
{
if (env_size) memcpy( env, params->Environment, env_size );
else env[0] = 0;
params->Environment = env;
}
done:
if (RtlSetCurrentDirectory_U( &params->CurrentDirectory.DosPath ))
{
MESSAGE("wine: could not open working directory %s, starting in the Windows directory.\n",
......
......@@ -165,11 +165,11 @@ static NTSTATUS open_nls_data_file( ULONG type, ULONG id, HANDLE *file )
if (!path) return STATUS_OBJECT_NAME_NOT_FOUND;
/* try to open file in system dir */
ntdll_wcscpy( buffer, type == NLS_SECTION_SORTKEYS ? sortdirW : systemdirW );
wcscpy( buffer, type == NLS_SECTION_SORTKEYS ? sortdirW : systemdirW );
p = strrchr( path, '/' ) + 1;
ascii_to_unicode( buffer + ntdll_wcslen(buffer), p, strlen(p) + 1 );
ascii_to_unicode( buffer + wcslen(buffer), p, strlen(p) + 1 );
valueW.Buffer = buffer;
valueW.Length = ntdll_wcslen( buffer ) * sizeof(WCHAR);
valueW.Length = wcslen( buffer ) * sizeof(WCHAR);
valueW.MaximumLength = sizeof( buffer );
InitializeObjectAttributes( &attr, &valueW, 0, 0, NULL );
......@@ -1080,12 +1080,22 @@ static const char overrides_help_message[] =
*
* Return the initial environment.
*/
NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *size )
static WCHAR *get_initial_environment( SIZE_T *ret_size )
{
char **e;
WCHAR *ptr = env, *end = env + *size;
SIZE_T size = 1;
WCHAR *env, *ptr, *end;
*wargv = main_wargv;
/* estimate needed size */
for (e = main_envp; *e; e++)
{
if (is_special_env_var( *e )) continue;
size += strlen(*e) + 1;
}
if (!(env = malloc( size * sizeof(WCHAR) ))) return NULL;
ptr = env;
end = env + size;
for (e = main_envp; *e && ptr < end; e++)
{
char *str = *e;
......@@ -1105,17 +1115,9 @@ NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *siz
ptr += ntdll_umbstowcs( str, strlen(str) + 1, ptr, end - ptr );
}
if (ptr < end)
{
*ptr++ = 0;
*size = ptr - env;
return STATUS_SUCCESS;
}
/* estimate needed size */
for (e = main_envp, *size = 1; *e; e++) if (!is_special_env_var( *e )) *size += strlen(*e) + 1;
return STATUS_BUFFER_TOO_SMALL;
*ret_size = (ptr - env) * sizeof(WCHAR);
return env;
}
......@@ -1220,7 +1222,7 @@ NTSTATUS CDECL get_dynamic_environment( WCHAR *env, SIZE_T *size )
*
* Return the initial console handles.
*/
void CDECL get_initial_console( RTL_USER_PROCESS_PARAMETERS *params )
static void get_initial_console( RTL_USER_PROCESS_PARAMETERS *params )
{
int output_fd = -1;
......@@ -1264,12 +1266,13 @@ void CDECL get_initial_console( RTL_USER_PROCESS_PARAMETERS *params )
*
* Get the current directory at startup.
*/
void CDECL get_initial_directory( UNICODE_STRING *dir )
static void get_initial_directory( UNICODE_STRING *dir )
{
const char *pwd;
char *cwd;
int size;
dir->MaximumLength = MAX_PATH * sizeof(WCHAR);
dir->Length = 0;
/* try to get it from the Unix cwd */
......@@ -1320,8 +1323,22 @@ void CDECL get_initial_directory( UNICODE_STRING *dir )
}
if (!dir->Length) /* still not initialized */
{
static const WCHAR windows_dir[] = {'C',':','\\','w','i','n','d','o','w','s'};
MESSAGE("Warning: could not find DOS drive for current working directory '%s', "
"starting in the Windows directory.\n", cwd ? cwd : "" );
memcpy( dir->Buffer, windows_dir, sizeof(windows_dir) );
dir->Length = sizeof(windows_dir);
}
/* add trailing backslash */
if (dir->Buffer[dir->Length / sizeof(WCHAR) - 1] != '\\')
{
dir->Buffer[dir->Length / sizeof(WCHAR)] = '\\';
dir->Length += sizeof(WCHAR);
}
dir->Buffer[dir->Length / sizeof(WCHAR)] = 0;
free( cwd );
}
......@@ -1349,6 +1366,91 @@ void CDECL get_locales( WCHAR *sys, WCHAR *user )
}
/***********************************************************************
* build_command_line
*
* Build the command line of a process from the argv array.
*
* We must quote and escape characters so that the argv array can be rebuilt
* from the command line:
* - spaces and tabs must be quoted
* 'a b' -> '"a b"'
* - quotes must be escaped
* '"' -> '\"'
* - if '\'s are followed by a '"', they must be doubled and followed by '\"',
* resulting in an odd number of '\' followed by a '"'
* '\"' -> '\\\"'
* '\\"' -> '\\\\\"'
* - '\'s are followed by the closing '"' must be doubled,
* resulting in an even number of '\' followed by a '"'
* ' \' -> '" \\"'
* ' \\' -> '" \\\\"'
* - '\'s that are not followed by a '"' can be left as is
* 'a\b' == 'a\b'
* 'a\\b' == 'a\\b'
*/
static WCHAR *build_command_line( WCHAR **wargv )
{
int len;
WCHAR **arg, *ret;
LPWSTR p;
len = 1;
for (arg = wargv; *arg; arg++) len += 3 + 2 * wcslen( *arg );
if (!(ret = malloc( len * sizeof(WCHAR) ))) return NULL;
p = ret;
for (arg = wargv; *arg; arg++)
{
BOOL has_space, has_quote;
int i, bcount;
WCHAR *a;
/* check for quotes and spaces in this argument */
has_space = !**arg || wcschr( *arg, ' ' ) || wcschr( *arg, '\t' );
has_quote = wcschr( *arg, '"' ) != NULL;
/* now transfer it to the command line */
if (has_space) *p++ = '"';
if (has_quote || has_space)
{
bcount = 0;
for (a = *arg; *a; a++)
{
if (*a == '\\') bcount++;
else
{
if (*a == '"') /* double all the '\\' preceding this '"', plus one */
for (i = 0; i <= bcount; i++) *p++ = '\\';
bcount = 0;
}
*p++ = *a;
}
}
else
{
wcscpy( p, *arg );
p += wcslen( p );
}
if (has_space)
{
/* Double all the '\' preceding the closing quote */
for (i = 0; i < bcount; i++) *p++ = '\\';
*p++ = '"';
}
*p++ = ' ';
}
if (p > ret) p--; /* remove last space */
*p = 0;
if (p - ret >= 32767)
{
ERR( "command line too long (%u)\n", (DWORD)(p - ret) );
NtTerminateProcess( GetCurrentProcess(), 1 );
}
return ret;
}
static inline void copy_unicode_string( WCHAR **src, WCHAR **dst, UNICODE_STRING *str, UINT len )
{
str->Buffer = *dst;
......@@ -1360,6 +1462,11 @@ static inline void copy_unicode_string( WCHAR **src, WCHAR **dst, UNICODE_STRING
*dst += len / sizeof(WCHAR) + 1;
}
static inline void put_unicode_string( WCHAR *src, WCHAR **dst, UNICODE_STRING *str )
{
copy_unicode_string( &src, dst, str, wcslen(src) * sizeof(WCHAR) );
}
/*************************************************************************
* build_initial_params
......@@ -1369,10 +1476,17 @@ static inline void copy_unicode_string( WCHAR **src, WCHAR **dst, UNICODE_STRING
static RTL_USER_PROCESS_PARAMETERS *build_initial_params(void)
{
RTL_USER_PROCESS_PARAMETERS *params = NULL;
SIZE_T size;
SIZE_T size, env_size;
WCHAR *dst;
WCHAR *cmdline = build_command_line( main_wargv + 1 );
WCHAR *env = get_initial_environment( &env_size );
NTSTATUS status;
size = sizeof(*params);
size = (sizeof(*params)
+ MAX_PATH * sizeof(WCHAR) /* curdir */
+ (wcslen( cmdline ) + 1) * sizeof(WCHAR) /* command line */
+ (wcslen( main_wargv[0] ) + 1) * sizeof(WCHAR) /* image path */
+ env_size);
status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&params, 0, &size,
MEM_COMMIT, PAGE_READWRITE );
......@@ -1382,6 +1496,22 @@ static RTL_USER_PROCESS_PARAMETERS *build_initial_params(void)
params->Size = size;
params->Flags = PROCESS_PARAMS_FLAG_NORMALIZED;
params->wShowWindow = 1; /* SW_SHOWNORMAL */
params->CurrentDirectory.DosPath.Buffer = (WCHAR *)(params + 1);
get_initial_directory( &params->CurrentDirectory.DosPath );
dst = params->CurrentDirectory.DosPath.Buffer + MAX_PATH;
put_unicode_string( main_wargv[0], &dst, &params->ImagePathName );
put_unicode_string( cmdline, &dst, &params->CommandLine );
free( cmdline );
params->Environment = dst;
params->EnvironmentSize = env_size;
memcpy( dst, env, env_size );
free( env );
get_initial_console( params );
return params;
}
......@@ -1487,7 +1617,7 @@ NTSTATUS WINAPI NtGetNlsSectionPtr( ULONG type, ULONG id, void *unknown, void **
if ((status = get_nls_section_name( type, id, name ))) return status;
nameW.Buffer = name;
nameW.Length = ntdll_wcslen(name) * sizeof(WCHAR);
nameW.Length = wcslen(name) * sizeof(WCHAR);
nameW.MaximumLength = sizeof(name);
InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
if ((status = NtOpenSection( &handle, SECTION_MAP_READ, &attr )))
......
......@@ -1607,10 +1607,7 @@ static struct unix_funcs unix_funcs =
ntdll_sin,
ntdll_sqrt,
ntdll_tan,
get_initial_environment,
get_dynamic_environment,
get_initial_console,
get_initial_directory,
get_unix_codepage_data,
get_locales,
virtual_release_address_space,
......
......@@ -99,10 +99,7 @@ extern LONGLONG CDECL fast_RtlGetSystemTimePrecise(void) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL fast_wait_cv( RTL_CONDITION_VARIABLE *variable, const void *value,
const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *size ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL get_dynamic_environment( WCHAR *env, SIZE_T *size ) DECLSPEC_HIDDEN;
extern void CDECL get_initial_directory( UNICODE_STRING *dir ) DECLSPEC_HIDDEN;
extern void CDECL get_initial_console( RTL_USER_PROCESS_PARAMETERS *params ) DECLSPEC_HIDDEN;
extern USHORT * CDECL get_unix_codepage_data(void) DECLSPEC_HIDDEN;
extern void CDECL get_locales( WCHAR *sys, WCHAR *user ) DECLSPEC_HIDDEN;
extern void CDECL virtual_release_address_space(void) DECLSPEC_HIDDEN;
......
......@@ -27,7 +27,7 @@
struct _DISPATCHER_CONTEXT;
/* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 109
#define NTDLL_UNIXLIB_VERSION 110
struct unix_funcs
{
......@@ -71,10 +71,7 @@ struct unix_funcs
double (CDECL *tan)( double d );
/* environment functions */
NTSTATUS (CDECL *get_initial_environment)( WCHAR **wargv[], WCHAR *env, SIZE_T *size );
NTSTATUS (CDECL *get_dynamic_environment)( WCHAR *env, SIZE_T *size );
void (CDECL *get_initial_console)( RTL_USER_PROCESS_PARAMETERS *params );
void (CDECL *get_initial_directory)( UNICODE_STRING *dir );
USHORT * (CDECL *get_unix_codepage_data)(void);
void (CDECL *get_locales)( WCHAR *sys, WCHAR *user );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment