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