update for HEAD-2003091401
[reactos.git] / lib / ntdll / rtl / env.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS system libraries
5  * FILE:            lib/ntdll/rtl/env.c
6  * PURPOSE:         Environment functions
7  * PROGRAMMER:      Eric Kohl
8  * UPDATE HISTORY:
9  *                  Created 30/09/98
10  */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <ntdll/rtl.h>
16 #include <napi/teb.h>
17 #include <string.h>
18
19 #define NDEBUG
20 #include <ntdll/ntdll.h>
21
22
23 /* FUNCTIONS *****************************************************************/
24
25 /*
26  * @implemented
27  */
28 NTSTATUS STDCALL
29 RtlCreateEnvironment(BOOLEAN Inherit,
30                      PWSTR *Environment)
31 {
32   PVOID EnvPtr = NULL;
33   NTSTATUS Status = STATUS_SUCCESS;
34   ULONG RegionSize = PAGE_SIZE;
35
36   if (Inherit == TRUE)
37     {
38       RtlAcquirePebLock();
39 #if 0
40       if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
41         {
42           Status = NtQueryVirtualMemory(NtCurrentProcess(),
43                                         NtCurrentPeb()->ProcessParameters->Environment,
44                                         MemoryBasicInformation,
45                                         &MemInfo,
46                                         sizeof(MEMORY_BASIC_INFORMATION),
47                                         NULL);
48           if (!NT_SUCCESS(Status))
49             {
50               RtlReleasePebLock();
51               *Environment = NULL;
52               return(Status);
53             }
54
55           RegionSize = MemInfo.RegionSize;
56           Status = NtAllocateVirtualMemory(NtCurrentProcess(),
57                                            &EnvPtr,
58                                            0,
59                                            &RegionSize,
60                                            MEM_RESERVE | MEM_COMMIT,
61                                            PAGE_READWRITE);
62           if (!NT_SUCCESS(Status))
63             {
64               RtlReleasePebLock();
65               *Environment = NULL;
66               return(Status);
67             }
68
69           memmove(EnvPtr,
70                   NtCurrentPeb ()->ProcessParameters->Environment,
71                   MemInfo.RegionSize);
72
73           *Environment = EnvPtr;
74         }
75 #endif
76       RtlReleasePebLock ();
77     }
78   else
79     {
80       Status = NtAllocateVirtualMemory(NtCurrentProcess(),
81                                        &EnvPtr,
82                                        0,
83                                        &RegionSize,
84                                        MEM_RESERVE | MEM_COMMIT,
85                                        PAGE_READWRITE);
86       if (NT_SUCCESS(Status))
87         {
88           memset(EnvPtr,
89                  0,
90                  RegionSize);
91           *Environment = EnvPtr;
92         }
93     }
94
95   return(Status);
96 }
97
98
99 /*
100  * @implemented
101  */
102 VOID STDCALL
103 RtlDestroyEnvironment(PWSTR Environment)
104 {
105   ULONG Size = 0;
106
107   NtFreeVirtualMemory(NtCurrentProcess(),
108                       (PVOID*)&Environment,
109                       &Size,
110                       MEM_RELEASE);
111 }
112
113
114 /*
115  * @implemented
116  */
117 NTSTATUS STDCALL
118 RtlExpandEnvironmentStrings_U(PWSTR Environment,
119                               PUNICODE_STRING Source,
120                               PUNICODE_STRING Destination,
121                               PULONG Length)
122 {
123   UNICODE_STRING var;
124   UNICODE_STRING val;
125   NTSTATUS Status = STATUS_SUCCESS;
126   BOOLEAN flag = FALSE;
127   PWSTR s;
128   PWSTR d;
129   PWSTR w;
130   int src_len;
131   int dst_max;
132   int tail;
133
134   DPRINT("RtlExpandEnvironmentStrings_U %p %wZ %p %p\n",
135          Environment, Source, Destination, Length);
136
137   src_len = Source->Length / sizeof(WCHAR);
138   s = Source->Buffer;
139   dst_max = Destination->MaximumLength / sizeof(WCHAR);
140   d = Destination->Buffer;
141
142   while (src_len)
143     {
144       if (*s == L'%')
145         {
146           if (flag)
147             {
148               flag = FALSE;
149               goto copy;
150             }
151           w = s + 1;
152           tail = src_len - 1;
153           while (*w != L'%' && tail)
154             {
155               w++;
156               tail--;
157             }
158           if (!tail)
159             goto copy;
160
161           var.Length = (w - ( s + 1)) * sizeof(WCHAR);
162           var.MaximumLength = var.Length;
163           var.Buffer = s + 1;
164
165           val.Length = 0;
166           val.MaximumLength = dst_max * sizeof(WCHAR);
167           val.Buffer = d;
168           Status = RtlQueryEnvironmentVariable_U (Environment, &var, &val);
169           if (NT_SUCCESS(Status))
170             {
171               d += val.Length / sizeof(WCHAR);
172               dst_max -= val.Length / sizeof(WCHAR);
173               s = w + 1;
174               src_len = tail - 1;
175               continue;
176             }
177           /* variable not found or buffer too small, just copy %var% */
178           flag = TRUE;
179         }
180 copy:
181       if (!dst_max)
182         {
183           Status = STATUS_BUFFER_TOO_SMALL;
184           break;
185         }
186
187       *d++ = *s++;
188       dst_max--;
189       src_len--;
190     }
191
192   Destination->Length = (d - Destination->Buffer) * sizeof(WCHAR);
193   if (Length != NULL)
194     *Length = Destination->Length;
195   if (dst_max)
196     Destination->Buffer[Destination->Length / sizeof(WCHAR)] = 0;
197
198   DPRINT("Destination %wZ\n", Destination);
199   return(Status);
200 }
201
202
203 /*
204  * @implemented
205  */
206 VOID STDCALL
207 RtlSetCurrentEnvironment(PWSTR NewEnvironment,
208                          PWSTR *OldEnvironment)
209 {
210   PVOID EnvPtr;
211
212   DPRINT("NewEnvironment %x OldEnvironment %x\n",
213          NewEnvironment, OldEnvironment);
214
215   RtlAcquirePebLock();
216
217   EnvPtr = NtCurrentPeb()->ProcessParameters->Environment;
218   NtCurrentPeb()->ProcessParameters->Environment = NewEnvironment;
219
220   if (OldEnvironment != NULL)
221     *OldEnvironment = EnvPtr;
222
223   RtlReleasePebLock();
224 }
225
226
227 /*
228  * @implemented
229  */
230 NTSTATUS STDCALL
231 RtlSetEnvironmentVariable(PWSTR *Environment,
232                           PUNICODE_STRING Name,
233                           PUNICODE_STRING Value)
234 {
235   MEMORY_BASIC_INFORMATION mbi;
236   UNICODE_STRING var;
237   int hole_len, new_len, env_len = 0;
238   WCHAR *new_env = 0, *env_end = 0, *wcs, *env, *val = 0, *tail = 0, *hole = 0;
239   PWSTR head = NULL;
240   ULONG size = 0, new_size;
241   LONG f = 1;
242   NTSTATUS Status = STATUS_SUCCESS;
243
244   DPRINT("RtlSetEnvironmentVariable(Environment %p Name %wZ Value %wZ)\n",
245          Environment, Name, Value);
246
247   if (Environment)
248     {
249       env = *Environment;
250     }
251   else
252     {
253       RtlAcquirePebLock();
254       env = NtCurrentPeb()->ProcessParameters->Environment;
255     }
256
257   if (env)
258     {
259       /* get environment length */
260       wcs = env_end = env;
261       do
262       {
263          env_end += wcslen(env_end) + 1;
264       }
265       while (*env_end);
266       env_end++;
267       env_len = env_end - env;
268       DPRINT("environment length %ld characters\n", env_len);
269
270       /* find where to insert */
271       while (*wcs)
272         {
273           var.Buffer = wcs++;
274           wcs = wcschr(wcs, L'=');
275           if (wcs == NULL)
276           {
277              wcs = var.Buffer + wcslen(var.Buffer);
278           }
279           if (*wcs)
280             {
281               var.Length = (wcs - var.Buffer) * sizeof(WCHAR);
282               var.MaximumLength = var.Length;
283               val = ++wcs;
284               wcs += wcslen(wcs); 
285               f = RtlCompareUnicodeString(&var, Name, TRUE);
286               if (f >= 0)
287                 {
288                   if (f) /* Insert before found */
289                     {
290                       hole = tail = var.Buffer;
291                     }
292                   else /* Exact match */
293                     {
294                       head = var.Buffer;
295                       tail = ++wcs;
296                       hole = val;
297                     }
298                   goto found;
299                 }
300             }
301           wcs++;
302         }
303       hole = tail = wcs; /* Append to environment */
304     }
305
306 found:
307   if (Value->Length > 0)
308     {
309       hole_len = tail - hole;
310       /* calculate new environment size */
311       new_size = Value->Length + sizeof(WCHAR);
312       /* adding new variable */
313       if (f)
314         new_size += Name->Length + sizeof(WCHAR);
315       new_len = new_size / sizeof(WCHAR);
316       if (hole_len < new_len)
317         {
318           /* enlarge environment size */
319           /* check the size of available memory */
320           new_size += (env_len - hole_len) * sizeof(WCHAR);
321           new_size = ROUNDUP(new_size, PAGE_SIZE);
322           mbi.RegionSize = 0;
323           DPRINT("new_size %lu\n", new_size);
324
325           if (env)
326             {
327               Status = NtQueryVirtualMemory(NtCurrentProcess(),
328                                             env,
329                                             0,
330                                             &mbi,
331                                             sizeof(mbi),
332                                             NULL);
333               if (!NT_SUCCESS(Status))
334                 {
335                   if (Environment == NULL)
336                     {
337                       RtlReleasePebLock();
338                     }
339                   return(Status);
340                 }
341             }
342
343           if (new_size > mbi.RegionSize)
344             {
345               /* reallocate memory area */
346               Status = NtAllocateVirtualMemory(NtCurrentProcess(),
347                                                (VOID**)&new_env,
348                                                0,
349                                                &new_size,
350                                                MEM_RESERVE | MEM_COMMIT,
351                                                PAGE_READWRITE);
352               if (!NT_SUCCESS(Status))
353                 {
354                   if (Environment == NULL)
355                     {
356                       RtlReleasePebLock();
357                     }
358                   return(Status);
359                 }
360
361               if (env)
362                 {
363                   memmove(new_env,
364                           env,
365                           (hole - env) * sizeof(WCHAR));
366                   hole = new_env + (hole - env);
367                 }
368               else
369                 {
370                   /* absolutely new environment */
371                   tail = hole = new_env;
372                   *hole = 0;
373                   env_end = hole + 1;
374                 }
375             }
376         }
377
378       /* move tail */
379       memmove (hole + new_len, tail, (env_end - tail) * sizeof(WCHAR));
380
381       if (new_env)
382         {
383           /* we reallocated environment, let's free the old one */
384           if (Environment)
385             *Environment = new_env;
386           else
387             NtCurrentPeb()->ProcessParameters->Environment = new_env;
388
389           if (env)
390             {
391               size = 0;
392               NtFreeVirtualMemory(NtCurrentProcess(),
393                                   (PVOID*)&env,
394                                   &size,
395                                   MEM_RELEASE);
396             }
397         }
398
399       /* and now copy given stuff */
400       if (f)
401         {
402           /* copy variable name and '=' character */
403           memmove(hole,
404                   Name->Buffer,
405                   Name->Length);
406           hole += Name->Length / sizeof(WCHAR);
407           *hole++ = L'=';
408         }
409
410       /* copy value */
411       memmove(hole,
412               Value->Buffer,
413               Value->Length);
414       hole += Value->Length / sizeof(WCHAR);
415       *hole = 0;
416     }
417   else
418     {
419       /* remove the environment variable */
420       if (f == 0)
421         {
422           memmove(head,
423                   tail,
424                   (env_end - tail) * sizeof(WCHAR));
425         }
426       else
427         {
428           Status = STATUS_VARIABLE_NOT_FOUND;
429         }
430     }
431
432   if (Environment == NULL)
433     {
434       RtlReleasePebLock();
435     }
436
437   return(Status);
438 }
439
440
441 /*
442  * @implemented
443  */
444 NTSTATUS STDCALL
445 RtlQueryEnvironmentVariable_U(PWSTR Environment,
446                               PUNICODE_STRING Name,
447                               PUNICODE_STRING Value)
448 {
449   NTSTATUS Status;
450   PWSTR wcs;
451   UNICODE_STRING var;
452   PWSTR val;
453   int len;
454   BOOLEAN SysEnvUsed = FALSE;
455
456   DPRINT("RtlQueryEnvironmentVariable_U Environment %p Variable %wZ Value %p\n",
457          Environment, Name, Value);
458
459   if (Environment == NULL)
460     {
461       Environment = NtCurrentPeb()->ProcessParameters->Environment;
462       SysEnvUsed = TRUE;
463     }
464
465   if (Environment == NULL)
466     return(STATUS_VARIABLE_NOT_FOUND);
467
468   Value->Length = 0;
469   if (SysEnvUsed == TRUE)
470     RtlAcquirePebLock();
471
472   wcs = Environment;
473   len = Name->Length / sizeof(WCHAR);
474   while (*wcs)
475     {
476       var.Buffer = wcs++;
477       wcs = wcschr(wcs, L'=');
478       if (wcs == NULL)
479       {
480          wcs = var.Buffer + wcslen(var.Buffer);
481       }
482       if (*wcs)
483         {
484           var.Length = var.MaximumLength = (wcs - var.Buffer) * sizeof(WCHAR);
485           val = ++wcs;
486           wcs += wcslen(wcs);
487
488           if (RtlEqualUnicodeString(&var, Name, TRUE))
489             {
490               Value->Length = (wcs - val) * sizeof(WCHAR);
491               if (Value->Length < Value->MaximumLength)
492                 {
493                   memcpy(Value->Buffer, val, Value->Length + sizeof(WCHAR));
494                   DPRINT("Value %S\n", val);
495                   DPRINT("Return STATUS_SUCCESS\n");
496                   Status = STATUS_SUCCESS;
497                 }
498               else
499                 {
500                   DPRINT("Return STATUS_BUFFER_TOO_SMALL\n");
501                   Status = STATUS_BUFFER_TOO_SMALL;
502                 }
503
504               if (SysEnvUsed == TRUE)
505                 RtlReleasePebLock();
506
507               return(Status);
508             }
509         }
510       wcs++;
511     }
512
513   if (SysEnvUsed == TRUE)
514     RtlReleasePebLock();
515
516   DPRINT("Return STATUS_VARIABLE_NOT_FOUND\n");
517   return(STATUS_VARIABLE_NOT_FOUND);
518 }
519
520 /* EOF */