2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
5 * PURPOSE: Environment functions
6 * PROGRAMMER: Eric Kohl
9 /* INCLUDES ******************************************************************/
16 /* FUNCTIONS *****************************************************************/
20 RtlSetEnvironmentStrings(IN PWCHAR NewEnvironment
, IN ULONG NewEnvironmentSize
)
23 return STATUS_NOT_IMPLEMENTED
;
33 PWSTR
*OutEnvironment
)
35 MEMORY_BASIC_INFORMATION MemInfo
;
36 PVOID CurrentEnvironment
, NewEnvironment
= NULL
;
37 NTSTATUS Status
= STATUS_SUCCESS
;
38 SIZE_T RegionSize
= PAGE_SIZE
;
40 /* Check if we should inherit the current environment */
43 /* In this case we need to lock the PEB */
46 /* Get a pointer to the current Environment and check if it's not NULL */
47 CurrentEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
48 if (CurrentEnvironment
!= NULL
)
50 /* Query the size of the current environment allocation */
51 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
53 MemoryBasicInformation
,
55 sizeof(MEMORY_BASIC_INFORMATION
),
57 if (!NT_SUCCESS(Status
))
60 *OutEnvironment
= NULL
;
64 /* Allocate a new region of the same size */
65 RegionSize
= MemInfo
.RegionSize
;
66 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
70 MEM_RESERVE
| MEM_COMMIT
,
72 if (!NT_SUCCESS(Status
))
75 *OutEnvironment
= NULL
;
79 /* Copy the current environment */
80 RtlCopyMemory(NewEnvironment
,
85 /* We are done with the PEB, release the lock */
89 /* Check if we still need an environment */
90 if (NewEnvironment
== NULL
)
92 /* Allocate a new environment */
93 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
97 MEM_RESERVE
| MEM_COMMIT
,
99 if (NT_SUCCESS(Status
))
101 RtlZeroMemory(NewEnvironment
, RegionSize
);
105 *OutEnvironment
= NewEnvironment
;
115 RtlDestroyEnvironment(PWSTR Environment
)
119 NtFreeVirtualMemory(NtCurrentProcess(),
130 RtlExpandEnvironmentStrings_U(PWSTR Environment
,
131 PUNICODE_STRING Source
,
132 PUNICODE_STRING Destination
,
135 UNICODE_STRING Variable
;
136 UNICODE_STRING Value
;
137 NTSTATUS ReturnStatus
= STATUS_SUCCESS
;
147 ULONG TotalLength
= 1; /* for terminating NULL */
149 DPRINT("RtlExpandEnvironmentStrings_U %p %wZ %p %p\n",
150 Environment
, Source
, Destination
, Length
);
152 SourceLength
= Source
->Length
/ sizeof(WCHAR
);
153 SourceBuffer
= Source
->Buffer
;
154 DestMax
= Destination
->MaximumLength
/ sizeof(WCHAR
);
155 DestBuffer
= Destination
->Buffer
;
159 if (*SourceBuffer
!= L
'%')
161 CopyBuffer
= SourceBuffer
;
163 while (SourceLength
!= 0 && *SourceBuffer
!= L
'%')
172 /* Process environment variable. */
174 VariableEnd
= SourceBuffer
+ 1;
175 Tail
= SourceLength
- 1;
176 while (*VariableEnd
!= L
'%' && Tail
!= 0)
184 Variable
.MaximumLength
=
185 Variable
.Length
= (USHORT
)(VariableEnd
- (SourceBuffer
+ 1)) * sizeof(WCHAR
);
186 Variable
.Buffer
= SourceBuffer
+ 1;
189 Value
.MaximumLength
= (USHORT
)DestMax
* sizeof(WCHAR
);
190 Value
.Buffer
= DestBuffer
;
192 Status
= RtlQueryEnvironmentVariable_U(Environment
, &Variable
,
194 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_TOO_SMALL
)
196 SourceBuffer
= VariableEnd
+ 1;
197 SourceLength
= Tail
- 1;
198 TotalLength
+= Value
.Length
/ sizeof(WCHAR
);
199 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
201 DestBuffer
+= Value
.Length
/ sizeof(WCHAR
);
202 DestMax
-= Value
.Length
/ sizeof(WCHAR
);
207 ReturnStatus
= STATUS_BUFFER_TOO_SMALL
;
213 /* Variable not found. */
214 CopyBuffer
= SourceBuffer
;
215 CopyLength
= SourceLength
- Tail
+ 1;
216 SourceLength
-= CopyLength
;
217 SourceBuffer
+= CopyLength
;
222 /* Unfinished variable name. */
223 CopyBuffer
= SourceBuffer
;
224 CopyLength
= SourceLength
;
229 TotalLength
+= CopyLength
;
232 if (DestMax
< CopyLength
)
234 CopyLength
= DestMax
;
235 ReturnStatus
= STATUS_BUFFER_TOO_SMALL
;
237 RtlCopyMemory(DestBuffer
, CopyBuffer
, CopyLength
* sizeof(WCHAR
));
238 DestMax
-= CopyLength
;
239 DestBuffer
+= CopyLength
;
243 /* NULL-terminate the buffer. */
247 ReturnStatus
= STATUS_BUFFER_TOO_SMALL
;
249 Destination
->Length
= (USHORT
)(DestBuffer
- Destination
->Buffer
) * sizeof(WCHAR
);
251 *Length
= TotalLength
* sizeof(WCHAR
);
253 DPRINT("Destination %wZ\n", Destination
);
263 RtlSetCurrentEnvironment(PWSTR NewEnvironment
,
264 PWSTR
*OldEnvironment
)
268 DPRINT("NewEnvironment 0x%p OldEnvironment 0x%p\n",
269 NewEnvironment
, OldEnvironment
);
273 EnvPtr
= NtCurrentPeb()->ProcessParameters
->Environment
;
274 NtCurrentPeb()->ProcessParameters
->Environment
= NewEnvironment
;
276 if (OldEnvironment
!= NULL
)
277 *OldEnvironment
= EnvPtr
;
287 RtlSetEnvironmentVariable(PWSTR
*Environment
,
288 PUNICODE_STRING Name
,
289 PUNICODE_STRING Value
)
291 MEMORY_BASIC_INFORMATION mbi
;
293 size_t hole_len
, new_len
, env_len
= 0;
294 WCHAR
*new_env
= 0, *env_end
= 0, *wcs
, *env
, *val
= 0, *tail
= 0, *hole
= 0;
296 SIZE_T size
= 0, new_size
;
298 NTSTATUS Status
= STATUS_SUCCESS
;
300 DPRINT("RtlSetEnvironmentVariable(Environment %p Name %wZ Value %wZ)\n",
301 Environment
, Name
, Value
);
303 /* Variable name must not be empty */
304 if (Name
->Length
< sizeof(WCHAR
))
305 return STATUS_INVALID_PARAMETER
;
307 /* Variable names can't contain a '=' except as a first character. */
308 for (wcs
= Name
->Buffer
+ 1;
309 wcs
< Name
->Buffer
+ (Name
->Length
/ sizeof(WCHAR
));
313 return STATUS_INVALID_PARAMETER
;
323 env
= NtCurrentPeb()->ProcessParameters
->Environment
;
328 /* get environment length */
332 env_end
+= wcslen(env_end
) + 1;
336 env_len
= env_end
- env
;
337 DPRINT("environment length %lu characters\n", env_len
);
339 /* find where to insert */
343 wcs
= wcschr(wcs
, L
'=');
346 wcs
= var
.Buffer
+ wcslen(var
.Buffer
);
350 var
.Length
= (USHORT
)(wcs
- var
.Buffer
) * sizeof(WCHAR
);
351 var
.MaximumLength
= var
.Length
;
354 f
= RtlCompareUnicodeString(&var
, Name
, TRUE
);
357 if (f
) /* Insert before found */
359 hole
= tail
= var
.Buffer
;
361 else /* Exact match */
372 hole
= tail
= wcs
; /* Append to environment */
376 if (Value
!= NULL
&& Value
->Buffer
!= NULL
)
378 hole_len
= tail
- hole
;
379 /* calculate new environment size */
380 new_size
= Value
->Length
+ sizeof(WCHAR
);
381 /* adding new variable */
383 new_size
+= Name
->Length
+ sizeof(WCHAR
);
384 new_len
= new_size
/ sizeof(WCHAR
);
385 if (hole_len
< new_len
)
387 /* enlarge environment size */
388 /* check the size of available memory */
389 new_size
+= (env_len
- hole_len
) * sizeof(WCHAR
);
390 new_size
= ROUND_UP(new_size
, PAGE_SIZE
);
392 DPRINT("new_size %lu\n", new_size
);
396 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
398 MemoryBasicInformation
,
400 sizeof(MEMORY_BASIC_INFORMATION
),
402 if (!NT_SUCCESS(Status
))
404 if (Environment
== NULL
)
412 if (new_size
> mbi
.RegionSize
)
414 /* reallocate memory area */
415 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
419 MEM_RESERVE
| MEM_COMMIT
,
421 if (!NT_SUCCESS(Status
))
423 if (Environment
== NULL
)
434 (hole
- env
) * sizeof(WCHAR
));
435 hole
= new_env
+ (hole
- env
);
439 /* absolutely new environment */
440 tail
= hole
= new_env
;
448 memmove (hole
+ new_len
, tail
, (env_end
- tail
) * sizeof(WCHAR
));
452 /* we reallocated environment, let's free the old one */
454 *Environment
= new_env
;
456 NtCurrentPeb()->ProcessParameters
->Environment
= new_env
;
461 NtFreeVirtualMemory(NtCurrentProcess(),
468 /* and now copy given stuff */
471 /* copy variable name and '=' character */
475 hole
+= Name
->Length
/ sizeof(WCHAR
);
483 hole
+= Value
->Length
/ sizeof(WCHAR
);
488 /* remove the environment variable */
493 (env_end
- tail
) * sizeof(WCHAR
));
497 if (Environment
== NULL
)
510 RtlQueryEnvironmentVariable_U(PWSTR Environment
,
511 PUNICODE_STRING Name
,
512 PUNICODE_STRING Value
)
518 BOOLEAN SysEnvUsed
= FALSE
;
520 DPRINT("RtlQueryEnvironmentVariable_U Environment %p Variable %wZ Value %p\n",
521 Environment
, Name
, Value
);
523 if (Environment
== NULL
)
525 PPEB Peb
= RtlGetCurrentPeb();
528 Environment
= Peb
->ProcessParameters
->Environment
;
533 if (Environment
== NULL
)
537 return(STATUS_VARIABLE_NOT_FOUND
);
543 DPRINT("Starting search at :%p\n", wcs
);
547 wcs
= wcschr(wcs
, L
'=');
550 wcs
= var
.Buffer
+ wcslen(var
.Buffer
);
551 DPRINT("Search at :%S\n", wcs
);
555 var
.Length
= var
.MaximumLength
= (USHORT
)(wcs
- var
.Buffer
) * sizeof(WCHAR
);
558 DPRINT("Search at :%S\n", wcs
);
560 if (RtlEqualUnicodeString(&var
, Name
, TRUE
))
562 Value
->Length
= (USHORT
)(wcs
- val
) * sizeof(WCHAR
);
563 if (Value
->Length
<= Value
->MaximumLength
)
565 memcpy(Value
->Buffer
, val
,
566 min(Value
->Length
+ sizeof(WCHAR
), Value
->MaximumLength
));
567 DPRINT("Value %S\n", val
);
568 DPRINT("Return STATUS_SUCCESS\n");
569 Status
= STATUS_SUCCESS
;
573 DPRINT("Return STATUS_BUFFER_TOO_SMALL\n");
574 Status
= STATUS_BUFFER_TOO_SMALL
;
589 DPRINT("Return STATUS_VARIABLE_NOT_FOUND: %wZ\n", Name
);
590 return(STATUS_VARIABLE_NOT_FOUND
);