/*++ Copyright (c) 1993 Microsoft Corporation Module Name: dnarc.c Abstract: ARC/NV-RAM manipulation routines for 32-bit winnt setup. Author: Ted Miller (tedm) 19-December-1993 Revision History: --*/ #include "precomp.h" #pragma hdrstop #include "msg.h" #ifndef _X86_ #ifndef UNICODE #error dnarc.c is unicode-only #endif #include "msg.h" PWSTR BootVarNames[BootVarMax] = { L"SYSTEMPARTITION", L"OSLOADER", L"OSLOADPARTITION", L"OSLOADFILENAME", L"LOADIDENTIFIER", L"OSLOADOPTIONS" }; PWSTR szAUTOLOAD = L"AUTOLOAD", szCOUNTDOWN = L"COUNTDOWN"; PWSTR BootVarValues[BootVarMax]; PWSTR OriginalBootVarValues[BootVarMax]; PWSTR OriginalAutoload; PWSTR OriginalCountdown; DWORD BootVarComponentCount[BootVarMax]; PWSTR *BootVarComponents[BootVarMax]; DWORD LargestComponentCount; PWSTR DosDeviceTargets[24]; PWCHAR SystemPartitionDriveLetters; PWSTR SETUPLDR_FILENAME = L"\\setupldr"; WCHAR SetupLdrTarg[128]; // we set this flag to TRUE after nv-ram is written, so we'll know whether // we should restore it if the user cancels. BOOL bRestoreNVRAM = FALSE; // // Leave as array because some code uses sizeof(ArcNameDirectory) // WCHAR ArcNameDirectory[] = L"\\ArcName"; #define MAX_COMPONENTS 20 // // Helper macro to make object attribute initialization a little cleaner. // #define INIT_OBJA(Obja,UnicodeString,UnicodeText) \ \ RtlInitUnicodeString((UnicodeString),(UnicodeText)); \ \ InitializeObjectAttributes( \ (Obja), \ (UnicodeString), \ OBJ_CASE_INSENSITIVE, \ NULL, \ NULL \ ) PWSTR NormalizeArcPath( IN PWSTR Path ) /*++ Routine Description: Transform an ARC path into one with no sets of empty parenthesis (ie, transforom all instances of () to (0).). The returned path will be all lowercase. Arguments: Path - ARC path to be normalized. Return Value: Pointer to buffer containing normalized path. Caller must free this buffer with SpMemFree. --*/ { PWSTR p,q,r; PWSTR NormalizedPath; NormalizedPath = MALLOC((lstrlen(Path)+100)*sizeof(WCHAR)); ZeroMemory(NormalizedPath,(lstrlen(Path)+100)*sizeof(WCHAR)); for(p=Path; q=(PWSTR)StringString(p,L"()"); p=q+2) { r = NormalizedPath + lstrlen(NormalizedPath); _lstrcpynW(r,p,(q-p)+1); lstrcat(NormalizedPath,L"(0)"); } lstrcat(NormalizedPath,p); NormalizedPath = REALLOC(NormalizedPath,(lstrlen(NormalizedPath)+1)*sizeof(WCHAR)); // // If we do this, all nv-ram vars end up lowercased! // We don't actually need to do this for any reason in this program. // //CharLower(NormalizedPath); return(NormalizedPath); } VOID GetVarComponents( IN PWSTR VarValue, OUT PWSTR **Components, OUT PDWORD ComponentCount ) { PWSTR *components; DWORD componentCount; PWSTR p; PWSTR Var; PWSTR comp; DWORD len; components = MALLOC(MAX_COMPONENTS * sizeof(PWSTR)); for(Var=VarValue,componentCount=0; *Var; ) { // // Skip leading spaces. // while((*Var == L' ') || (*Var == L'\t')) { Var++; } if(*Var == 0) { break; } p = Var; while(*p && (*p != L';')) { p++; } len = (PUCHAR)p - (PUCHAR)Var; comp = MALLOC(len + sizeof(WCHAR)); len /= sizeof(WCHAR); _lstrcpynW(comp,Var,len+1); components[componentCount] = NormalizeArcPath(comp); FREE(comp); componentCount++; if(componentCount == MAX_COMPONENTS) { break; } Var = p; if(*Var) { Var++; // skip ; } } *Components = REALLOC(components,componentCount*sizeof(PWSTR)); *ComponentCount = componentCount; } PWSTR DriveLetterToArcPath( IN WCHAR DriveLetter ) { UNICODE_STRING UnicodeString; HANDLE DirectoryHandle; HANDLE ObjectHandle; OBJECT_ATTRIBUTES Obja; NTSTATUS Status; BOOL RestartScan; DWORD Context; BOOL MoreEntries; PWSTR ArcName; UCHAR Buffer[1024]; POBJECT_DIRECTORY_INFORMATION DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer; PWSTR ArcPath; PWSTR NtPath; NtPath = DosDeviceTargets[(WCHAR)CharUpper((PWCHAR)DriveLetter) - L'C']; if(!NtPath) { return(NULL); } // // Assume failure. // ArcPath = NULL; // // Open the \ArcName directory. // INIT_OBJA(&Obja,&UnicodeString,ArcNameDirectory); Status = NtOpenDirectoryObject(&DirectoryHandle,DIRECTORY_QUERY,&Obja); if(NT_SUCCESS(Status)) { RestartScan = TRUE; Context = 0; MoreEntries = TRUE; do { Status = NtQueryDirectoryObject( DirectoryHandle, Buffer, sizeof(Buffer), TRUE, // return single entry RestartScan, &Context, NULL // return length ); if(NT_SUCCESS(Status)) { CharLower(DirInfo->Name.Buffer); // // Make sure this name is a symbolic link. // if(DirInfo->Name.Length && (DirInfo->TypeName.Length >= 24) && StringUpperN((PWSTR)DirInfo->TypeName.Buffer,12) && !memcmp(DirInfo->TypeName.Buffer,L"SYMBOLICLINK",24)) { ArcName = MALLOC(DirInfo->Name.Length + sizeof(ArcNameDirectory) + sizeof(WCHAR)); lstrcpy(ArcName,ArcNameDirectory); DnConcatenatePaths(ArcName,DirInfo->Name.Buffer,(DWORD)(-1)); // // We have the entire arc name in ArcName. Now open it as a symbolic link. // INIT_OBJA(&Obja,&UnicodeString,ArcName); Status = NtOpenSymbolicLinkObject( &ObjectHandle, READ_CONTROL | SYMBOLIC_LINK_QUERY, &Obja ); if(NT_SUCCESS(Status)) { // // Finally, 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)) { // // nul-terminate the returned string // UnicodeString.Buffer[UnicodeString.Length/sizeof(WCHAR)] = 0; if(!lstrcmpi(UnicodeString.Buffer,NtPath)) { ArcPath = ArcName + (sizeof(ArcNameDirectory)/sizeof(WCHAR)); } } NtClose(ObjectHandle); } if(!ArcPath) { FREE(ArcName); } } } else { MoreEntries = FALSE; if(Status == STATUS_NO_MORE_ENTRIES) { Status = STATUS_SUCCESS; } } RestartScan = FALSE; } while(MoreEntries && !ArcPath); NtClose(DirectoryHandle); } // // ArcPath points into thje middle of a buffer. // The caller needs to be able to free it, so place it in its // own buffer here. // if(ArcPath) { ArcPath = DupString(ArcPath); FREE(ArcName); } return(ArcPath); } WCHAR ArcPathToDriveLetter( IN PWSTR ArcPath ) { NTSTATUS Status; HANDLE ObjectHandle; OBJECT_ATTRIBUTES Obja; UNICODE_STRING UnicodeString; UCHAR Buffer[1024]; WCHAR DriveLetter; WCHAR drive; PWSTR arcPath; // // Assume failure // DriveLetter = 0; arcPath = MALLOC(((lstrlen(ArcPath)+1)*sizeof(WCHAR)) + sizeof(ArcNameDirectory)); lstrcpy(arcPath,ArcNameDirectory); lstrcat(arcPath,L"\\"); lstrcat(arcPath,ArcPath); INIT_OBJA(&Obja,&UnicodeString,arcPath); 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)) { UnicodeString.Buffer[UnicodeString.Length/sizeof(WCHAR)] = 0; for(drive=L'C'; drive<=L'Z'; drive++) { if(DosDeviceTargets[drive-L'C'] && !lstrcmpi(UnicodeString.Buffer,DosDeviceTargets[drive-L'C'])) { DriveLetter = drive; break; } } } NtClose(ObjectHandle); } FREE(arcPath); return(DriveLetter); } VOID InitDriveNameTranslations( VOID ) { WCHAR DriveName[3]; WCHAR Drive; WCHAR Buffer[512]; DriveName[1] = L':'; DriveName[2] = 0; // // Calculate NT names for all local hard disks C-Z. // for(Drive=L'C'; Drive<=L'Z'; Drive++) { DosDeviceTargets[Drive-L'C'] = NULL; if(MyGetDriveType(Drive) == DRIVE_FIXED) { DriveName[0] = Drive; if(QueryDosDeviceW(DriveName,Buffer,SIZECHARS(Buffer))) { DosDeviceTargets[Drive-L'C'] = DupString(Buffer); } } } } VOID DetermineSystemPartitions( VOID ) { BOOL syspart[24]; PWSTR *SyspartComponents; DWORD NumSyspartComponents; DWORD d,x; WCHAR drive; SyspartComponents = BootVarComponents[BootVarSystemPartition]; NumSyspartComponents = BootVarComponentCount[BootVarSystemPartition]; // // Convert each system partition to a drive letter. // ZeroMemory(syspart,sizeof(syspart)); for(d=0; d LargestComponentCount) { LargestComponentCount = BootVarComponentCount[var]; } } DetermineSystemPartitions(); ec = NO_ERROR; } return(ec); } BOOL InitializeArcStuff( IN HWND hdlg ) { switch(DoInitializeArcStuff()) { case NO_ERROR: // // Make sure there is at least one valid system partition. // if(SystemPartitionDriveLetters && *SystemPartitionDriveLetters) { // // Pick the first system partition as the default. // SystemPartitionDrive = *SystemPartitionDriveLetters; } else { MessageBoxFromMessage( hdlg, MSG_NO_SYSPARTS, AppTitleStringId, MB_OK | MB_ICONSTOP ); return(FALSE); } return(TRUE); default: // // Unknown error. // MessageBoxFromMessage( hdlg, MSG_COULDNT_READ_NVRAM, AppTitleStringId, MB_OK | MB_ICONSTOP ); return(FALSE); } } BOOL DoSetNvRamVar( IN PWSTR VarName, IN PWSTR VarValue ) { UNICODE_STRING U1,U2; RtlInitUnicodeString(&U1,VarName); RtlInitUnicodeString(&U2,VarValue); return(NT_SUCCESS(NtSetSystemEnvironmentValue(&U1,&U2))); } BOOL WriteNewBootSetVar( IN DWORD var, IN PTSTR NewPart ) { WCHAR Buffer[2048]; DWORD i; // // Write the new part first. // lstrcpy(Buffer,NewPart); // // Append all components that were not deleted. // for(i=0; i 1) { EnableWindow( GetDlgItem(hdlg, IDC_OPTIONS), TRUE ); SendDlgItemMessage( hdlg, IDC_OPTIONS, BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0) ); SetFocus(GetDlgItem(hdlg, IDC_OPTIONS)); RetreiveAndFormatMessageIntoBuffer( MSG_SYSPART_LOW, Buffer, SIZECHARS(Buffer) ); } else { EnableWindow( GetDlgItem(hdlg, IDC_OPTIONS), FALSE ); SendDlgItemMessage( hdlg, IDC_CONTINUE, BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0) ); SetFocus(GetDlgItem(hdlg, IDC_CONTINUE)); RetreiveAndFormatMessageIntoBuffer( MSG_SYSPART_LOW_1, Buffer, SIZECHARS(Buffer) ); } SetDlgItemText(hdlg,IDC_TEXT1,Buffer); return(FALSE); } case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_CONTINUE: case IDC_OPTIONS: case IDCANCEL: EndDialog(hdlg, (UINT)LOWORD(wParam)); break; default: return(FALSE); } break; default: return(FALSE); } return(TRUE); } UINT DlgProcSysPartNtftWarn( IN HWND hdlg, IN UINT msg, IN WPARAM wParam, IN LPARAM lParam ) { switch(msg) { case WM_INITDIALOG: { TCHAR Buffer[4096]; PTSTR p; p = MyLoadString(AppTitleStringId); SetWindowText(hdlg,p); FREE(p); // // // Center the dialog on the screen and bring it to the top. // CenterDialog(hdlg); SetForegroundWindow(hdlg); MessageBeep(MB_ICONHAND); // // Set the icon to be the stop sign // SendDlgItemMessage( hdlg, IDC_EXCLAIM, STM_SETICON, (WPARAM)LoadIcon(NULL, IDI_HAND), 0 ); RetreiveAndFormatMessageIntoBuffer( MSG_SYSPART_NTFT_MULTI, Buffer, SIZECHARS(Buffer) ); SetDlgItemText(hdlg,IDC_TEXT1,Buffer); return(FALSE); } case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_OPTIONS: case IDCANCEL: EndDialog(hdlg, (UINT)LOWORD(wParam)); break; default: return(FALSE); } break; default: return(FALSE); } return(TRUE); } #endif // ndef _X86_