3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
6 * PURPOSE: Environment functions
7 * PROGRAMMER: Eric Kohl
12 /* INCLUDES ******************************************************************/
14 #include <ddk/ntddk.h>
15 #include <ntdll/rtl.h>
17 #include <ntos/minmax.h>
21 #include <ntdll/ntdll.h>
23 PPEB STDCALL
RtlpCurrentPeb(VOID
);
24 /* FUNCTIONS *****************************************************************/
30 RtlCreateEnvironment(BOOLEAN Inherit
,
33 MEMORY_BASIC_INFORMATION MemInfo
;
35 NTSTATUS Status
= STATUS_SUCCESS
;
36 ULONG RegionSize
= PAGE_SIZE
;
42 if (NtCurrentPeb()->ProcessParameters
->Environment
!= NULL
)
44 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
45 NtCurrentPeb()->ProcessParameters
->Environment
,
46 MemoryBasicInformation
,
48 sizeof(MEMORY_BASIC_INFORMATION
),
50 if (!NT_SUCCESS(Status
))
57 RegionSize
= MemInfo
.RegionSize
;
58 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
62 MEM_RESERVE
| MEM_COMMIT
,
64 if (!NT_SUCCESS(Status
))
72 NtCurrentPeb ()->ProcessParameters
->Environment
,
75 *Environment
= EnvPtr
;
82 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
86 MEM_RESERVE
| MEM_COMMIT
,
88 if (NT_SUCCESS(Status
))
93 *Environment
= EnvPtr
;
105 RtlDestroyEnvironment(PWSTR Environment
)
109 NtFreeVirtualMemory(NtCurrentProcess(),
120 RtlExpandEnvironmentStrings_U(PWSTR Environment
,
121 PUNICODE_STRING Source
,
122 PUNICODE_STRING Destination
,
125 UNICODE_STRING Variable
;
126 UNICODE_STRING Value
;
127 NTSTATUS ReturnStatus
= STATUS_SUCCESS
;
137 ULONG TotalLength
= 1; /* for terminating NULL */
139 DPRINT("RtlExpandEnvironmentStrings_U %p %wZ %p %p\n",
140 Environment
, Source
, Destination
, Length
);
142 SourceLength
= Source
->Length
/ sizeof(WCHAR
);
143 SourceBuffer
= Source
->Buffer
;
144 DestMax
= Destination
->MaximumLength
/ sizeof(WCHAR
);
145 DestBuffer
= Destination
->Buffer
;
149 if (*SourceBuffer
!= L
'%')
151 CopyBuffer
= SourceBuffer
;
153 while (SourceLength
!= 0 && *SourceBuffer
!= L
'%')
162 /* Process environment variable. */
164 VariableEnd
= SourceBuffer
+ 1;
165 Tail
= SourceLength
- 1;
166 while (*VariableEnd
!= L
'%' && Tail
!= 0)
174 Variable
.MaximumLength
=
175 Variable
.Length
= (VariableEnd
- (SourceBuffer
+ 1)) * sizeof(WCHAR
);
176 Variable
.Buffer
= SourceBuffer
+ 1;
179 Value
.MaximumLength
= DestMax
* sizeof(WCHAR
);
180 Value
.Buffer
= DestBuffer
;
182 Status
= RtlQueryEnvironmentVariable_U(Environment
, &Variable
,
184 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_TOO_SMALL
)
186 SourceBuffer
= VariableEnd
+ 1;
187 SourceLength
= Tail
- 1;
188 TotalLength
+= Value
.Length
/ sizeof(WCHAR
);
189 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
191 DestBuffer
+= Value
.Length
/ sizeof(WCHAR
);
192 DestMax
-= Value
.Length
/ sizeof(WCHAR
);
197 ReturnStatus
= STATUS_BUFFER_TOO_SMALL
;
203 /* Variable not found. */
204 CopyBuffer
= SourceBuffer
;
205 CopyLength
= SourceLength
- Tail
+ 1;
206 SourceLength
-= CopyLength
;
207 SourceBuffer
+= CopyLength
;
212 /* Unfinished variable name. */
213 CopyBuffer
= SourceBuffer
;
214 CopyLength
= SourceLength
;
219 TotalLength
+= CopyLength
;
222 if (DestMax
< CopyLength
)
224 CopyLength
= DestMax
;
225 ReturnStatus
= STATUS_BUFFER_TOO_SMALL
;
227 RtlCopyMemory(DestBuffer
, CopyBuffer
, CopyLength
* sizeof(WCHAR
));
228 DestMax
-= CopyLength
;
229 DestBuffer
+= CopyLength
;
233 /* NULL-terminate the buffer. */
237 ReturnStatus
= STATUS_BUFFER_TOO_SMALL
;
239 Destination
->Length
= (DestBuffer
- Destination
->Buffer
) * sizeof(WCHAR
);
241 *Length
= TotalLength
* sizeof(WCHAR
);
243 DPRINT("Destination %wZ\n", Destination
);
253 RtlSetCurrentEnvironment(PWSTR NewEnvironment
,
254 PWSTR
*OldEnvironment
)
258 DPRINT("NewEnvironment %x OldEnvironment %x\n",
259 NewEnvironment
, OldEnvironment
);
263 EnvPtr
= NtCurrentPeb()->ProcessParameters
->Environment
;
264 NtCurrentPeb()->ProcessParameters
->Environment
= NewEnvironment
;
266 if (OldEnvironment
!= NULL
)
267 *OldEnvironment
= EnvPtr
;
277 RtlSetEnvironmentVariable(PWSTR
*Environment
,
278 PUNICODE_STRING Name
,
279 PUNICODE_STRING Value
)
281 MEMORY_BASIC_INFORMATION mbi
;
283 int hole_len
, new_len
, env_len
= 0;
284 WCHAR
*new_env
= 0, *env_end
= 0, *wcs
, *env
, *val
= 0, *tail
= 0, *hole
= 0;
286 ULONG size
= 0, new_size
;
288 NTSTATUS Status
= STATUS_SUCCESS
;
290 DPRINT("RtlSetEnvironmentVariable(Environment %p Name %wZ Value %wZ)\n",
291 Environment
, Name
, Value
);
293 /* Variable names can't contain a '=' except as a first character. */
294 for (wcs
= Name
->Buffer
+ 1;
295 wcs
< Name
->Buffer
+ (Name
->Length
/ sizeof(WCHAR
));
299 return STATUS_INVALID_PARAMETER
;
309 env
= NtCurrentPeb()->ProcessParameters
->Environment
;
314 /* get environment length */
318 env_end
+= wcslen(env_end
) + 1;
322 env_len
= env_end
- env
;
323 DPRINT("environment length %ld characters\n", env_len
);
325 /* find where to insert */
329 wcs
= wcschr(wcs
, L
'=');
332 wcs
= var
.Buffer
+ wcslen(var
.Buffer
);
336 var
.Length
= (wcs
- var
.Buffer
) * sizeof(WCHAR
);
337 var
.MaximumLength
= var
.Length
;
340 f
= RtlCompareUnicodeString(&var
, Name
, TRUE
);
343 if (f
) /* Insert before found */
345 hole
= tail
= var
.Buffer
;
347 else /* Exact match */
358 hole
= tail
= wcs
; /* Append to environment */
362 if (Value
!= NULL
&& Value
->Length
> 0)
364 hole_len
= tail
- hole
;
365 /* calculate new environment size */
366 new_size
= Value
->Length
+ sizeof(WCHAR
);
367 /* adding new variable */
369 new_size
+= Name
->Length
+ sizeof(WCHAR
);
370 new_len
= new_size
/ sizeof(WCHAR
);
371 if (hole_len
< new_len
)
373 /* enlarge environment size */
374 /* check the size of available memory */
375 new_size
+= (env_len
- hole_len
) * sizeof(WCHAR
);
376 new_size
= ROUNDUP(new_size
, PAGE_SIZE
);
378 DPRINT("new_size %lu\n", new_size
);
382 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
384 MemoryBasicInformation
,
386 sizeof(MEMORY_BASIC_INFORMATION
),
388 if (!NT_SUCCESS(Status
))
390 if (Environment
== NULL
)
398 if (new_size
> mbi
.RegionSize
)
400 /* reallocate memory area */
401 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
405 MEM_RESERVE
| MEM_COMMIT
,
407 if (!NT_SUCCESS(Status
))
409 if (Environment
== NULL
)
420 (hole
- env
) * sizeof(WCHAR
));
421 hole
= new_env
+ (hole
- env
);
425 /* absolutely new environment */
426 tail
= hole
= new_env
;
434 memmove (hole
+ new_len
, tail
, (env_end
- tail
) * sizeof(WCHAR
));
438 /* we reallocated environment, let's free the old one */
440 *Environment
= new_env
;
442 NtCurrentPeb()->ProcessParameters
->Environment
= new_env
;
447 NtFreeVirtualMemory(NtCurrentProcess(),
454 /* and now copy given stuff */
457 /* copy variable name and '=' character */
461 hole
+= Name
->Length
/ sizeof(WCHAR
);
469 hole
+= Value
->Length
/ sizeof(WCHAR
);
474 /* remove the environment variable */
479 (env_end
- tail
) * sizeof(WCHAR
));
483 Status
= STATUS_VARIABLE_NOT_FOUND
;
487 if (Environment
== NULL
)
500 RtlQueryEnvironmentVariable_U(PWSTR Environment
,
501 PUNICODE_STRING Name
,
502 PUNICODE_STRING Value
)
508 BOOLEAN SysEnvUsed
= FALSE
;
510 DPRINT("RtlQueryEnvironmentVariable_U Environment %p Variable %wZ Value %p\n",
511 Environment
, Name
, Value
);
513 if (Environment
== NULL
)
515 PPEB Peb
= RtlpCurrentPeb();
517 Environment
= Peb
->ProcessParameters
->Environment
;
522 if (Environment
== NULL
)
523 return(STATUS_VARIABLE_NOT_FOUND
);
526 if (SysEnvUsed
== TRUE
)
533 wcs
= wcschr(wcs
, L
'=');
536 wcs
= var
.Buffer
+ wcslen(var
.Buffer
);
540 var
.Length
= var
.MaximumLength
= (wcs
- var
.Buffer
) * sizeof(WCHAR
);
544 if (RtlEqualUnicodeString(&var
, Name
, TRUE
))
546 Value
->Length
= (wcs
- val
) * sizeof(WCHAR
);
547 if (Value
->Length
<= Value
->MaximumLength
)
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
;
557 DPRINT("Return STATUS_BUFFER_TOO_SMALL\n");
558 Status
= STATUS_BUFFER_TOO_SMALL
;
561 if (SysEnvUsed
== TRUE
)
570 if (SysEnvUsed
== TRUE
)
573 DPRINT("Return STATUS_VARIABLE_NOT_FOUND\n");
574 return(STATUS_VARIABLE_NOT_FOUND
);