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