[KERNEL32]
[reactos.git] / reactos / dll / win32 / kernel32 / client / environ.c
1 /* $Id: environ.c 54459 2011-11-20 17:00:39Z pschweitzer $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/misc/env.c
6 * PURPOSE: Environment functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Emanuele Aliberti
9 * Thomas Weidenmueller
10 * UPDATE HISTORY:
11 * Created 01/11/98
12 */
13
14 /* INCLUDES *******************************************************************/
15
16 #include <k32.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 /* FUNCTIONS ******************************************************************/
22
23 /*
24 * @implemented
25 */
26 DWORD
27 WINAPI
28 GetEnvironmentVariableA(IN LPCSTR lpName,
29 IN LPSTR lpBuffer,
30 IN DWORD nSize)
31 {
32 ANSI_STRING VarName, VarValue;
33 UNICODE_STRING VarNameU, VarValueU;
34 PWSTR Buffer;
35 ULONG Result = 0;
36 USHORT UniSize;
37 NTSTATUS Status;
38
39 /* Initialize all the strings */
40 RtlInitAnsiString(&VarName, lpName);
41 RtlInitUnicodeString(&VarNameU, NULL);
42 RtlInitUnicodeString(&VarValueU, NULL);
43 Status = RtlAnsiStringToUnicodeString(&VarNameU, &VarName, TRUE);
44 if (!NT_SUCCESS(Status)) goto Quickie;
45
46 /* Check if the size is too big to fit */
47 UniSize = UNICODE_STRING_MAX_CHARS - 2;
48 if (nSize <= UniSize)
49 {
50 /* It fits, but was there a string at all? */
51 if (nSize)
52 {
53 /* Keep the given size, minus a NULL-char */
54 UniSize = nSize - 1;
55 }
56 else
57 {
58 /* No size */
59 UniSize = 0;
60 }
61 }
62 else
63 {
64 /* String is too big, so we need to return a NULL char as well */
65 UniSize--;
66 }
67
68 /* Allocate the value string buffer */
69 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UniSize * sizeof(WCHAR));
70 if (!Buffer)
71 {
72 Status = STATUS_NO_MEMORY;
73 goto Quickie;
74 }
75
76 /* And initialize its string */
77 RtlInitEmptyUnicodeString(&VarValueU, Buffer, UniSize * sizeof(WCHAR));
78
79 /* Acquire the PEB lock since we'll be querying variables now */
80 RtlAcquirePebLock();
81
82 /* Query the variable */
83 Status = RtlQueryEnvironmentVariable_U(NULL, &VarNameU, &VarValueU);
84 if ((NT_SUCCESS(Status)) && !(nSize)) Status = STATUS_BUFFER_TOO_SMALL;
85
86 /* Check if we didn't have enough space */
87 if (!(NT_SUCCESS(Status)) && (Status == STATUS_BUFFER_TOO_SMALL))
88 {
89 /* Fixup the length that the API returned */
90 VarValueU.MaximumLength = VarValueU.Length + 2;
91
92 /* Free old Unicode buffer */
93 RtlFreeHeap(RtlGetProcessHeap(), 0, VarValueU.Buffer);
94
95 /* Allocate new one */
96 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, VarValueU.MaximumLength);
97 if (Buffer)
98 {
99 /* Query the variable so we can know its size */
100 VarValueU.Buffer = Buffer;
101 Status = RtlQueryEnvironmentVariable_U(NULL, &VarNameU, &VarValueU);
102 if (NT_SUCCESS(Status))
103 {
104 /* Get the ASCII length of the variable */
105 Result = RtlUnicodeStringToAnsiSize(&VarValueU);
106 }
107 }
108 else
109 {
110 /* Set failure status */
111 Status = STATUS_NO_MEMORY;
112 }
113 }
114 else if (NT_SUCCESS(Status))
115 {
116 /* Check if the size is too big to fit */
117 UniSize = UNICODE_STRING_MAX_BYTES - 1;
118 if (nSize <= UniSize) UniSize = nSize;
119
120 /* Check the size */
121 Result = RtlUnicodeStringToAnsiSize(&VarValueU);
122 if (Result <= UniSize)
123 {
124 /* Convert the string */
125 RtlInitEmptyAnsiString(&VarValue, lpBuffer, UniSize);
126 Status = RtlUnicodeStringToAnsiString(&VarValue, &VarValueU, FALSE);
127 if (NT_SUCCESS(Status))
128 {
129 /* NULL-terminate and set the final length */
130 lpBuffer[VarValue.Length] = ANSI_NULL;
131 Result = VarValue.Length;
132 }
133 }
134 }
135
136 /* Release the lock */
137 RtlReleasePebLock();
138
139 Quickie:
140 /* Free the strings */
141 RtlFreeUnicodeString(&VarNameU);
142 if (VarValueU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, VarValueU.Buffer);
143
144 /* Check if we suceeded */
145 if (!NT_SUCCESS(Status))
146 {
147 /* We did not, clear the result and set the error code */
148 BaseSetLastNTError(Status);
149 Result = 0;
150 }
151
152 /* Return the result */
153 return Result;
154 }
155
156 /*
157 * @implemented
158 */
159 DWORD
160 WINAPI
161 GetEnvironmentVariableW(IN LPCWSTR lpName,
162 IN LPWSTR lpBuffer,
163 IN DWORD nSize)
164 {
165 UNICODE_STRING VarName, VarValue;
166 NTSTATUS Status;
167 USHORT UniSize;
168
169 if (nSize <= (UNICODE_STRING_MAX_CHARS - 1))
170 {
171 if (nSize)
172 {
173 UniSize = nSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
174 }
175 else
176 {
177 UniSize = 0;
178 }
179 }
180 else
181 {
182 UniSize = UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL);
183 }
184
185 Status = RtlInitUnicodeStringEx(&VarName, lpName);
186 if (!NT_SUCCESS(Status))
187 {
188 BaseSetLastNTError(Status);
189 return 0;
190 }
191
192 RtlInitEmptyUnicodeString(&VarValue, lpBuffer, UniSize);
193
194 Status = RtlQueryEnvironmentVariable_U(NULL, &VarName, &VarValue);
195 if (!NT_SUCCESS(Status))
196 {
197 if (Status == STATUS_BUFFER_TOO_SMALL)
198 {
199 return (VarValue.Length / sizeof(WCHAR)) + sizeof(ANSI_NULL);
200 }
201 BaseSetLastNTError (Status);
202 return 0;
203 }
204
205 lpBuffer[VarValue.Length / sizeof(WCHAR)] = UNICODE_NULL;
206
207 return (VarValue.Length / sizeof(WCHAR));
208 }
209
210 /*
211 * @implemented
212 */
213 BOOL
214 WINAPI
215 SetEnvironmentVariableA(IN LPCSTR lpName,
216 IN LPCSTR lpValue)
217 {
218 ANSI_STRING VarName, VarValue;
219 UNICODE_STRING VarNameU, VarValueU;
220 NTSTATUS Status;
221
222 RtlInitAnsiString(&VarName, (LPSTR)lpName);
223 Status = RtlAnsiStringToUnicodeString(&VarNameU, &VarName, TRUE);
224 if (NT_SUCCESS(Status))
225 {
226 if (lpValue)
227 {
228 RtlInitAnsiString(&VarValue, (LPSTR)lpValue);
229 Status = RtlAnsiStringToUnicodeString(&VarValueU, &VarValue, TRUE);
230 if (NT_SUCCESS(Status))
231 {
232 Status = RtlSetEnvironmentVariable(NULL, &VarNameU, &VarValueU);
233 RtlFreeUnicodeString(&VarValueU);
234 }
235 }
236 else
237 {
238 Status = RtlSetEnvironmentVariable(NULL, &VarNameU, NULL);
239 }
240
241 RtlFreeUnicodeString(&VarNameU);
242
243 if (NT_SUCCESS(Status)) return TRUE;
244 }
245
246 BaseSetLastNTError(Status);
247 return FALSE;
248 }
249
250 /*
251 * @implemented
252 */
253 BOOL
254 WINAPI
255 SetEnvironmentVariableW(IN LPCWSTR lpName,
256 IN LPCWSTR lpValue)
257 {
258 UNICODE_STRING VarName, VarValue;
259 NTSTATUS Status;
260
261 Status = RtlInitUnicodeStringEx(&VarName, lpName);
262 if (NT_SUCCESS(Status))
263 {
264 if (lpValue)
265 {
266 Status = RtlInitUnicodeStringEx(&VarValue, lpValue);
267 if (NT_SUCCESS(Status))
268 {
269 Status = RtlSetEnvironmentVariable(NULL, &VarName, &VarValue);
270 }
271 }
272 else
273 {
274 Status = RtlSetEnvironmentVariable(NULL, &VarName, NULL);
275 }
276
277 if (NT_SUCCESS(Status)) return TRUE;
278 }
279
280 BaseSetLastNTError(Status);
281 return FALSE;
282 }
283
284 /*
285 * @implemented
286 */
287 LPSTR
288 WINAPI
289 GetEnvironmentStringsA(VOID)
290 {
291 ULONG Length, Size;
292 NTSTATUS Status;
293 PWCHAR Environment, p;
294 PCHAR Buffer = NULL;
295
296 RtlAcquirePebLock();
297 p = Environment = NtCurrentPeb()->ProcessParameters->Environment;
298
299 do
300 {
301 p += wcslen(p) + 1;
302 } while (*p);
303
304 Length = p - Environment + 1;
305
306 Status = RtlUnicodeToMultiByteSize(&Size, Environment, Length * sizeof(WCHAR));
307 if (NT_SUCCESS(Status))
308 {
309 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
310 if (Buffer)
311 {
312 Status = RtlUnicodeToOemN(Buffer, Size, 0, Environment, Length * sizeof(WCHAR));
313 if (!NT_SUCCESS(Status))
314 {
315 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
316 Buffer = NULL;
317
318 BaseSetLastNTError(Status);
319 }
320 }
321 else
322 {
323 BaseSetLastNTError(STATUS_NO_MEMORY);
324 }
325 }
326 else
327 {
328 BaseSetLastNTError(Status);
329 }
330
331 RtlReleasePebLock();
332 return Buffer;
333 }
334
335 /*
336 * @implemented
337 */
338 LPWSTR
339 WINAPI
340 GetEnvironmentStringsW(VOID)
341 {
342 PWCHAR Environment, p;
343 ULONG Length;
344
345 RtlAcquirePebLock();
346
347 p = Environment = NtCurrentPeb()->ProcessParameters->Environment;
348
349 do
350 {
351 p += wcslen(p) + 1;
352 } while (*p);
353
354 Length = p - Environment + 1;
355
356 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
357 if (p)
358 {
359 RtlCopyMemory(p, Environment, Length * sizeof(WCHAR));
360 }
361 else
362 {
363 BaseSetLastNTError(STATUS_NO_MEMORY);
364 }
365
366 RtlReleasePebLock();
367 return p;
368 }
369
370 /*
371 * @implemented
372 */
373 BOOL
374 WINAPI
375 FreeEnvironmentStringsA(IN LPSTR EnvironmentStrings)
376 {
377 return (BOOL)RtlFreeHeap(RtlGetProcessHeap(), 0, EnvironmentStrings);
378 }
379
380 /*
381 * @implemented
382 */
383 BOOL
384 WINAPI
385 FreeEnvironmentStringsW(IN LPWSTR EnvironmentStrings)
386 {
387 return (BOOL)RtlFreeHeap(RtlGetProcessHeap(), 0, EnvironmentStrings);
388 }
389
390 /*
391 * @implemented
392 */
393 DWORD
394 WINAPI
395 ExpandEnvironmentStringsA(IN LPCSTR lpSrc,
396 IN LPSTR lpDst,
397 IN DWORD nSize)
398 {
399 ANSI_STRING Source, Dest;
400 UNICODE_STRING SourceU, DestU;
401 PWSTR Buffer;
402 ULONG Result = 0, Length;
403 USHORT UniSize;
404 NTSTATUS Status;
405
406 /* Check if the size is too big to fit */
407 UniSize = UNICODE_STRING_MAX_CHARS - 2;
408 if (nSize <= UniSize) UniSize = nSize;
409
410 /* Clear the input buffer */
411 if (lpDst) *lpDst = ANSI_NULL;
412
413 /* Initialize all the strings */
414 RtlInitAnsiString(&Source, lpSrc);
415 RtlInitUnicodeString(&SourceU, NULL);
416 RtlInitUnicodeString(&DestU, NULL);
417 Status = RtlAnsiStringToUnicodeString(&SourceU, &Source, TRUE);
418 if (!NT_SUCCESS(Status)) goto Quickie;
419
420 /* If the string fit in, make space for a NULL char */
421 if (UniSize)
422 {
423 UniSize--;
424 }
425 else
426 {
427 /* No input size, so no string size */
428 UniSize = 0;
429 }
430
431 /* Allocate the value string buffer */
432 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UniSize * sizeof(WCHAR));
433 if (!Buffer)
434 {
435 Status = STATUS_NO_MEMORY;
436 goto Quickie;
437 }
438
439 /* And initialize its string */
440 RtlInitEmptyUnicodeString(&DestU, Buffer, UniSize * sizeof(WCHAR));
441
442 /* Query the variable */
443 Length = 0;
444 Status = RtlExpandEnvironmentStrings_U(NULL, &SourceU, &DestU, &Length);
445
446 /* Check if we didn't have enough space */
447 if (!(NT_SUCCESS(Status)) && (Status == STATUS_BUFFER_TOO_SMALL))
448 {
449 /* Fixup the length that the API returned */
450 DestU.MaximumLength = Length;
451
452 /* Free old Unicode buffer */
453 RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
454
455 /* Allocate new one */
456 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
457 if (Buffer)
458 {
459 /* Query the variable so we can know its size */
460 DestU.Buffer = Buffer;
461 Status = RtlExpandEnvironmentStrings_U(NULL, &SourceU, &DestU, &Length);
462 if (NT_SUCCESS(Status))
463 {
464 /* Get the ASCII length of the variable, add a byte for NULL */
465 Result = RtlUnicodeStringToAnsiSize(&DestU) + sizeof(ANSI_NULL);
466 }
467 }
468 else
469 {
470 /* Set failure status */
471 Status = STATUS_NO_MEMORY;
472 }
473 }
474 else if (NT_SUCCESS(Status))
475 {
476 /* Check if the size is too big to fit */
477 UniSize = UNICODE_STRING_MAX_BYTES - 1;
478 if (nSize <= UniSize) UniSize = nSize;
479
480 /* Check the size */
481 Result = RtlUnicodeStringToAnsiSize(&DestU);
482 if (Result <= UniSize)
483 {
484 /* Convert the string */
485 RtlInitEmptyAnsiString(&Dest, lpDst, UniSize);
486 Status = RtlUnicodeStringToAnsiString(&Dest, &DestU, FALSE);
487
488 /* Write a NULL-char in case of failure only */
489 if (!NT_SUCCESS(Status)) *lpDst = ANSI_NULL;
490 }
491 }
492 Quickie:
493 /* Free the strings */
494 RtlFreeUnicodeString(&SourceU);
495 if (DestU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
496
497 /* Check if we suceeded */
498 if (!NT_SUCCESS(Status))
499 {
500 /* We did not, clear the result and set the error code */
501 BaseSetLastNTError(Status);
502 Result = 0;
503 }
504
505 /* Return the result */
506 return Result;
507 }
508
509 /*
510 * @implemented
511 */
512 DWORD
513 WINAPI
514 ExpandEnvironmentStringsW(IN LPCWSTR lpSrc,
515 IN LPWSTR lpDst,
516 IN DWORD nSize)
517 {
518 UNICODE_STRING Source, Destination;
519 NTSTATUS Status;
520 USHORT UniSize;
521
522 UniSize = UNICODE_STRING_MAX_CHARS - 2;
523 if (nSize <= UniSize) UniSize = nSize;
524
525 RtlInitUnicodeString(&Source, (LPWSTR)lpSrc);
526 RtlInitEmptyUnicodeString(&Destination, lpDst, UniSize * sizeof(WCHAR));
527
528 Status = RtlExpandEnvironmentStrings_U(NULL,
529 &Source,
530 &Destination,
531 &nSize);
532 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
533 {
534 return nSize / sizeof(WCHAR);
535 }
536
537 BaseSetLastNTError(Status);
538 return 0;
539 }
540
541 /*
542 * @implemented
543 */
544 BOOL
545 WINAPI
546 SetEnvironmentStringsA(IN LPCH NewEnvironment)
547 {
548 STUB;
549 return FALSE;
550 }
551
552 /*
553 * @implemented
554 */
555 BOOL
556 WINAPI
557 SetEnvironmentStringsW(IN LPWCH NewEnvironment)
558 {
559 STUB;
560 return FALSE;
561 }
562
563 /* EOF */