windows-nt/Source/XPSP1/NT/base/ntsetup/syssetup/arc.c
2020-09-26 16:20:57 +08:00

520 lines
11 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
arc.c
Abstract:
Routines relating to boot.ini.
Author:
Ted Miller (tedm) 4-Apr-1995
Revision History:
--*/
#include "setupp.h"
#pragma hdrstop
PWSTR
ArcDevicePathToNtPath(
IN PCWSTR ArcPath
)
/*++
Routine Description:
Convert an ARC path (device only) to an NT path.
Arguments:
ArcPath - supplies path to be converted.
Return Value:
Converted path. Caller must free with MyFree().
--*/
{
NTSTATUS Status;
HANDLE ObjectHandle;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING UnicodeString;
UCHAR Buffer[1024];
PWSTR arcPath;
PWSTR ntPath;
//
// Assume failure
//
ntPath = NULL;
arcPath = MyMalloc(((lstrlen(ArcPath)+1)*sizeof(WCHAR)) + sizeof(L"\\ArcName"));
if( !arcPath ) {
return NULL;
}
lstrcpy(arcPath,L"\\ArcName\\");
lstrcat(arcPath,ArcPath);
RtlInitUnicodeString(&UnicodeString,arcPath);
InitializeObjectAttributes(
&Obja,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenSymbolicLinkObject(
&ObjectHandle,
READ_CONTROL | SYMBOLIC_LINK_QUERY,
&Obja
);
if(NT_SUCCESS(Status)) {
//
// Query the object to get the link target.
//
UnicodeString.Buffer = (PWSTR)Buffer;
UnicodeString.Length = 0;
UnicodeString.MaximumLength = sizeof(Buffer);
Status = NtQuerySymbolicLinkObject(ObjectHandle,&UnicodeString,NULL);
if(NT_SUCCESS(Status)) {
ntPath = MyMalloc(UnicodeString.Length+sizeof(WCHAR));
if( ntPath ) {
CopyMemory(ntPath,UnicodeString.Buffer,UnicodeString.Length);
ntPath[UnicodeString.Length/sizeof(WCHAR)] = 0;
}
}
NtClose(ObjectHandle);
}
MyFree(arcPath);
return(ntPath);
}
PWSTR
NtFullPathToDosPath(
IN PCWSTR NtPath
)
{
OBJECT_ATTRIBUTES Attributes;
UNICODE_STRING UnicodeString;
NTSTATUS Status;
HANDLE DosDevicesDir;
HANDLE DosDevicesObj;
PWSTR dosPath;
PWSTR currentDosPath;
ULONG Context;
ULONG Length;
BOOLEAN RestartScan;
CHAR Buffer[1024];
WCHAR LinkSource[2*MAX_PATH];
WCHAR LinkTarget[2*MAX_PATH];
POBJECT_DIRECTORY_INFORMATION DirInfo;
UINT PrefixLength;
UINT NtPathLength;
WCHAR canonNtPath[MAX_PATH];
OBJECT_ATTRIBUTES Obja;
HANDLE ObjectHandle;
PWSTR ntPath;
//
// Canonicalize the NT path by following the symbolic link.
//
ntPath = (PWSTR) NtPath;
dosPath = NULL;
RtlInitUnicodeString(&UnicodeString,ntPath);
InitializeObjectAttributes(
&Obja,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
NtPathLength = UnicodeString.Length/sizeof(WCHAR);
PrefixLength = UnicodeString.Length/sizeof(WCHAR);
for (;;) {
Status = NtOpenSymbolicLinkObject(
&ObjectHandle,
READ_CONTROL | SYMBOLIC_LINK_QUERY,
&Obja
);
if (NT_SUCCESS(Status)) {
UnicodeString.Buffer = canonNtPath;
UnicodeString.Length = 0;
UnicodeString.MaximumLength = sizeof(WCHAR)*MAX_PATH;
RtlZeroMemory(canonNtPath, UnicodeString.MaximumLength);
Status = NtQuerySymbolicLinkObject(ObjectHandle,&UnicodeString,NULL);
if(NT_SUCCESS(Status)) {
if (NtPathLength > PrefixLength) {
RtlCopyMemory((PCHAR) canonNtPath + UnicodeString.Length,
ntPath + PrefixLength,
(NtPathLength - PrefixLength)*sizeof(WCHAR));
}
ntPath = canonNtPath;
}
NtClose(ObjectHandle);
break;
}
RtlInitUnicodeString(&UnicodeString,ntPath);
PrefixLength--;
while (PrefixLength > 0) {
if (ntPath[PrefixLength] == '\\') {
break;
}
PrefixLength--;
}
if (!PrefixLength) {
break;
}
UnicodeString.Length = (USHORT)(PrefixLength*sizeof(WCHAR));
InitializeObjectAttributes(
&Obja,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
}
NtPathLength = lstrlen(ntPath);
//
// Open \DosDevices directory.
//
RtlInitUnicodeString(&UnicodeString,L"\\DosDevices");
InitializeObjectAttributes(&Attributes,&UnicodeString,OBJ_CASE_INSENSITIVE,NULL,NULL);
Status = NtOpenDirectoryObject(&DosDevicesDir,DIRECTORY_QUERY,&Attributes);
if(!NT_SUCCESS(Status)) {
return(NULL);
}
//
// Iterate each object in that directory.
//
Context = 0;
RestartScan = TRUE;
Status = NtQueryDirectoryObject(
DosDevicesDir,
Buffer,
sizeof(Buffer),
TRUE,
RestartScan,
&Context,
&Length
);
RestartScan = FALSE;
DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
while(NT_SUCCESS(Status)) {
DirInfo->Name.Buffer[DirInfo->Name.Length/sizeof(WCHAR)] = 0;
DirInfo->TypeName.Buffer[DirInfo->TypeName.Length/sizeof(WCHAR)] = 0;
//
// Skip this entry if it's not a symbolic link.
//
if(DirInfo->Name.Length && !lstrcmpi(DirInfo->TypeName.Buffer,L"SymbolicLink")) {
//
// Get this \DosDevices object's link target.
//
UnicodeString.Buffer = LinkSource;
UnicodeString.Length = sizeof(L"\\DosDevices\\") - sizeof(WCHAR);
UnicodeString.MaximumLength = sizeof(LinkSource);
lstrcpy(LinkSource,L"\\DosDevices\\");
RtlAppendUnicodeStringToString(&UnicodeString,&DirInfo->Name);
InitializeObjectAttributes(&Attributes,&UnicodeString,OBJ_CASE_INSENSITIVE,NULL,NULL);
Status = NtOpenSymbolicLinkObject(
&DosDevicesObj,
READ_CONTROL|SYMBOLIC_LINK_QUERY,
&Attributes
);
if(NT_SUCCESS(Status)) {
UnicodeString.Buffer = LinkTarget;
UnicodeString.Length = 0;
UnicodeString.MaximumLength = sizeof(LinkTarget);
Status = NtQuerySymbolicLinkObject(DosDevicesObj,&UnicodeString,NULL);
CloseHandle(DosDevicesObj);
if(NT_SUCCESS(Status)) {
//
// Make sure LinkTarget is nul-terminated.
//
PrefixLength = UnicodeString.Length/sizeof(WCHAR);
UnicodeString.Buffer[PrefixLength] = 0;
//
// See if it's a prefix of the path we're converting,
//
if(!_wcsnicmp(ntPath,LinkTarget,PrefixLength)) {
//
// Got a match.
//
currentDosPath = dosPath;
if(dosPath = MyMalloc(DirInfo->Name.Length + ((NtPathLength - PrefixLength + 1)*sizeof(WCHAR)))) {
lstrcpy(dosPath,DirInfo->Name.Buffer);
lstrcat(dosPath,ntPath + PrefixLength);
}
if (currentDosPath) {
if (lstrlen(currentDosPath) < lstrlen(dosPath)) {
MyFree(dosPath);
dosPath = currentDosPath;
} else {
MyFree(currentDosPath);
}
}
}
}
}
}
//
// Go on to next object.
//
Status = NtQueryDirectoryObject(
DosDevicesDir,
Buffer,
sizeof(Buffer),
TRUE,
RestartScan,
&Context,
&Length
);
}
CloseHandle(DosDevicesDir);
return dosPath;
}
BOOL
SetNvRamVariable(
IN PCWSTR VarName,
IN PCWSTR VarValue
)
{
UNICODE_STRING VarNameU,VarValueU;
NTSTATUS Status;
//
// Set up unicode strings.
//
RtlInitUnicodeString(&VarNameU ,VarName );
RtlInitUnicodeString(&VarValueU,VarValue);
pSetupEnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE);
Status = NtSetSystemEnvironmentValue(&VarNameU,&VarValueU);
return(NT_SUCCESS(Status));
}
BOOL
ChangeBootTimeoutNvram(
IN UINT Timeout
)
/*++
Routine Description:
Changes the boot countdown value in nv-ram.
The non-ARC version (which operates on boot.ini) is in i386\bootini.c.
Arguments:
Timeout - supplies new timeout value, in seconds.
Return Value:
None.
--*/
{
WCHAR TimeoutValue[24];
wsprintf(TimeoutValue,L"%u",Timeout);
if(!SetNvRamVariable(L"COUNTDOWN",TimeoutValue)) {
return(FALSE);
}
return(SetNvRamVariable(L"AUTOLOAD",L"YES"));
}
#if defined(EFI_NVRAM_ENABLED)
BOOL
ChangeBootTimeoutEfiNvram(
IN UINT Timeout
)
/*++
Routine Description:
Changes the boot countdown value in EFI nv-ram.
Arguments:
Timeout - supplies new timeout value, in seconds.
Return Value:
None.
--*/
{
NTSTATUS Status;
BOOT_OPTIONS BootOptions;
ASSERT(IsEfi());
BootOptions.Version = BOOT_OPTIONS_VERSION;
BootOptions.Length = sizeof(BootOptions);
BootOptions.Timeout = Timeout;
pSetupEnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE);
Status = NtSetBootOptions(&BootOptions, BOOT_OPTIONS_FIELD_TIMEOUT);
return(NT_SUCCESS(Status));
}
#endif // defined(EFI_NVRAM_ENABLED)
#if defined(_X86_)
BOOL
IsArc(
VOID
)
/*++
Routine Description:
Run time check to determine if this is an Arc system. We attempt to read an
Arc variable using the Hal. This will fail for Bios based systems.
Arguments:
None
Return Value:
True = This is an Arc system.
--*/
{
UNICODE_STRING UnicodeString;
NTSTATUS Status;
WCHAR Buffer[4096];
if(!pSetupEnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE))
return(FALSE); // need better error handling?
//
// Get the env var into the temp buffer.
//
RtlInitUnicodeString(&UnicodeString, L"OSLOADER");
Status = NtQuerySystemEnvironmentValue(
&UnicodeString,
Buffer,
sizeof(Buffer)/sizeof(WCHAR),
NULL
);
return(NT_SUCCESS(Status) ? TRUE: FALSE);
}
#endif
BOOL
ChangeBootTimeout(
IN UINT Timeout
)
/*++
Routine Description:
Changes the boot countdown value; decides whether
to use ARC or non-ARC version.
Arguments:
Timeout - supplies new timeout value, in seconds.
Return Value:
None.
--*/
{
#if defined(EFI_NVRAM_ENABLED)
if (IsEfi()) {
return ChangeBootTimeoutEfiNvram(Timeout);
}
#endif
if (IsArc()) {
return ChangeBootTimeoutNvram(Timeout);
}
#if defined(_X86_)
return ChangeBootTimeoutBootIni(Timeout);
#else
return FALSE;
#endif
}