2002-10-01 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / lib / ntdll / rtl / env.c
1 /* $Id: env.c,v 1.18 2002/10/01 19:27:20 chorns Exp $
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 */