mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 15:18:33 +00:00
594 lines
16 KiB
C
594 lines
16 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: lib/rtl/env.c
|
|
* PURPOSE: Environment functions
|
|
* PROGRAMMER: Eric Kohl
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <rtl.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlSetEnvironmentStrings(IN PWCHAR NewEnvironment, IN ULONG NewEnvironmentSize)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlCreateEnvironment(
|
|
BOOLEAN Inherit,
|
|
PWSTR *OutEnvironment)
|
|
{
|
|
MEMORY_BASIC_INFORMATION MemInfo;
|
|
PVOID CurrentEnvironment, NewEnvironment = NULL;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SIZE_T RegionSize = PAGE_SIZE;
|
|
|
|
/* Check if we should inherit the current environment */
|
|
if (Inherit)
|
|
{
|
|
/* In this case we need to lock the PEB */
|
|
RtlAcquirePebLock();
|
|
|
|
/* Get a pointer to the current Environment and check if it's not NULL */
|
|
CurrentEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
|
|
if (CurrentEnvironment != NULL)
|
|
{
|
|
/* Query the size of the current environment allocation */
|
|
Status = NtQueryVirtualMemory(NtCurrentProcess(),
|
|
CurrentEnvironment,
|
|
MemoryBasicInformation,
|
|
&MemInfo,
|
|
sizeof(MEMORY_BASIC_INFORMATION),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
RtlReleasePebLock();
|
|
*OutEnvironment = NULL;
|
|
return Status;
|
|
}
|
|
|
|
/* Allocate a new region of the same size */
|
|
RegionSize = MemInfo.RegionSize;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&NewEnvironment,
|
|
0,
|
|
&RegionSize,
|
|
MEM_RESERVE | MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
RtlReleasePebLock();
|
|
*OutEnvironment = NULL;
|
|
return Status;
|
|
}
|
|
|
|
/* Copy the current environment */
|
|
RtlCopyMemory(NewEnvironment,
|
|
CurrentEnvironment,
|
|
MemInfo.RegionSize);
|
|
}
|
|
|
|
/* We are done with the PEB, release the lock */
|
|
RtlReleasePebLock ();
|
|
}
|
|
|
|
/* Check if we still need an environment */
|
|
if (NewEnvironment == NULL)
|
|
{
|
|
/* Allocate a new environment */
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&NewEnvironment,
|
|
0,
|
|
&RegionSize,
|
|
MEM_RESERVE | MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
RtlZeroMemory(NewEnvironment, RegionSize);
|
|
}
|
|
}
|
|
|
|
*OutEnvironment = NewEnvironment;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID NTAPI
|
|
RtlDestroyEnvironment(PWSTR Environment)
|
|
{
|
|
SIZE_T Size = 0;
|
|
|
|
NtFreeVirtualMemory(NtCurrentProcess(),
|
|
(PVOID)&Environment,
|
|
&Size,
|
|
MEM_RELEASE);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS NTAPI
|
|
RtlExpandEnvironmentStrings_U(PWSTR Environment,
|
|
PUNICODE_STRING Source,
|
|
PUNICODE_STRING Destination,
|
|
PULONG Length)
|
|
{
|
|
UNICODE_STRING Variable;
|
|
UNICODE_STRING Value;
|
|
NTSTATUS ReturnStatus = STATUS_SUCCESS;
|
|
NTSTATUS Status;
|
|
PWSTR SourceBuffer;
|
|
PWSTR DestBuffer;
|
|
PWSTR CopyBuffer;
|
|
PWSTR VariableEnd;
|
|
ULONG SourceLength;
|
|
ULONG DestMax;
|
|
ULONG CopyLength;
|
|
ULONG Tail;
|
|
ULONG TotalLength = 1; /* for terminating NULL */
|
|
|
|
DPRINT("RtlExpandEnvironmentStrings_U %p %wZ %p %p\n",
|
|
Environment, Source, Destination, Length);
|
|
|
|
SourceLength = Source->Length / sizeof(WCHAR);
|
|
SourceBuffer = Source->Buffer;
|
|
DestMax = Destination->MaximumLength / sizeof(WCHAR);
|
|
DestBuffer = Destination->Buffer;
|
|
|
|
while (SourceLength)
|
|
{
|
|
if (*SourceBuffer != L'%')
|
|
{
|
|
CopyBuffer = SourceBuffer;
|
|
CopyLength = 0;
|
|
while (SourceLength != 0 && *SourceBuffer != L'%')
|
|
{
|
|
SourceBuffer++;
|
|
CopyLength++;
|
|
SourceLength--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Process environment variable. */
|
|
|
|
VariableEnd = SourceBuffer + 1;
|
|
Tail = SourceLength - 1;
|
|
while (*VariableEnd != L'%' && Tail != 0)
|
|
{
|
|
VariableEnd++;
|
|
Tail--;
|
|
}
|
|
|
|
if (Tail != 0)
|
|
{
|
|
Variable.MaximumLength =
|
|
Variable.Length = (USHORT)(VariableEnd - (SourceBuffer + 1)) * sizeof(WCHAR);
|
|
Variable.Buffer = SourceBuffer + 1;
|
|
|
|
Value.Length = 0;
|
|
Value.MaximumLength = (USHORT)DestMax * sizeof(WCHAR);
|
|
Value.Buffer = DestBuffer;
|
|
|
|
Status = RtlQueryEnvironmentVariable_U(Environment, &Variable,
|
|
&Value);
|
|
if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
SourceBuffer = VariableEnd + 1;
|
|
SourceLength = Tail - 1;
|
|
TotalLength += Value.Length / sizeof(WCHAR);
|
|
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
DestBuffer += Value.Length / sizeof(WCHAR);
|
|
DestMax -= Value.Length / sizeof(WCHAR);
|
|
}
|
|
else
|
|
{
|
|
DestMax = 0;
|
|
ReturnStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
/* Variable not found. */
|
|
CopyBuffer = SourceBuffer;
|
|
CopyLength = SourceLength - Tail + 1;
|
|
SourceLength -= CopyLength;
|
|
SourceBuffer += CopyLength;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Unfinished variable name. */
|
|
CopyBuffer = SourceBuffer;
|
|
CopyLength = SourceLength;
|
|
SourceLength = 0;
|
|
}
|
|
}
|
|
|
|
TotalLength += CopyLength;
|
|
if (DestMax)
|
|
{
|
|
if (DestMax < CopyLength)
|
|
{
|
|
CopyLength = DestMax;
|
|
ReturnStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
RtlCopyMemory(DestBuffer, CopyBuffer, CopyLength * sizeof(WCHAR));
|
|
DestMax -= CopyLength;
|
|
DestBuffer += CopyLength;
|
|
}
|
|
}
|
|
|
|
/* NULL-terminate the buffer. */
|
|
if (DestMax)
|
|
*DestBuffer = 0;
|
|
else
|
|
ReturnStatus = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
Destination->Length = (USHORT)(DestBuffer - Destination->Buffer) * sizeof(WCHAR);
|
|
if (Length != NULL)
|
|
*Length = TotalLength * sizeof(WCHAR);
|
|
|
|
DPRINT("Destination %wZ\n", Destination);
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID NTAPI
|
|
RtlSetCurrentEnvironment(PWSTR NewEnvironment,
|
|
PWSTR *OldEnvironment)
|
|
{
|
|
PVOID EnvPtr;
|
|
|
|
DPRINT("NewEnvironment 0x%p OldEnvironment 0x%p\n",
|
|
NewEnvironment, OldEnvironment);
|
|
|
|
RtlAcquirePebLock();
|
|
|
|
EnvPtr = NtCurrentPeb()->ProcessParameters->Environment;
|
|
NtCurrentPeb()->ProcessParameters->Environment = NewEnvironment;
|
|
|
|
if (OldEnvironment != NULL)
|
|
*OldEnvironment = EnvPtr;
|
|
|
|
RtlReleasePebLock();
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS NTAPI
|
|
RtlSetEnvironmentVariable(PWSTR *Environment,
|
|
PUNICODE_STRING Name,
|
|
PUNICODE_STRING Value)
|
|
{
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
UNICODE_STRING var;
|
|
size_t hole_len, new_len, env_len = 0;
|
|
WCHAR *new_env = 0, *env_end = 0, *wcs, *env, *val = 0, *tail = 0, *hole = 0;
|
|
PWSTR head = NULL;
|
|
SIZE_T size = 0, new_size;
|
|
LONG f = 1;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DPRINT("RtlSetEnvironmentVariable(Environment %p Name %wZ Value %wZ)\n",
|
|
Environment, Name, Value);
|
|
|
|
/* Variable name must not be empty */
|
|
if (Name->Length < sizeof(WCHAR))
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* Variable names can't contain a '=' except as a first character. */
|
|
for (wcs = Name->Buffer + 1;
|
|
wcs < Name->Buffer + (Name->Length / sizeof(WCHAR));
|
|
wcs++)
|
|
{
|
|
if (*wcs == L'=')
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Environment)
|
|
{
|
|
env = *Environment;
|
|
}
|
|
else
|
|
{
|
|
RtlAcquirePebLock();
|
|
env = NtCurrentPeb()->ProcessParameters->Environment;
|
|
}
|
|
|
|
if (env)
|
|
{
|
|
/* get environment length */
|
|
wcs = env_end = env;
|
|
do
|
|
{
|
|
env_end += wcslen(env_end) + 1;
|
|
}
|
|
while (*env_end);
|
|
env_end++;
|
|
env_len = env_end - env;
|
|
DPRINT("environment length %lu characters\n", env_len);
|
|
|
|
/* find where to insert */
|
|
while (*wcs)
|
|
{
|
|
var.Buffer = wcs++;
|
|
wcs = wcschr(wcs, L'=');
|
|
if (wcs == NULL)
|
|
{
|
|
wcs = var.Buffer + wcslen(var.Buffer);
|
|
}
|
|
if (*wcs)
|
|
{
|
|
var.Length = (USHORT)(wcs - var.Buffer) * sizeof(WCHAR);
|
|
var.MaximumLength = var.Length;
|
|
val = ++wcs;
|
|
wcs += wcslen(wcs);
|
|
f = RtlCompareUnicodeString(&var, Name, TRUE);
|
|
if (f >= 0)
|
|
{
|
|
if (f) /* Insert before found */
|
|
{
|
|
hole = tail = var.Buffer;
|
|
}
|
|
else /* Exact match */
|
|
{
|
|
head = var.Buffer;
|
|
tail = ++wcs;
|
|
hole = val;
|
|
}
|
|
goto found;
|
|
}
|
|
}
|
|
wcs++;
|
|
}
|
|
hole = tail = wcs; /* Append to environment */
|
|
}
|
|
|
|
found:
|
|
if (Value != NULL && Value->Buffer != NULL)
|
|
{
|
|
hole_len = tail - hole;
|
|
/* calculate new environment size */
|
|
new_size = Value->Length + sizeof(WCHAR);
|
|
/* adding new variable */
|
|
if (f)
|
|
new_size += Name->Length + sizeof(WCHAR);
|
|
new_len = new_size / sizeof(WCHAR);
|
|
if (hole_len < new_len)
|
|
{
|
|
/* enlarge environment size */
|
|
/* check the size of available memory */
|
|
new_size += (env_len - hole_len) * sizeof(WCHAR);
|
|
new_size = ROUND_UP(new_size, PAGE_SIZE);
|
|
mbi.RegionSize = 0;
|
|
DPRINT("new_size %lu\n", new_size);
|
|
|
|
if (env)
|
|
{
|
|
Status = NtQueryVirtualMemory(NtCurrentProcess(),
|
|
env,
|
|
MemoryBasicInformation,
|
|
&mbi,
|
|
sizeof(MEMORY_BASIC_INFORMATION),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (Environment == NULL)
|
|
{
|
|
RtlReleasePebLock();
|
|
}
|
|
return(Status);
|
|
}
|
|
}
|
|
|
|
if (new_size > mbi.RegionSize)
|
|
{
|
|
/* reallocate memory area */
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
(PVOID)&new_env,
|
|
0,
|
|
&new_size,
|
|
MEM_RESERVE | MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (Environment == NULL)
|
|
{
|
|
RtlReleasePebLock();
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
if (env)
|
|
{
|
|
memmove(new_env,
|
|
env,
|
|
(hole - env) * sizeof(WCHAR));
|
|
hole = new_env + (hole - env);
|
|
}
|
|
else
|
|
{
|
|
/* absolutely new environment */
|
|
tail = hole = new_env;
|
|
*hole = 0;
|
|
env_end = hole + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* move tail */
|
|
memmove (hole + new_len, tail, (env_end - tail) * sizeof(WCHAR));
|
|
|
|
if (new_env)
|
|
{
|
|
/* we reallocated environment, let's free the old one */
|
|
if (Environment)
|
|
*Environment = new_env;
|
|
else
|
|
NtCurrentPeb()->ProcessParameters->Environment = new_env;
|
|
|
|
if (env)
|
|
{
|
|
size = 0;
|
|
NtFreeVirtualMemory(NtCurrentProcess(),
|
|
(PVOID)&env,
|
|
&size,
|
|
MEM_RELEASE);
|
|
}
|
|
}
|
|
|
|
/* and now copy given stuff */
|
|
if (f)
|
|
{
|
|
/* copy variable name and '=' character */
|
|
memmove(hole,
|
|
Name->Buffer,
|
|
Name->Length);
|
|
hole += Name->Length / sizeof(WCHAR);
|
|
*hole++ = L'=';
|
|
}
|
|
|
|
/* copy value */
|
|
memmove(hole,
|
|
Value->Buffer,
|
|
Value->Length);
|
|
hole += Value->Length / sizeof(WCHAR);
|
|
*hole = 0;
|
|
}
|
|
else
|
|
{
|
|
/* remove the environment variable */
|
|
if (f == 0)
|
|
{
|
|
memmove(head,
|
|
tail,
|
|
(env_end - tail) * sizeof(WCHAR));
|
|
}
|
|
}
|
|
|
|
if (Environment == NULL)
|
|
{
|
|
RtlReleasePebLock();
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS NTAPI
|
|
RtlQueryEnvironmentVariable_U(PWSTR Environment,
|
|
PCUNICODE_STRING Name,
|
|
PUNICODE_STRING Value)
|
|
{
|
|
NTSTATUS Status;
|
|
PWSTR wcs;
|
|
UNICODE_STRING var;
|
|
PWSTR val;
|
|
BOOLEAN SysEnvUsed = FALSE;
|
|
|
|
DPRINT("RtlQueryEnvironmentVariable_U Environment %p Variable %wZ Value %p\n",
|
|
Environment, Name, Value);
|
|
|
|
if (Environment == NULL)
|
|
{
|
|
PPEB Peb = RtlGetCurrentPeb();
|
|
if (Peb) {
|
|
RtlAcquirePebLock();
|
|
Environment = Peb->ProcessParameters->Environment;
|
|
SysEnvUsed = TRUE;
|
|
}
|
|
}
|
|
|
|
if (Environment == NULL)
|
|
{
|
|
if (SysEnvUsed)
|
|
RtlReleasePebLock();
|
|
return(STATUS_VARIABLE_NOT_FOUND);
|
|
}
|
|
|
|
Value->Length = 0;
|
|
|
|
wcs = Environment;
|
|
DPRINT("Starting search at :%p\n", wcs);
|
|
while (*wcs)
|
|
{
|
|
var.Buffer = wcs++;
|
|
wcs = wcschr(wcs, L'=');
|
|
if (wcs == NULL)
|
|
{
|
|
wcs = var.Buffer + wcslen(var.Buffer);
|
|
DPRINT("Search at :%S\n", wcs);
|
|
}
|
|
if (*wcs)
|
|
{
|
|
var.Length = var.MaximumLength = (USHORT)(wcs - var.Buffer) * sizeof(WCHAR);
|
|
val = ++wcs;
|
|
wcs += wcslen(wcs);
|
|
DPRINT("Search at :%S\n", wcs);
|
|
|
|
if (RtlEqualUnicodeString(&var, Name, TRUE))
|
|
{
|
|
Value->Length = (USHORT)(wcs - val) * sizeof(WCHAR);
|
|
if (Value->Length <= Value->MaximumLength)
|
|
{
|
|
memcpy(Value->Buffer, val,
|
|
min(Value->Length + sizeof(WCHAR), Value->MaximumLength));
|
|
DPRINT("Value %S\n", val);
|
|
DPRINT("Return STATUS_SUCCESS\n");
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Return STATUS_BUFFER_TOO_SMALL\n");
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
if (SysEnvUsed)
|
|
RtlReleasePebLock();
|
|
|
|
return(Status);
|
|
}
|
|
}
|
|
wcs++;
|
|
}
|
|
|
|
if (SysEnvUsed)
|
|
RtlReleasePebLock();
|
|
|
|
DPRINT("Return STATUS_VARIABLE_NOT_FOUND: %wZ\n", Name);
|
|
return(STATUS_VARIABLE_NOT_FOUND);
|
|
}
|
|
|
|
/* EOF */
|