Implemented a bunch of environment related NTDLL APIs.

diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index 80a9c08..d3ddadc 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -69,6 +69,7 @@
 	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 0000000..9a161fa
--- /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 <assert.h>
+
+#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 86eb38c..d15f7d5 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 a8aa6df..bc8e6ce 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -40,9 +40,59 @@
                                      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 77ad84c..b73fec5 100644
--- a/dlls/ntdll/rtl.c
+++ b/dlls/ntdll/rtl.c
@@ -316,14 +316,6 @@
 }
 
 /******************************************************************************
- *  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.@]
  */
 DWORD WINAPI RtlNewSecurityObject(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6) {
@@ -428,31 +420,6 @@
 
 
 /******************************************************************************
- *  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.@]
  */
 PVOID WINAPI RtlInitializeGenericTable(PVOID pTable, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5)
@@ -652,8 +619,8 @@
  */
 DWORD WINAPI RtlGetLongestNtPathLength(void)
 {
-  TRACE("()\n");
-  return 277;
+    TRACE("()\n");
+    return 277;
 }
 
 /*********************************************************************
diff --git a/include/winternl.h b/include/winternl.h
index 876ed13..77f92fb 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -951,7 +951,7 @@
 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 @@
 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 @@
 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 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 63769a7..72c8a80 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 @@
 
 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 */