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