#include "spprecmp.h" #pragma hdrstop /*++ Revision History Michael Peterson (Seagate Software) + Modified SpIsNtInDirectory() so that it always returns FALSE if DR is in effect. --*/ PWSTR *NtDirectoryList; ULONG NtDirectoryCount; BOOLEAN SpNFilesExist( IN OUT PWSTR PathName, IN PWSTR *Files, IN ULONG FileCount, IN BOOLEAN Directories ) { UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES Obja; HANDLE Handle; ULONG i; PWSTR FilenamePart; IO_STATUS_BLOCK IoStatusBlock; NTSTATUS Status; // // No reason to call this routine to check for 0 files. // ASSERT(FileCount); // // Stick a backslash on the end of the path part if necessary. // SpConcatenatePaths(PathName,L""); FilenamePart = PathName + wcslen(PathName); // // Check each file. If any one of then doesn't exist, // then return FALSE. // for(i=0; iDiskNumber].Geometry.BytesPerSector; // // Get cluster size from the BPB. // ASSERT(Region->Filesystem >= FilesystemFirstKnown); Status = SpOpenPartition( HardDisks[Region->DiskNumber].DevicePath, SpPtGetOrdinal(Region,PartitionOrdinalCurrent), &Handle, FALSE ); if(!NT_SUCCESS(Status)) { goto xx0; } UBuffer = SpMemAlloc(2*bps); Buffer = ALIGN(UBuffer,bps); Status = SpReadWriteDiskSectors( Handle, 0, 1, bps, Buffer, FALSE ); if(!NT_SUCCESS(Status)) { ZwClose(Handle); SpMemFree(UBuffer); goto xx0; } // // Make sure this sector appears to hold a valid boot sector // for a hard disk. // // "55AA" was not presented by DOS 5.0 for NEC98, // so must not to check "55aa" in BPB, // if(((!IsNEC_98) && ((Buffer[510] == 0x55) && (Buffer[511] == 0xaa) && (Buffer[21] == 0xf8))) || ((IsNEC_98) && (Buffer[21] == 0xf8))) { //NEC98 // // bps * spc. // ClusterSize = (ULONG)U_USHORT(Buffer+11) * (ULONG)Buffer[13]; } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpRemoveInstallation: sector 0 on %ws is invalid\n",PartitionPath)); Status = STATUS_UNSUCCESSFUL; } ZwClose(Handle); SpMemFree(UBuffer); if(!NT_SUCCESS(Status)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpRemoveInstallation: can't get cluster size on %ws\n",PartitionPath)); goto xx0; } // // Find out if the repair directory exists, if it does exist load // setup.log from the repair directory. Otherwise, load setup.log // from the WinNt directory // wcscpy(FileName,PartitionPath); SpConcatenatePaths(FileName,Directory); RootDirLength = wcslen(FileName); SpConcatenatePaths(FileName,SETUP_REPAIR_DIRECTORY); INIT_OBJA( &Obja, &UnicodeString, FileName ); Status = ZwOpenFile( &TempHandle, FILE_LIST_DIRECTORY | SYNCHRONIZE, &Obja, &IoStatusBlock, FILE_SHARE_READ, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); if( !NT_SUCCESS( Status ) ) { FileName[ RootDirLength ] = L'\0'; } else { ZwClose( TempHandle ); } SpConcatenatePaths(FileName,SETUP_LOG_FILENAME); // // Load setup.log from the given path. // Status = SpLoadSetupTextFile(FileName,NULL,0,&Inf,&ErrLine,TRUE,FALSE); if(!NT_SUCCESS(Status)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpRemoveInstallation: can't load inf file %ws (%lx)\n",FileName,Status)); while(1) { ULONG ks[2] = { ASCI_CR, 0 }; SpStartScreen( SP_SCRN_CANT_LOAD_SETUP_LOG, 3, HEADER_HEIGHT+2, FALSE, FALSE, DEFAULT_ATTRIBUTE, FileName + wcslen(PartitionPath) // skip \device\harddiskx\partitiony ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, 0 ); switch(SpWaitValidKey(ks,NULL,NULL)) { case ASCI_CR: goto xx0; } } } // // Go through all files in the [Repair.WinntFiles] section // SpStartScreen( SP_SCRN_WAIT_REMOVING_NT_FILES, 0, 8, TRUE, FALSE, DEFAULT_ATTRIBUTE ); // // Determine whether setup.log has the new or old style // if( OldFormatSetupLogFile = !IsSetupLogFormatNew( Inf ) ) { SectionName = SIF_REPAIRWINNTFILES; } else { SectionName = SIF_NEW_REPAIR_WINNTFILES; } FileCount = SpCountLinesInSection(Inf,SectionName); SpFormatMessage( TemporaryBuffer, sizeof(TemporaryBuffer), SP_TEXT_SETUP_IS_REMOVING_FILES ); Gauge = SpCreateAndDisplayGauge( FileCount, 0, VideoVars.ScreenHeight - STATUS_HEIGHT - (3*GAUGE_HEIGHT/2), TemporaryBuffer, NULL, GF_PERCENTAGE, 0 ); // // Clear the status area. // SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,0); // // Set the status text in the lower right portion of the screen // to "Removing:" in preparation for displaying filenames as // files are deleted. The 12 is for an 8.3 name. // SpDisplayStatusActionLabel(SP_STAT_REMOVING,12); for(i=0; i MenuWidth) { MenuWidth = SplangGetColumnCount(MenuItems[i]); } } // // Use 80-column screen here because that's how the screen text // above the menu will be formatted. // MenuLeftX = 40 - (MenuWidth/2); // // Create menu and populate it. // SpDisplayScreen(ScreenMsgId,3,HEADER_HEIGHT+1); Menu = SpMnCreate( MenuLeftX, NextMessageTopLine+(SplangQueryMinimizeExtraSpacing() ? 1 : 2), MenuWidth, VideoVars.ScreenHeight-STATUS_HEIGHT-NextMessageTopLine-(SplangQueryMinimizeExtraSpacing() ? 2 : 3) ); for(i=0; i<=NtCount; i++) { SpMnAddItem(Menu,MenuItems[i],MenuLeftX,MenuWidth,TRUE,i); } // // Present the menu of installations available for removal // on this partition and await a choice. // b = TRUE; do { ULONG Keys[4] = { ASCI_CR,KEY_F3,ASCI_ESC,0 }; ULONG Mnemonics[2] = { MnemonicRemoveFiles,0 }; ULONG key; ULONG_PTR Choice; SpDisplayScreen(ScreenMsgId,3,HEADER_HEIGHT+1); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ESC_EQUALS_CANCEL, SP_STAT_ENTER_EQUALS_SELECT, SP_STAT_F3_EQUALS_EXIT, 0 ); nextkey: SpMnDisplay(Menu, NtCount, FALSE, Keys, NULL, NULL, NULL, &key, &Choice); if(key == KEY_F3) { SpConfirmExit(); } else if(key == ASCI_ESC) { break; } else if(key == ASCI_CR) { if(Choice == NtCount) { b = FALSE; } else { BOOLEAN keys; ULONG ValidKeys2[3] = { KEY_F3,ASCI_ESC,0 }; // // User wants to actually remove an installation. // Confirm and then do that here. // redraw2: SpStartScreen( SP_SCRN_REMOVE_EXISTING_NT, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, MenuItems[Choice] ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_R_EQUALS_REMOVE_FILES, SP_STAT_ESC_EQUALS_CANCEL, SP_STAT_F3_EQUALS_EXIT, 0 ); keys = TRUE; while(keys) { switch(SpWaitValidKey(ValidKeys2,NULL,Mnemonics)) { case KEY_F3: SpConfirmExit(); goto redraw2; case ASCI_ESC: keys = FALSE; break; default: // // Must be r=remove files. // *SpaceFreed = SpRemoveInstallation( Region, PartitionPath, NtDirectoryList[MenuOrdinals[Choice]] ); rc = TRUE; SpStartScreen( SP_SCRN_DONE_REMOVING_EXISTING_NT, 4, HEADER_HEIGHT+3, FALSE, FALSE, DEFAULT_ATTRIBUTE, *SpaceFreed ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, 0 ); while(SpInputGetKeypress() != ASCI_CR) ; keys = FALSE; b = FALSE; break; } } } } else { goto nextkey; } } while(b); SpMnDestroy(Menu); xx1: for(i=0; i<=NtCount; i++) { SpMemFree(MenuItems[i]); } SpMemFree(MenuItems); SpMemFree(MenuOrdinals); xx0: SpMemFree(PartitionPath); return(rc); } #if 0 typedef VOID (*PINSTALLATION_CALLBACK_ROUTINE)( IN PWSTR DirectoryPath, IN PFILE_DIRECTORY_INFORMATION FoundFileInfo ); // // Stuff to reduce stack usage. // PINSTALLATION_CALLBACK_ROUTINE FileIterationCallback; POBJECT_ATTRIBUTES FileIterationObja; PIO_STATUS_BLOCK FileIterationIoStatusBlock; PUNICODE_STRING FileIterationUnicodeString; VOID SpIterateInstallationFilesWorker( IN PWSTR FilenamePart1, IN PWSTR FilenamePart2 ) { PVOID InfoBuffer; PWSTR FullPath; NTSTATUS Status; HANDLE hFile; BOOLEAN restart; #define DIRINFO(x) ((PFILE_DIRECTORY_INFORMATION)InfoBuffer) InfoBuffer = SpMemAlloc(1024); // // Form the full path name of the current directory. // FullPath = SpMemAlloc( ( wcslen(FilenamePart1) + (FilenamePart2 ? wcslen(FilenamePart2) : 0), + 2) * sizeof(WCHAR) ); wcscpy(FullPath,FilenamePart1); if(FilenamePart2) { SpConcatenatePaths(FullPath,FilenamePart2); } // // Open the directory for list access. // INIT_OBJA(FileIterationObja,FileIterationUnicodeString,FullPath); Status = ZwOpenFile( &hFile, FILE_LIST_DIRECTORY | SYNCHRONIZE, FileIterationObja, FileIterationIoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT ); if(NT_SUCCESS(Status)) { restart = TRUE; do { Status = ZwQueryDirectoryFile( hFile, NULL, NULL, NULL, FileIterationIoStatusBlock, InfoBuffer, 1024 - sizeof(WCHAR), // leave room for nul FileDirectoryInformation, TRUE, // return single entry NULL, // no file name (match all files) restart ); restart = FALSE; if(NT_SUCCESS(Status)) { // // nul-terminate the filename just in case // DIRINFO->FileName[DIRINFO->FileNameLength/sizeof(WCHAR)] = 0; if(DIRINFO->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if(DIRINFO->FileName[0] != L'.') { SpIterateInstallationFiles( FullPath, DIRINFO->FileName ); FileIterationCallback(FullPath,InfoBuffer); } } else { FileIterationCallback(FullPath,InfoBuffer); } } } while(NT_SUCCESS(Status)); ZwClose(hFile); } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to open directory %ws for list access (%lx)\n",FullPath,Status)); } SpMemFree(FullPath); SpMemFree(InfoBuffer); } VOID SpIterateInstallationFiles( IN PWSTR FilenamePart1, IN PWSTR FilenamePart2, IN PINSTALLATION_CALLBACK_ROUTINE CallbackFunction ) { // // Set up stack-saving globals // FileIterationIoStatusBlock = SpMemAlloc(sizeof(IO_STATUS_BLOCK); FileIterationUnicodeString = SpMemAlloc(sizeof(UNICODE_STRING)); FileIterationObja = SpMemAlloc(sizeof(OBJECT_ATTRIBUTES); FileIterationCallback = CallbackFunction; // // Do the iteration. // SpIterateInstallationFilesWorker(FileNamePart1,FilenamePart2); // // Clean up. // SpMemFree(FileIterationObja); SpMemFree(FileIterationUnicodeString); SpMemFree(FileIterationIoStatusBlock); } #endif BOOLEAN IsSetupLogFormatNew( IN PVOID Inf ) /*++ Routine Description: Informs the caller whether or not the information on setup.log is in the new format. Arguments: Inf - Return Value: TRUE if the information is in the new format. FALSE otherwise. --*/ { return( SpGetSectionKeyExists ( Inf, SIF_NEW_REPAIR_SIGNATURE, SIF_NEW_REPAIR_VERSION_KEY ) ); }