/*++ 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(_AMD64_) || defined(_X86_) return ChangeBootTimeoutBootIni(Timeout); #else return FALSE; #endif }