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