diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 80a9c08aff3..d3ddadcef5b 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -69,6 +69,7 @@ C_SRCS = \ cdrom.c \ critsection.c \ debugtools.c \ + env.c \ error.c \ exception.c \ file.c \ diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c new file mode 100644 index 00000000000..9a161fa458f --- /dev/null +++ b/dlls/ntdll/env.c @@ -0,0 +1,286 @@ +/* + * Ntdll environment functions + * + * Copyright 1996, 1998 Alexandre Julliard + * Copyright 2003 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" + +#include + +#include "winternl.h" +#include "wine/unicode.h" +#include "wine/debug.h" +#include "ntdll_misc.h" + +WINE_DEFAULT_DEBUG_CHANNEL(environ); + +/****************************************************************************** + * RtlCreateEnvironment [NTDLL.@] + */ +NTSTATUS WINAPI RtlCreateEnvironment(BOOLEAN inherit, PWSTR* env) +{ + NTSTATUS nts; + + TRACE("(%u,%p)!\n", inherit, env); + + if (inherit) + { + MEMORY_BASIC_INFORMATION mbi; + + RtlAcquirePebLock(); + + nts = NtQueryVirtualMemory(NtCurrentProcess(), ntdll_get_process_pmts()->Environment, + 0, &mbi, sizeof(mbi), NULL); + if (nts == STATUS_SUCCESS) + { + *env = NULL; + nts = NtAllocateVirtualMemory(NtCurrentProcess(), (void**)env, 0, &mbi.RegionSize, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (nts == STATUS_SUCCESS) + memcpy(*env, ntdll_get_process_pmts()->Environment, mbi.RegionSize); + else *env = NULL; + } + RtlReleasePebLock(); + } + else + { + ULONG size = 1; + nts = NtAllocateVirtualMemory(NtCurrentProcess(), (void**)env, 0, &size, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (nts == STATUS_SUCCESS) + memset(*env, 0, size); + } + + return nts; +} + +/****************************************************************************** + * RtlDestroyEnvironment [NTDLL.@] + */ +NTSTATUS WINAPI RtlDestroyEnvironment(PWSTR env) +{ + ULONG size = 0; + + TRACE("(%p)!\n", env); + + return NtFreeVirtualMemory(NtCurrentProcess(), (void**)&env, &size, MEM_RELEASE); +} + +/****************************************************************** + * RtlQueryEnvironmentVariable_U [NTDLL.@] + * + */ +NTSTATUS WINAPI RtlQueryEnvironmentVariable_U(PWSTR env, + PUNICODE_STRING name, + PUNICODE_STRING value) +{ + NTSTATUS nts = STATUS_VARIABLE_NOT_FOUND; + PWSTR var; + unsigned namelen, varlen; + + TRACE("%s %s %p\n", debugstr_w(env), debugstr_w(name->Buffer), value); + + value->Length = 0; + namelen = name->Length / sizeof(WCHAR); + if (!namelen) return nts; + + if (!env) + { + RtlAcquirePebLock(); + var = ntdll_get_process_pmts()->Environment; + } + else var = env; + + for (; *var; var += varlen + 1) + { + varlen = strlenW(var); + /* match var names, but avoid setting a var with a name including a '=' + * (a starting '=' is valid though) + */ + if (strncmpiW(var, name->Buffer, namelen) == 0 && var[namelen] == '=' && + strchrW(var + 1, '=') == var + namelen) + { + value->Length = (varlen - namelen - 1) * sizeof(WCHAR); + if (value->Length <= value->MaximumLength) + { + memmove(value->Buffer, var + namelen + 1, value->Length + sizeof(WCHAR)); + nts = STATUS_SUCCESS; + } + else nts = STATUS_BUFFER_TOO_SMALL; + break; + } + } + + if (!env) RtlReleasePebLock(); + + return nts; +} + +/****************************************************************** + * RtlSetCurrentEnvironment [NTDLL.@] + * + */ +void WINAPI RtlSetCurrentEnvironment(PWSTR new_env, PWSTR* old_env) +{ + TRACE("(%p %p)\n", new_env, old_env); + + RtlAcquirePebLock(); + + if (old_env) *old_env = ntdll_get_process_pmts()->Environment; + ntdll_get_process_pmts()->Environment = new_env; + + RtlReleasePebLock(); +} + + +/****************************************************************************** + * RtlSetEnvironmentVariable [NTDLL.@] + */ +NTSTATUS WINAPI RtlSetEnvironmentVariable(PWSTR* penv, PUNICODE_STRING name, + PUNICODE_STRING value) +{ + INT len, old_size; + LPWSTR p, env; + NTSTATUS nts = STATUS_VARIABLE_NOT_FOUND; + MEMORY_BASIC_INFORMATION mbi; + + TRACE("(%p,%s,%s): stub!\n", penv, debugstr_w(name->Buffer), debugstr_w(value->Buffer)); + + if (!name || !name->Buffer || !name->Buffer[0]) + return STATUS_INVALID_PARAMETER_1; + /* variable names can't contain a '=' except as a first character */ + if (strchrW(name->Buffer + 1, '=')) return STATUS_INVALID_PARAMETER; + + if (!penv) + { + RtlAcquirePebLock(); + env = ntdll_get_process_pmts()->Environment; + } else env = *penv; + + len = name->Length / sizeof(WCHAR); + + /* compute current size of environment */ + for (p = env; *p; p += strlenW(p) + 1); + old_size = p + 1 - env; + + /* Find a place to insert the string */ + for (p = env; *p; p += strlenW(p) + 1) + { + if (!strncmpiW(name->Buffer, p, len) && (p[len] == '=')) break; + } + if (!value && !*p) goto done; /* Value to remove doesn't exist */ + + /* Realloc the buffer */ + len = value ? len + value->Length / sizeof(WCHAR) + 2 : 0; + if (*p) len -= strlenW(p) + 1; /* The name already exists */ + + if (len < 0) + { + LPWSTR next = p + strlenW(p) + 1; /* We know there is a next one */ + memmove(next + len, next, (old_size - (next - env)) * sizeof(WCHAR)); + } + + nts = NtQueryVirtualMemory(NtCurrentProcess(), env, 0, + &mbi, sizeof(mbi), NULL); + if (nts != STATUS_SUCCESS) goto done; + + if ((old_size + len) * sizeof(WCHAR) > mbi.RegionSize) + { + LPWSTR new_env; + ULONG new_size = (old_size + len) * sizeof(WCHAR); + + new_env = NULL; + nts = NtAllocateVirtualMemory(NtCurrentProcess(), (void**)&new_env, 0, + &new_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (nts != STATUS_SUCCESS) goto done; + + memmove(new_env, env, (p - env) * sizeof(WCHAR)); + assert(len > 0); + memmove(new_env + (p - env) + len, p, (old_size - (p - env)) * sizeof(WCHAR)); + p = new_env + (p - env); + + RtlDestroyEnvironment(env); + if (!penv) ntdll_get_process_pmts()->Environment = new_env; + else *penv = new_env; + env = new_env; + } + else + { + if (len > 0) memmove(p + len, p, (old_size - (p - env)) * sizeof(WCHAR)); + } + + /* Set the new string */ + if (value) + { + static const WCHAR equalW[] = {'=',0}; + + strcpyW(p, name->Buffer); + strcatW(p, equalW); + strcatW(p, value->Buffer); + } + +done: + if (!penv) RtlReleasePebLock(); + + return nts; +} + +/*********************************************************************** + * build_environment + * + * Build the Win32 environment from the Unix environment + */ +BOOL build_initial_environment(void) +{ + extern char **environ; + LPSTR* e, te; + LPWSTR p; + ULONG size; + NTSTATUS nts; + int len; + + /* Compute the total size of the Unix environment */ + size = sizeof(BYTE); + for (e = environ; *e; e++) + { + if (!memcmp(*e, "PATH=", 5)) continue; + size += strlen(*e) + 1; + } + size *= sizeof(WCHAR); + + /* Now allocate the environment */ + nts = NtAllocateVirtualMemory(NtCurrentProcess(), (void**)&p, 0, &size, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (nts != STATUS_SUCCESS) return FALSE; + + ntdll_get_process_pmts()->Environment = p; + /* And fill it with the Unix environment */ + for (e = environ; *e; e++) + { + /* skip Unix PATH and store WINEPATH as PATH */ + if (!memcmp(*e, "PATH=", 5)) continue; + if (!memcmp(*e, "WINEPATH=", 9 )) te = *e + 4; else te = *e; + len = strlen(te); + RtlMultiByteToUnicodeN(p, len * sizeof(WCHAR), NULL, te, len); + p[len] = 0; + p += len + 1; + } + *p = 0; + + return TRUE; +} diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 86eb38cfff0..d15f7d59b2a 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -319,7 +319,7 @@ @ stdcall RtlCopyUnicodeString(ptr ptr) @ stdcall RtlCreateAcl(ptr long long) @ stub RtlCreateAndSetSD -@ stdcall RtlCreateEnvironment(long long) +@ stdcall RtlCreateEnvironment(long ptr) @ stdcall RtlCreateHeap(long ptr long long ptr ptr) @ stub RtlCreateProcessParameters @ stub RtlCreateQueryDebugBuffer @@ -343,7 +343,7 @@ @ stub RtlDeleteRegistryValue @ stdcall RtlDeleteResource(ptr) @ stdcall RtlDeleteSecurityObject(long) -@ stdcall RtlDestroyEnvironment(long) +@ stdcall RtlDestroyEnvironment(ptr) @ stdcall RtlDestroyHeap(long) @ stub RtlDestroyProcessParameters @ stub RtlDestroyQueryDebugBuffer @@ -484,7 +484,7 @@ @ stdcall RtlPrefixString(ptr ptr long) @ stdcall RtlPrefixUnicodeString(ptr ptr long) @ stub RtlProtectHeap -@ stdcall RtlQueryEnvironmentVariable_U(long long long) +@ stdcall RtlQueryEnvironmentVariable_U(ptr ptr ptr) @ stub RtlQueryInformationAcl @ stub RtlQueryProcessBackTraceInformation @ stub RtlQueryProcessDebugInformation @@ -512,9 +512,9 @@ @ stdcall RtlSetAllBits(ptr) @ stdcall RtlSetBits(ptr long long) @ stub RtlSetCurrentDirectory_U -@ stub RtlSetCurrentEnvironment +@ stdcall RtlSetCurrentEnvironment(wstr ptr) @ stdcall RtlSetDaclSecurityDescriptor(ptr long ptr long) -@ stdcall RtlSetEnvironmentVariable(long long long) +@ stdcall RtlSetEnvironmentVariable(ptr ptr ptr) @ stdcall RtlSetGroupSecurityDescriptor(ptr ptr long) @ stub RtlSetInformationAcl @ stdcall RtlSetOwnerSecurityDescriptor(ptr ptr long) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index a8aa6dffda4..bc8e6ce9994 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -40,9 +40,59 @@ extern FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *expor FARPROC origfun, DWORD ordinal ); extern void RELAY_SetupDLL( const char *module ); +typedef struct RTL_DRIVE_LETTER_CURDIR +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + UNICODE_STRING DosPath; +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + +typedef struct _RTL_USER_PROCESS_PARAMETERS +{ + ULONG AllocationSize; + ULONG Size; + ULONG Flags; + ULONG DebugFlags; + HANDLE hConsole; + ULONG ProcessGroup; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + UNICODE_STRING CurrentDirectoryName; + HANDLE CurrentDirectoryHandle; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + PWSTR Environment; + ULONG dwX; + ULONG dwY; + ULONG dwXSize; + ULONG dwYSize; + ULONG dwXCountChars; + ULONG dwYCountChars; + ULONG dwFillAttribute; + ULONG dwFlags; + ULONG wShowWindow; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopInfo; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeInfo; + RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; + static inline HANDLE ntdll_get_process_heap(void) { HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process; return pdb[0x18 / sizeof(HANDLE)]; /* get dword at offset 0x18 in pdb */ } + +/* FIXME: this should be part of PEB, once it's defined */ +extern RTL_USER_PROCESS_PARAMETERS process_pmts; +BOOL build_initial_environment(void); + +static inline RTL_USER_PROCESS_PARAMETERS* ntdll_get_process_pmts(void) +{ + return &process_pmts; +} #endif diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c index 77ad84c810a..b73fec5583b 100644 --- a/dlls/ntdll/rtl.c +++ b/dlls/ntdll/rtl.c @@ -315,14 +315,6 @@ VOID WINAPI RtlReleasePebLock(void) RtlLeaveCriticalSection( &peb_lock ); } -/****************************************************************************** - * RtlSetEnvironmentVariable [NTDLL.@] - */ -DWORD WINAPI RtlSetEnvironmentVariable(DWORD x1,PUNICODE_STRING key,PUNICODE_STRING val) { - FIXME("(0x%08lx,%s,%s),stub!\n",x1,debugstr_w(key->Buffer),debugstr_w(val->Buffer)); - return 0; -} - /****************************************************************************** * RtlNewSecurityObject [NTDLL.@] */ @@ -427,31 +419,6 @@ BOOLEAN WINAPI RtlDosPathNameToNtPathName_U( } -/****************************************************************************** - * RtlCreateEnvironment [NTDLL.@] - */ -DWORD WINAPI RtlCreateEnvironment(DWORD x1,DWORD x2) { - FIXME("(0x%08lx,0x%08lx),stub!\n",x1,x2); - return 0; -} - - -/****************************************************************************** - * RtlDestroyEnvironment [NTDLL.@] - */ -DWORD WINAPI RtlDestroyEnvironment(DWORD x) { - FIXME("(0x%08lx),stub!\n",x); - return 0; -} - -/****************************************************************************** - * RtlQueryEnvironmentVariable_U [NTDLL.@] - */ -DWORD WINAPI RtlQueryEnvironmentVariable_U(DWORD x1,PUNICODE_STRING key,PUNICODE_STRING val) { - FIXME("(0x%08lx,%s,%p),stub!\n",x1,debugstr_w(key->Buffer),val); - return 0; -} - /****************************************************************************** * RtlInitializeGenericTable [NTDLL.@] */ @@ -652,8 +619,8 @@ VOID WINAPI RtlFillMemoryUlong(ULONG* lpDest, ULONG ulCount, ULONG ulValue) */ DWORD WINAPI RtlGetLongestNtPathLength(void) { - TRACE("()\n"); - return 277; + TRACE("()\n"); + return 277; } /********************************************************************* diff --git a/include/winternl.h b/include/winternl.h index 876ed13faa2..77f92fb908d 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -951,7 +951,7 @@ DWORD WINAPI RtlCopySid(DWORD,PSID,PSID); void WINAPI RtlCopyString(STRING*,const STRING*); void WINAPI RtlCopyUnicodeString(UNICODE_STRING*,const UNICODE_STRING*); NTSTATUS WINAPI RtlCreateAcl(PACL,DWORD,DWORD); -DWORD WINAPI RtlCreateEnvironment(DWORD,DWORD); +NTSTATUS WINAPI RtlCreateEnvironment(BOOLEAN, PWSTR*); HANDLE WINAPI RtlCreateHeap(ULONG,PVOID,ULONG,ULONG,PVOID,PRTL_HEAP_DEFINITION); NTSTATUS WINAPI RtlCreateSecurityDescriptor(PSECURITY_DESCRIPTOR,DWORD); BOOLEAN WINAPI RtlCreateUnicodeString(PUNICODE_STRING,LPCWSTR); @@ -960,7 +960,7 @@ BOOLEAN WINAPI RtlCreateUnicodeStringFromAsciiz(PUNICODE_STRING,LPCSTR); NTSTATUS WINAPI RtlDeleteCriticalSection(RTL_CRITICAL_SECTION *); void WINAPI RtlDeleteResource(LPRTL_RWLOCK); DWORD WINAPI RtlDeleteSecurityObject(DWORD); -DWORD WINAPI RtlDestroyEnvironment(DWORD); +NTSTATUS WINAPI RtlDestroyEnvironment(PWSTR); HANDLE WINAPI RtlDestroyHeap(HANDLE); DOS_PATHNAME_TYPE WINAPI RtlDetermineDosPathNameType_U(PCWSTR); BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(LPWSTR,PUNICODE_STRING,DWORD,DWORD); @@ -1076,7 +1076,7 @@ DWORD WINAPI RtlOpenCurrentUser(ACCESS_MASK,PHKEY); BOOLEAN WINAPI RtlPrefixString(const STRING*,const STRING*,BOOLEAN); BOOLEAN WINAPI RtlPrefixUnicodeString(const UNICODE_STRING*,const UNICODE_STRING*,BOOLEAN); -DWORD WINAPI RtlQueryEnvironmentVariable_U(DWORD,PUNICODE_STRING,PUNICODE_STRING) ; +NTSTATUS WINAPI RtlQueryEnvironmentVariable_U(PWSTR,PUNICODE_STRING,PUNICODE_STRING); NTSTATUS WINAPI RtlQueryTimeZoneInformation(LPTIME_ZONE_INFORMATION); void WINAPI RtlRaiseException(PEXCEPTION_RECORD); @@ -1090,8 +1090,9 @@ void WINAPI RtlSecondsSince1970ToTime(DWORD,LARGE_INTEGER *); void WINAPI RtlSecondsSince1980ToTime(DWORD,LARGE_INTEGER *); void WINAPI RtlSetAllBits(PRTL_BITMAP); void WINAPI RtlSetBits(PRTL_BITMAP,ULONG,ULONG); +void WINAPI RtlSetCurrentEnvironment(PWSTR, PWSTR*); NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR,BOOLEAN,PACL,BOOLEAN); -DWORD WINAPI RtlSetEnvironmentVariable(DWORD,PUNICODE_STRING,PUNICODE_STRING); +NTSTATUS WINAPI RtlSetEnvironmentVariable(PWSTR*,PUNICODE_STRING,PUNICODE_STRING); NTSTATUS WINAPI RtlSetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR,PSID,BOOLEAN); NTSTATUS WINAPI RtlSetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR,PSID,BOOLEAN); NTSTATUS WINAPI RtlSetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR,BOOLEAN,PACL,BOOLEAN); diff --git a/scheduler/process.c b/scheduler/process.c index 63769a781fc..72c8a809472 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -46,6 +46,7 @@ #include "wine/server.h" #include "options.h" #include "wine/debug.h" +#include "ntdll_misc.h" WINE_DEFAULT_DEBUG_CHANNEL(process); WINE_DECLARE_DEBUG_CHANNEL(relay); @@ -106,6 +107,8 @@ typedef struct _PDB PDB current_process; +RTL_USER_PROCESS_PARAMETERS process_pmts; + /* Process flags */ #define PDB32_DEBUGGED 0x0001 /* Process is being debugged */ #define PDB32_WIN16_PROC 0x0008 /* Win16 process */