Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4410 lines
115 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. win9xupg.c
  5. Abstract:
  6. Code for detecting a Win9x installation, and code to blow away any
  7. existing Win9x files.
  8. Author:
  9. Jim Schmidt (jimschm) 24-Feb-1997
  10. Revision History:
  11. Marc R. Whitten (marcw) 28-Feb-1997
  12. Moved Win9x copy and delete functions from spcopy.c to this module
  13. Added drive letter mapping code.
  14. Jim Schmidt (JimSchm) November, December 2000
  15. Win9x uninstall work
  16. Jay Krell (a-JayK) December 2000
  17. Win9x uninstall work (cab)
  18. --*/
  19. #include "spprecmp.h"
  20. #pragma hdrstop
  21. #include "ntddscsi.h"
  22. #include "spwin9xuninstall.h"
  23. #include "spcab.h"
  24. #include "spmemory.h"
  25. #include "spprintf.h"
  26. #include "spcabp.h"
  27. #include "bootvar.h"
  28. #include "spwin.h"
  29. extern BOOLEAN DriveAssignFromA; //NEC98
  30. #define STRING_VALUE(s) REG_SZ,(s),(wcslen((s))+1)*sizeof(WCHAR)
  31. typedef enum {
  32. BACKUP_DOESNT_EXIST,
  33. BACKUP_IN_PROGRESS,
  34. BACKUP_SKIPPED_BY_USER,
  35. BACKUP_COMPLETE
  36. } JOURNALSTATUS;
  37. // in spdskreg.c
  38. BOOL
  39. SpBuildDiskRegistry(
  40. VOID
  41. );
  42. VOID
  43. SpGetPartitionStartingOffsetAndLength(
  44. IN DWORD DiskIndex,
  45. IN PDISK_REGION Region,
  46. IN BOOL ExtendedPartition,
  47. OUT PLARGE_INTEGER Offset,
  48. OUT PLARGE_INTEGER Length
  49. );
  50. VOID
  51. SpDumpDiskRegistry(
  52. VOID
  53. );
  54. // in spsetup.c
  55. VOID
  56. SpCompleteBootListConfig(
  57. WCHAR DriveLetter
  58. );
  59. // in win31upg.c
  60. WCHAR
  61. SpExtractDriveLetter(
  62. IN PWSTR PathComponent
  63. );
  64. BOOLEAN
  65. SpIsWin9xMsdosSys(
  66. IN PDISK_REGION Region,
  67. OUT PSTR* Win9xPath
  68. );
  69. VOID
  70. SpAssignDriveLettersToMatchWin9x (
  71. IN PVOID WinntSif
  72. );
  73. VOID
  74. SppMoveWin9xFilesWorker (
  75. IN PVOID WinntSif,
  76. IN PCWSTR MoveSection,
  77. IN BOOLEAN Rollback
  78. );
  79. VOID
  80. SppDeleteWin9xFilesWorker (
  81. IN PVOID WinntSif,
  82. IN PCWSTR FileSection, OPTIONAL
  83. IN PCWSTR DirSection, OPTIONAL
  84. IN BOOLEAN Rollback
  85. );
  86. PDISK_REGION
  87. SppRegionFromFullNtName (
  88. IN PWSTR NtName,
  89. IN PartitionOrdinalType OrdinalType,
  90. OUT PWSTR *Path OPTIONAL
  91. );
  92. BOOLEAN
  93. SppCreateTextModeBootEntry (
  94. IN PWSTR LoadIdentifierString,
  95. IN PWSTR OsLoadOptions, OPTIONAL
  96. IN BOOLEAN Deafult
  97. );
  98. BOOLEAN
  99. SppDelEmptyDir (
  100. IN PCWSTR NtPath
  101. );
  102. ENUMNONNTUPRADETYPE
  103. SpLocateWin95(
  104. OUT PDISK_REGION *InstallRegion,
  105. OUT PWSTR *InstallPath,
  106. OUT PDISK_REGION *SystemPartitionRegion
  107. )
  108. /*++
  109. Routine Description:
  110. Determine whether we are to continue a Win95 upgrade.
  111. This is based solely on values found in the parameters file.
  112. Arguments:
  113. InstallRegion - Returns a pointer to the region to install to.
  114. InstallPath - Returns a pointer to a buffer containing the path
  115. on the partition to install to. The caller must free this
  116. buffer with SpMemFree().
  117. SystemPartitionRegion - Returns a pointer to the region for the
  118. system partition (ie, C:).
  119. Return Value:
  120. UpgradeWin95 if we are supposed to upgrade win95
  121. NoWinUpgrade if not.
  122. --*/
  123. {
  124. PWSTR Win95Drive;
  125. PWSTR p;
  126. PWSTR Sysroot;
  127. PDISK_REGION CColonRegion;
  128. ENUMNONNTUPRADETYPE UpgradeType = UpgradeWin95;
  129. //
  130. // Changed sequence the test migration flag and migrate drive letters,
  131. // to not migrate drive letters when fresh from Win9x on NEC98.
  132. //
  133. //
  134. // Test the migration flag.
  135. //
  136. p = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,WINNT_D_WIN95UPGRADE_W,0);
  137. Win95Drive = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,WINNT_D_WIN32_DRIVE_W,0);
  138. Sysroot = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,WINNT_D_WIN32_PATH_W,0);
  139. if (!IsNEC_98) {
  140. CColonRegion = SpPtValidSystemPartition();
  141. }
  142. if(!p || _wcsicmp(p,WINNT_A_YES_W) || !Win95Drive || (!IsNEC_98 && !CColonRegion) || !Sysroot) {
  143. UpgradeType = NoWinUpgrade;
  144. }
  145. //
  146. // NEC98 must not migrate drive letters, when fresh setup.
  147. // The drive letter is started from A: on Win9x, but should be started from C:
  148. // on Win2000 fresh setup.
  149. //
  150. // NOTE : Also don't migrate the drive letters for clean installs
  151. // from winnt32.exe on Win9x machines, since the drive letter migration
  152. // is a bogus migration. We don't tell the mountmgr to reserve the drive letter
  153. // and when user creates and deletes a partition then we might end up assigning
  154. // the existing drive letter to new partition, which is really bad.
  155. //
  156. if(UpgradeType == NoWinUpgrade) {
  157. return UpgradeType;
  158. }
  159. //
  160. // First, make sure drive letters are correct.
  161. //
  162. SpAssignDriveLettersToMatchWin9x(WinntSifHandle);
  163. if(!IsNEC_98 && (UpgradeType == NoWinUpgrade)) {
  164. return(UpgradeType);
  165. }
  166. //
  167. // Migration enabled and everything looks OK.
  168. //
  169. *InstallRegion = SpRegionFromDosName(Win95Drive);
  170. *InstallPath = Sysroot;
  171. //
  172. // On NEC98, SystemPartitionRegion must be same as InstallRegion.
  173. //
  174. *SystemPartitionRegion = (!IsNEC_98) ? CColonRegion : *InstallRegion;
  175. return(UpgradeType);
  176. }
  177. #if 0
  178. BOOLEAN
  179. SpLocateWin95(
  180. IN PVOID WinntSif
  181. )
  182. /*++
  183. Routine Description:
  184. SpLocateWin95 looks for any installation of Windows 95 on any
  185. hard disk drive, and returns TRUE if one is found. When the user
  186. initiates setup from boot floppies, we alert them that they have
  187. an option to migrate.
  188. Arguments:
  189. none
  190. Return Value:
  191. TRUE if we are migrating Win95.
  192. FALSE otherwise.
  193. --*/
  194. {
  195. PDISK_REGION CColonRegion;
  196. PDISK_REGION Region;
  197. PUCHAR Win9xPath;
  198. //
  199. // If setup was initiated from WINNT95, don't bother telling user
  200. // about the migrate option--they obviously know.
  201. //
  202. if (Winnt95Setup)
  203. return TRUE;
  204. //
  205. // Look at boot sector for Win95 stuff
  206. //
  207. CLEAR_CLIENT_SCREEN();
  208. SpDisplayStatusText(SP_STAT_LOOKING_FOR_WIN95,DEFAULT_STATUS_ATTRIBUTE);
  209. //
  210. // See if there is a valid C: already. If not, then we can't have Win95.
  211. //
  212. CColonRegion = SpPtValidSystemPartition();
  213. if(!CColonRegion) {
  214. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: no C:, no Win95!\n"));
  215. return(FALSE);
  216. }
  217. //
  218. // Check the filesystem. If not FAT, then we don't have Win95.
  219. //
  220. if(CColonRegion->Filesystem != FilesystemFat) {
  221. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: C: is not FAT, no Win95!\n"));
  222. return(FALSE);
  223. }
  224. //
  225. // Check to see if there is enough free space, etc on C:.
  226. // If not, don't call attention to the migrate option, because
  227. // it won't work.
  228. //
  229. if(!SpPtValidateCColonFormat(WinntSif,NULL,CColonRegion,TRUE,NULL,NULL)) {
  230. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: C: not acceptable, no Win95!\n"));
  231. return(FALSE);
  232. }
  233. //
  234. // If msdos.sys is not the Win95 flavor, we do not have Win95
  235. // on drive C.
  236. //
  237. if(!SpIsWin9xMsdosSys(CColonRegion, &Win9xPath) )
  238. return FALSE;
  239. SpMemFree(Win9xPath);
  240. //
  241. // By this time, we've found a FAT C drive, it has the Win95
  242. // version of msdos.sys, and it has a valid config.sys. We
  243. // now conclude that this drive has Win95 on it!
  244. //
  245. // If we were initiated from WINNT32, don't tell the user
  246. // about this option.
  247. //
  248. //
  249. // We don't tell the user even if they ran 16-bit
  250. // WINNT. The only time this will run is if the user throws
  251. // in a boot floppy.
  252. //
  253. if (!WinntSetup)
  254. SpTellUserAboutMigrationOption(); // may not return!
  255. return TRUE;
  256. }
  257. VOID
  258. SpTellUserAboutMigrationOption ()
  259. {
  260. ULONG ValidKeys[3] = { KEY_F3,ASCI_CR,0 };
  261. ULONG Mnemonics[2] = { MnemonicContinueSetup,0 };
  262. while(1) {
  263. SpDisplayScreen(SP_SCRN_WIN95_MIGRATION,
  264. 3,
  265. HEADER_HEIGHT+1,
  266. );
  267. SpDisplayStatusOptions(
  268. DEFAULT_STATUS_ATTRIBUTE,
  269. SP_STAT_ENTER_EQUALS_CONTINUE,
  270. SP_STAT_F3_EQUALS_EXIT,
  271. 0
  272. );
  273. switch(SpWaitValidKey(ValidKeys,NULL,Mnemonics)) {
  274. case KEY_F3:
  275. SpConfirmExit();
  276. break;
  277. default:
  278. //
  279. // must be Enter=continue
  280. //
  281. return;
  282. }
  283. }
  284. return;
  285. }
  286. #endif
  287. BOOLEAN
  288. SpIsWin4Dir(
  289. IN PDISK_REGION Region,
  290. IN PWSTR PathComponent
  291. )
  292. /*++
  293. Routine Description:
  294. To find out if the directory indicated on the region contains a
  295. Microsoft Windows 95 (or later) installation. We do this by looking
  296. for a set of files in the SYSTEM subdirectory that don't exist under
  297. Win3.x, and under NT are located in the SYSTEM32 subdirectory.
  298. Arguments:
  299. Region - supplies pointer to disk region descriptor for region
  300. containing the directory to be checked.
  301. PathComponent - supplies a component of the dos path to search
  302. on the region. This is assumes to be in the form x:\dir.
  303. If it is not in this form, this routine will fail.
  304. Return Value:
  305. TRUE if this path contains a Microsoft Windows 4.x installation.
  306. FALSE otherwise.
  307. --*/
  308. {
  309. PWSTR files[] = { L"SHELL32.DLL", L"USER32.DLL", L"KERNEL32.DLL", L"GDI32.DLL" };
  310. PWCHAR OpenPath;
  311. BOOLEAN rc;
  312. //
  313. // Assume failure.
  314. //
  315. rc = FALSE;
  316. //
  317. // If the partition is not FAT, then ignore it.
  318. //
  319. if(Region->PartitionedSpace &&
  320. ((Region->Filesystem == FilesystemFat) || (Region->Filesystem == FilesystemFat32))) {
  321. OpenPath = SpMemAlloc((512 + wcslen(PathComponent) + ARRAYSIZE(L"SYSTEM")) * sizeof(WCHAR));
  322. //
  323. // Form the name of the partition.
  324. //
  325. SpNtNameFromRegion(Region,OpenPath,512*sizeof(WCHAR),PartitionOrdinalCurrent);
  326. //
  327. // Slap on the directory part of the path component.
  328. //
  329. SpConcatenatePaths(
  330. OpenPath,
  331. PathComponent + (SpExtractDriveLetter(PathComponent) ? 2 : 0)
  332. );
  333. //
  334. // Append the SYSTEM subdirectory to the path.
  335. //
  336. SpConcatenatePaths(OpenPath, L"SYSTEM");
  337. //
  338. // Determine whether all the required files are present.
  339. //
  340. rc = SpNFilesExist(OpenPath,files,ELEMENT_COUNT(files),FALSE);
  341. SpMemFree(OpenPath);
  342. }
  343. return(rc);
  344. }
  345. // needed for Win3.1 detection
  346. BOOLEAN
  347. SpIsWin9xMsdosSys(
  348. IN PDISK_REGION Region,
  349. OUT PSTR* Win9xPath
  350. )
  351. {
  352. WCHAR OpenPath[512];
  353. HANDLE FileHandle,SectionHandle;
  354. ULONG FileSize;
  355. PVOID ViewBase;
  356. PUCHAR pFile,pFileEnd,pLineEnd;
  357. ULONG i;
  358. NTSTATUS Status;
  359. ULONG LineLen,KeyLen;
  360. PCHAR Keyword = "[Paths]";
  361. PSTR p;
  362. ULONG cbText;
  363. //
  364. // Form name of config.sys.
  365. //
  366. SpNtNameFromRegion(Region,
  367. OpenPath,
  368. sizeof(OpenPath) - sizeof(L"msdos.sys"),
  369. PartitionOrdinalCurrent);
  370. SpConcatenatePaths(OpenPath,L"msdos.sys");
  371. //
  372. // Open and map the file.
  373. //
  374. FileHandle = 0;
  375. Status = SpOpenAndMapFile(
  376. OpenPath,
  377. &FileHandle,
  378. &SectionHandle,
  379. &ViewBase,
  380. &FileSize,
  381. FALSE
  382. );
  383. if(!NT_SUCCESS(Status)) {
  384. return(FALSE);
  385. }
  386. pFile = ViewBase;
  387. pFileEnd = pFile + FileSize;
  388. //
  389. // This code must guard access to the msdos.sys buffer because the
  390. // buffer is memory mapped (an i/o error would raise an exception).
  391. // This code could be structured better, as it now works by returning
  392. // from the try body -- but performance isn't an issue so this is acceptable
  393. // because it is so darned convenient.
  394. //
  395. __try {
  396. KeyLen = strlen(Keyword);
  397. //
  398. // Search for the [Paths] section
  399. //
  400. while (pFile < pFileEnd) {
  401. if (!_strnicmp(pFile, Keyword, KeyLen)) {
  402. break;
  403. }
  404. pFile++;
  405. }
  406. //
  407. // did we find the section
  408. //
  409. if (pFile >= pFileEnd) {
  410. return FALSE;
  411. }
  412. //
  413. // parse the [Paths] section
  414. //
  415. pFile += KeyLen;
  416. while(1) {
  417. //
  418. // Skip whitespace. If at end of file, then this is not a Win9x msdos.sys.
  419. //
  420. while((pFile < pFileEnd) && strchr(" \r\n\t",*pFile)) {
  421. pFile++;
  422. }
  423. if(pFile == pFileEnd) {
  424. return(FALSE);
  425. }
  426. //
  427. // Find the end of the current line.
  428. //
  429. pLineEnd = pFile;
  430. while((pLineEnd < pFileEnd) && !strchr("\r\n",*pLineEnd)) {
  431. pLineEnd++;
  432. }
  433. LineLen = pLineEnd - pFile;
  434. Keyword = "WinDir";
  435. KeyLen = strlen( Keyword );
  436. if( _strnicmp(pFile,Keyword,KeyLen) ) {
  437. pFile = pLineEnd;
  438. continue;
  439. }
  440. pFile += KeyLen;
  441. while((pFile < pFileEnd) && strchr(" =\r\n\t",*pFile)) {
  442. pFile++;
  443. }
  444. if(pFile == pFileEnd) {
  445. return(FALSE);
  446. }
  447. KeyLen = (ULONG)(pLineEnd - pFile);
  448. p = SpMemAlloc( KeyLen + 1 );
  449. for( i = 0; i < KeyLen; i++ ) {
  450. *(p + i) = *(pFile + i );
  451. }
  452. *(p + i ) = '\0';
  453. *Win9xPath = p;
  454. return(TRUE);
  455. }
  456. }
  457. __finally {
  458. SpUnmapFile(SectionHandle,ViewBase);
  459. ZwClose(FileHandle);
  460. }
  461. }
  462. /*++
  463. Routine Description:
  464. SpOpenWin9xDat file is a wrapper routine for opening one of the unicode DAT
  465. files used for certain win9x file lists.
  466. Arguments:
  467. DatFile - The name of the Dat file to enum.
  468. WinntSif - A pointer to a valid SIF handle object. This is used to
  469. retrieve information on the location of the DAT file named
  470. above.
  471. Return Value:
  472. A valid handle if the file was successfully opened, INVALID_HANDLE_VALUE
  473. otherwise.
  474. --*/
  475. HANDLE SpOpenWin9xDatFile (
  476. IN PCWSTR DatFile,
  477. IN PVOID WinntSif
  478. )
  479. {
  480. HANDLE rFile;
  481. NTSTATUS status;
  482. UNICODE_STRING datFileU;
  483. OBJECT_ATTRIBUTES oa;
  484. IO_STATUS_BLOCK ioStatusBlock;
  485. PDISK_REGION win9xTempRegion;
  486. PWSTR win9xTempDir;
  487. WCHAR ntName[ACTUAL_MAX_PATH];
  488. if (DatFile[0] && DatFile[1] == L':') {
  489. //
  490. // Convert a DOS path into an NT path
  491. //
  492. if (!SpNtNameFromDosPath (
  493. DatFile,
  494. ntName,
  495. sizeof (ntName),
  496. PartitionOrdinalCurrent
  497. )) {
  498. KdPrintEx((
  499. DPFLTR_SETUP_ID,
  500. DPFLTR_ERROR_LEVEL,
  501. "SETUP: Cannot convert path %ws to an NT path\n",
  502. DatFile
  503. ));
  504. return INVALID_HANDLE_VALUE;
  505. }
  506. } else {
  507. //
  508. // The location of the win9x.sif file is in the Win9xSif key of the [data] section.
  509. //
  510. win9xTempDir = SpGetSectionKeyIndex(WinntSif,SIF_DATA,WINNT_D_WIN9XTEMPDIR_W,0);
  511. if (!win9xTempDir) {
  512. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Could not get Win9x temp dir..\n"));
  513. return INVALID_HANDLE_VALUE;
  514. }
  515. //
  516. // Get the region from the dos name..
  517. //
  518. win9xTempRegion = SpRegionFromDosName (win9xTempDir);
  519. if (!win9xTempRegion) {
  520. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpRegionFromDosName failed for %ws\n", win9xTempDir));
  521. return INVALID_HANDLE_VALUE;
  522. }
  523. //
  524. // Get the NT name from the disk region..
  525. //
  526. SpNtNameFromRegion(
  527. win9xTempRegion,
  528. (PWSTR)TemporaryBuffer,
  529. sizeof(TemporaryBuffer) - (wcslen(&win9xTempDir[2]) - 2/*'\\'*/ - wcslen(DatFile)) * sizeof(WCHAR),
  530. PartitionOrdinalCurrent
  531. );
  532. //
  533. // build the complete NT path to the win9x sif file..
  534. //
  535. SpConcatenatePaths((PWSTR) TemporaryBuffer, &win9xTempDir[2]);
  536. SpConcatenatePaths((PWSTR) TemporaryBuffer, DatFile);
  537. wcsncpy ( ntName,
  538. TemporaryBuffer,
  539. MAX_COPY_SIZE(ntName));
  540. ntName[MAX_COPY_SIZE(ntName)] = L'\0';
  541. }
  542. //
  543. // Open the file.
  544. //
  545. RtlInitUnicodeString(&datFileU,ntName);
  546. InitializeObjectAttributes(&oa,&datFileU,OBJ_CASE_INSENSITIVE,NULL,NULL);
  547. status = ZwCreateFile(
  548. &rFile,
  549. FILE_GENERIC_READ,
  550. &oa,
  551. &ioStatusBlock,
  552. NULL,
  553. FILE_ATTRIBUTE_NORMAL,
  554. FILE_SHARE_READ,
  555. FILE_OPEN,
  556. 0,
  557. NULL,
  558. 0
  559. );
  560. if(!NT_SUCCESS(status)) {
  561. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpOpenWin9xDatFile: unable to open file %ws (%lx)\n",DatFile,status));
  562. return INVALID_HANDLE_VALUE;
  563. }
  564. return rFile;
  565. }
  566. typedef struct {
  567. HANDLE FileHandle;
  568. PWSTR EndOfFile;
  569. HANDLE FileSection;
  570. PWSTR NextLine;
  571. PWSTR UnMapAddress;
  572. WCHAR CurLine[MAX_PATH];
  573. } WIN9XDATFILEENUM, * PWIN9XDATFILEENUM;
  574. /*++
  575. Routine Description:
  576. SpAbortWin9xFileEnum aborts the current win9x DAT file enumeration.
  577. Arguments:
  578. None.
  579. Return Value:
  580. --*/
  581. VOID
  582. SpAbortWin9xFileEnum (
  583. IN PWIN9XDATFILEENUM Enum
  584. )
  585. {
  586. SpUnmapFile(Enum -> FileSection,Enum -> UnMapAddress);
  587. ZwClose(Enum -> FileHandle);
  588. }
  589. /*++
  590. Routine Description:
  591. SpEnumNextWin9xFile is fills in the enumeration structure with the next
  592. available data from the DAT file being enumerated.
  593. Arguments:
  594. Enum - A pointer to a valid enumeration structure for the file currently
  595. being enumerated.
  596. Return Value:
  597. TRUE if there was more data to enumerate, FALSE otherwise.
  598. --*/
  599. BOOL
  600. SpEnumNextWin9xFile (
  601. IN PWIN9XDATFILEENUM Enum
  602. )
  603. {
  604. PWSTR endOfLine;
  605. BOOL result = FALSE;
  606. PWSTR src;
  607. PWSTR dest;
  608. for (;;) {
  609. //
  610. // Does another line exist?
  611. //
  612. endOfLine = Enum->NextLine;
  613. if (endOfLine >= Enum->EndOfFile) {
  614. // no more data in file
  615. break;
  616. }
  617. //
  618. // Parse the next line
  619. //
  620. src = endOfLine;
  621. while (endOfLine < Enum->EndOfFile &&
  622. *endOfLine != L'\r' &&
  623. *endOfLine != L'\n'
  624. ) {
  625. endOfLine++;
  626. }
  627. // next line starts after \r\n, \r or \n
  628. Enum->NextLine = endOfLine;
  629. if (Enum->NextLine < Enum->EndOfFile && *Enum->NextLine == L'\r') {
  630. Enum->NextLine++;
  631. }
  632. if (Enum->NextLine < Enum->EndOfFile && *Enum->NextLine == L'\n') {
  633. Enum->NextLine++;
  634. }
  635. if ((endOfLine - src) > (MAX_PATH - 1)) {
  636. WCHAR chEnd = *endOfLine;
  637. *endOfLine = '\0';
  638. KdPrintEx ((
  639. DPFLTR_SETUP_ID,
  640. DPFLTR_ERROR_LEVEL,
  641. "SETUP: Ignoring a configuration file line that is too long - %ws\n",
  642. src
  643. ));
  644. *endOfLine = chEnd;
  645. continue;
  646. }
  647. //
  648. // Copy the line into the enum struct buffer
  649. //
  650. if (src == endOfLine) {
  651. // ignore blank lines
  652. continue;
  653. }
  654. dest = Enum->CurLine;
  655. do {
  656. *dest++ = *src++;
  657. } while (src < endOfLine);
  658. *dest = 0;
  659. result = TRUE;
  660. break;
  661. }
  662. if (!result) {
  663. //
  664. // No more files to enum.
  665. //
  666. SpAbortWin9xFileEnum(Enum);
  667. return FALSE;
  668. }
  669. return result;
  670. }
  671. /*++
  672. Routine Description:
  673. SpEnumFirstWin9xFile is responsible for initializing the enumeration of a
  674. win9x data file. The function then calls EnumNextWin9xFile to fill in the
  675. rest of the necessary fields of the enumeration structure.
  676. Arguments:
  677. Enum - A pointer to a WIN9XDATFILEENUM structure. It is initialized by
  678. this function.
  679. WinntSif - A pointer to a valid Sif File. It is used to retrieve
  680. information about the location of the dat file to be enumerated.
  681. DatFile - The name of the DAT file to be enumerated.
  682. Return Value:
  683. TRUE if the enumeration was succesffuly initalized and there was something
  684. to enumerate, FALSE otherwise.
  685. --*/
  686. BOOL
  687. SpEnumFirstWin9xFile (
  688. IN PWIN9XDATFILEENUM Enum,
  689. IN PVOID WinntSif,
  690. IN PCWSTR DatFile
  691. )
  692. {
  693. NTSTATUS status;
  694. UINT fileSize;
  695. //
  696. // Open the dat file..
  697. //
  698. Enum -> FileHandle = SpOpenWin9xDatFile (DatFile, WinntSif);
  699. if (Enum -> FileHandle == INVALID_HANDLE_VALUE) {
  700. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error opening %ws data file..\n",DatFile));
  701. return FALSE;
  702. }
  703. //
  704. // Get the file size.
  705. //
  706. status = SpGetFileSize (Enum->FileHandle, &fileSize);
  707. if(!NT_SUCCESS(status)) {
  708. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error getting file size.\n"));
  709. ZwClose (Enum -> FileHandle);
  710. return FALSE;
  711. }
  712. //
  713. // Map the file.
  714. //
  715. status = SpMapEntireFile(
  716. Enum -> FileHandle,
  717. &(Enum -> FileSection),
  718. &(Enum -> NextLine),
  719. TRUE
  720. );
  721. if(!NT_SUCCESS(status)) {
  722. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error attempting to map file.\n"));
  723. ZwClose (Enum -> FileHandle);
  724. return FALSE;
  725. }
  726. Enum->EndOfFile = (PWSTR) ((PBYTE) Enum->NextLine + fileSize);
  727. Enum->UnMapAddress = Enum->NextLine;
  728. //
  729. // Pass Unicode Signature..
  730. //
  731. Enum -> NextLine += 1;
  732. //
  733. // Call EnumNext.
  734. //
  735. return SpEnumNextWin9xFile (Enum);
  736. }
  737. BOOLEAN
  738. SppWriteToFile (
  739. IN HANDLE FileHandle,
  740. IN PVOID Data,
  741. IN UINT DataSize,
  742. IN OUT PLARGE_INTEGER WritePos OPTIONAL
  743. )
  744. {
  745. NTSTATUS status;
  746. IO_STATUS_BLOCK ioStatusBlock;
  747. if (!DataSize) {
  748. return TRUE;
  749. }
  750. status = ZwWriteFile (
  751. FileHandle,
  752. NULL,
  753. NULL,
  754. NULL,
  755. &ioStatusBlock,
  756. Data,
  757. DataSize,
  758. WritePos,
  759. NULL
  760. );
  761. if (!NT_SUCCESS (status)) {
  762. KdPrintEx ((
  763. DPFLTR_SETUP_ID,
  764. DPFLTR_ERROR_LEVEL,
  765. "SETUP: SppWriteToFile failed with status %x\n",
  766. status
  767. ));
  768. } else if (WritePos) {
  769. ASSERT (ioStatusBlock.Information == DataSize);
  770. WritePos->QuadPart += (LONGLONG) DataSize;
  771. }
  772. return NT_SUCCESS (status);
  773. }
  774. BOOLEAN
  775. SppReadFromFile (
  776. IN HANDLE FileHandle,
  777. OUT PVOID Data,
  778. IN UINT DataBufferSize,
  779. OUT PINT BytesRead,
  780. IN OUT PLARGE_INTEGER ReadPos OPTIONAL
  781. )
  782. {
  783. NTSTATUS status;
  784. IO_STATUS_BLOCK ioStatusBlock;
  785. ioStatusBlock.Information = 0;
  786. status = ZwReadFile (
  787. FileHandle,
  788. NULL,
  789. NULL,
  790. NULL,
  791. &ioStatusBlock,
  792. Data,
  793. DataBufferSize,
  794. ReadPos,
  795. NULL
  796. );
  797. if (status != STATUS_END_OF_FILE && !NT_SUCCESS (status)) {
  798. KdPrintEx ((
  799. DPFLTR_SETUP_ID,
  800. DPFLTR_ERROR_LEVEL,
  801. "SETUP: SppReadFromFile failed with status %x\n",
  802. status
  803. ));
  804. return FALSE;
  805. }
  806. *BytesRead = ioStatusBlock.Information;
  807. if (ReadPos) {
  808. ReadPos->QuadPart += (LONGLONG) ioStatusBlock.Information;
  809. }
  810. return TRUE;
  811. }
  812. BOOLEAN
  813. SppCloseBackupImage (
  814. IN BACKUP_IMAGE_HANDLE BackupImageHandle,
  815. IN PBACKUP_IMAGE_HEADER ImageHeader, OPTIONAL
  816. IN PWSTR JournalFile OPTIONAL
  817. )
  818. {
  819. BOOLEAN result = FALSE;
  820. NTSTATUS status;
  821. IO_STATUS_BLOCK ioStatusBlock;
  822. OBJECT_ATTRIBUTES obja = { 0 };
  823. UNICODE_STRING unicodeString = { 0 };
  824. HANDLE journalHandle = NULL;
  825. JOURNALSTATUS journalStatus;
  826. if (BackupImageHandle != INVALID_HANDLE_VALUE
  827. && BackupImageHandle != NULL
  828. ) {
  829. PVOID CabHandle = BackupImageHandle->CabHandle;
  830. if (CabHandle != NULL && CabHandle != INVALID_HANDLE_VALUE
  831. ) {
  832. BackupImageHandle->CabHandle = NULL;
  833. ASSERT(BackupImageHandle->CloseCabinet != NULL);
  834. result = BackupImageHandle->CloseCabinet(CabHandle) ? TRUE : FALSE; // ?: to convert BOOL<->BOOLEAN
  835. }
  836. }
  837. if (result) {
  838. //
  839. // If JournalFile is specified, mark it as complete.
  840. //
  841. if (JournalFile) {
  842. SpDeleteFile (JournalFile, NULL, NULL);
  843. INIT_OBJA (&obja, &unicodeString, JournalFile);
  844. status = ZwCreateFile (
  845. &journalHandle,
  846. SYNCHRONIZE | FILE_GENERIC_WRITE,
  847. &obja,
  848. &ioStatusBlock,
  849. NULL,
  850. FILE_ATTRIBUTE_NORMAL,
  851. 0,
  852. FILE_CREATE,
  853. FILE_SYNCHRONOUS_IO_NONALERT|FILE_WRITE_THROUGH,
  854. NULL,
  855. 0
  856. );
  857. if (NT_SUCCESS(status)) {
  858. journalStatus = BACKUP_COMPLETE;
  859. SppWriteToFile (journalHandle, &journalStatus, sizeof (journalStatus), NULL);
  860. ZwClose (journalHandle);
  861. } else {
  862. KdPrintEx ((
  863. DPFLTR_SETUP_ID,
  864. DPFLTR_ERROR_LEVEL,
  865. "SETUP: Unable to create %ws\n",
  866. JournalFile
  867. ));
  868. return FALSE;
  869. }
  870. }
  871. }
  872. return result;
  873. }
  874. VOID
  875. SpAppendToBaseName(
  876. PWSTR String,
  877. PCWSTR StringToAppend
  878. )
  879. /*++
  880. String is assumed to have enough room already.
  881. --*/
  882. {
  883. //
  884. // Caller ensure safety, must be at least
  885. // ARRAYSIZE(String) > wcslen(String) + wcslen(StringToAppend)
  886. //
  887. const PWSTR Dot = wcsrchr(String, '.');
  888. if (Dot != NULL) {
  889. const SIZE_T StringToAppendLen = wcslen(StringToAppend);
  890. RtlMoveMemory(Dot + 1 + StringToAppendLen, Dot + 1, (wcslen(Dot + 1) + 1) * sizeof(WCHAR));
  891. RtlMoveMemory(Dot, StringToAppend, StringToAppendLen * sizeof(WCHAR));
  892. *(Dot + StringToAppendLen) = '.';
  893. } else {
  894. wcscat(String, StringToAppend);
  895. }
  896. }
  897. BACKUP_IMAGE_HANDLE
  898. SppOpenBackupImage (
  899. IN BOOLEAN Create,
  900. OUT PBACKUP_IMAGE_HEADER Header,
  901. OUT PLARGE_INTEGER ImagePos, OPTIONAL
  902. OUT PWSTR JournalFile, OPTIONAL
  903. IN TCOMP CompressionType,
  904. OUT BOOLEAN *InvalidHandleMeansFail OPTIONAL
  905. )
  906. {
  907. PVOID CabHandle;
  908. NTSTATUS status = STATUS_SUCCESS;
  909. IO_STATUS_BLOCK ioStatusBlock;
  910. OBJECT_ATTRIBUTES obja = { 0 };
  911. UNICODE_STRING unicodeString = { 0 };
  912. HANDLE journalHandle = NULL;
  913. JOURNALSTATUS journalStatus;
  914. PWSTR p = NULL;
  915. BOOL success = FALSE;
  916. BACKUP_IMAGE_HANDLE imageHandle = INVALID_HANDLE_VALUE;
  917. BOOL Success = FALSE;
  918. PWSTR subDir = NULL;
  919. PDISK_REGION region = NULL;
  920. PWSTR backupDir = NULL;
  921. PWSTR ntRoot = NULL;
  922. PWSTR backupFileOb = NULL;
  923. PWSTR backupJournalOb = NULL;
  924. UINT dontCare;
  925. PWSTR backupLeafFile = NULL;
  926. BOOL backupDirIsRoot = FALSE;
  927. PWSTR backupImage = NULL;
  928. WCHAR CompressionTypeString[sizeof(CompressionType) * 8];
  929. if (InvalidHandleMeansFail) {
  930. *InvalidHandleMeansFail = TRUE;
  931. }
  932. //
  933. // Alloc buffers
  934. //
  935. ntRoot = SpMemAlloc (ACTUAL_MAX_PATH * sizeof (WCHAR));
  936. backupDir = SpMemAlloc (ACTUAL_MAX_PATH * sizeof (WCHAR));
  937. backupFileOb = SpMemAlloc (ACTUAL_MAX_PATH * sizeof (WCHAR));
  938. backupJournalOb = SpMemAlloc (ACTUAL_MAX_PATH * sizeof (WCHAR));
  939. backupImage = SpMemAlloc (ACTUAL_MAX_PATH * sizeof (WCHAR));
  940. if (!ntRoot
  941. || !backupDir
  942. || !backupFileOb
  943. || !backupJournalOb
  944. || !backupImage
  945. ) {
  946. goto cleanup;
  947. }
  948. //
  949. // Obtain the backup image path from winnt.sif. The return ptr points
  950. // to the SIF parse data structures.
  951. //
  952. ASSERT (WinntSifHandle);
  953. p = SpGetSectionKeyIndex (
  954. WinntSifHandle,
  955. WINNT_DATA_W,
  956. WINNT_D_BACKUP_IMAGE_W,
  957. 0
  958. );
  959. if (!p) {
  960. if (Create) {
  961. KdPrintEx((
  962. DPFLTR_SETUP_ID,
  963. DPFLTR_INFO_LEVEL,
  964. "SETUP: Backup image is not specified; not creating a backup\n"
  965. ));
  966. } else {
  967. KdPrintEx((
  968. DPFLTR_SETUP_ID,
  969. DPFLTR_ERROR_LEVEL,
  970. "SETUP: Backup image is not specified; cannot perform a restore\n"
  971. ));
  972. }
  973. goto cleanup;
  974. }
  975. SpFormatStringW(CompressionTypeString, RTL_NUMBER_OF(CompressionTypeString), L"%d", (int)CompressionType);
  976. if((wcslen(p) + wcslen(CompressionTypeString)) >= ACTUAL_MAX_PATH){
  977. KdPrintEx((
  978. DPFLTR_SETUP_ID,
  979. DPFLTR_ERROR_LEVEL,
  980. "SETUP: Backup image path length is exceed ACTUAL_MAX_PATH\n"
  981. ));
  982. goto cleanup;
  983. }
  984. wcscpy(backupImage, p);
  985. #if TRY_ALL_COMPRESSION_ALGORITHMS
  986. SpAppendToBaseName(backupImage, CompressionTypeString);
  987. #endif
  988. //
  989. // The backup spec is a DOS path. Convert it into an NT object path.
  990. //
  991. if (!SpNtNameFromDosPath (
  992. backupImage,
  993. backupFileOb,
  994. ACTUAL_MAX_PATH * sizeof (WCHAR),
  995. PartitionOrdinalCurrent
  996. )) {
  997. KdPrintEx((
  998. DPFLTR_SETUP_ID,
  999. DPFLTR_ERROR_LEVEL,
  1000. "SETUP: Cannot convert path %ws to an NT path\n",
  1001. backupImage
  1002. ));
  1003. goto cleanup;
  1004. }
  1005. //
  1006. // Check if backup.$$$ exists
  1007. //
  1008. wcscpy (backupJournalOb, backupFileOb);
  1009. p = wcsrchr (backupJournalOb, L'\\');
  1010. if (p) {
  1011. p = wcsrchr (p, L'.');
  1012. }
  1013. if (!p) {
  1014. KdPrintEx ((
  1015. DPFLTR_SETUP_ID,
  1016. DPFLTR_ERROR_LEVEL,
  1017. "SETUP: "__FUNCTION__": Invalid backup path spec: %ws\n",
  1018. backupFileOb
  1019. ));
  1020. goto cleanup;
  1021. }
  1022. wcscpy (p + 1, L"$$$");
  1023. if (JournalFile) {
  1024. wcscpy (JournalFile, backupJournalOb);
  1025. }
  1026. if(Create){
  1027. SpDeleteFile (backupFileOb, NULL, NULL);
  1028. SpDeleteFile (backupJournalOb, NULL, NULL);
  1029. }
  1030. INIT_OBJA (&obja, &unicodeString, backupJournalOb);
  1031. status = ZwCreateFile (
  1032. &journalHandle,
  1033. SYNCHRONIZE | FILE_GENERIC_READ,
  1034. &obja,
  1035. &ioStatusBlock,
  1036. NULL,
  1037. FILE_ATTRIBUTE_NORMAL,
  1038. 0,
  1039. FILE_OPEN,
  1040. FILE_SYNCHRONOUS_IO_NONALERT,
  1041. NULL,
  1042. 0
  1043. );
  1044. if (NT_SUCCESS (status)) {
  1045. if (!SppReadFromFile (
  1046. journalHandle,
  1047. &journalStatus,
  1048. sizeof (journalStatus),
  1049. &dontCare,
  1050. NULL
  1051. )) {
  1052. journalStatus = BACKUP_DOESNT_EXIST;
  1053. KdPrintEx((
  1054. DPFLTR_SETUP_ID,
  1055. DPFLTR_ERROR_LEVEL,
  1056. "SETUP: Journal exist but can't be read\n"
  1057. ));
  1058. }
  1059. ZwClose (journalHandle);
  1060. } else {
  1061. journalStatus = BACKUP_DOESNT_EXIST;
  1062. KdPrintEx((
  1063. DPFLTR_SETUP_ID,
  1064. DPFLTR_ERROR_LEVEL,
  1065. "BUGBUG: Journal doesn't exist\n"
  1066. ));
  1067. }
  1068. if (((journalStatus == BACKUP_COMPLETE) && Create) ||
  1069. (journalStatus == BACKUP_SKIPPED_BY_USER)
  1070. ) {
  1071. KdPrintEx((
  1072. DPFLTR_SETUP_ID,
  1073. DPFLTR_ERROR_LEVEL,
  1074. "SETUP: Backup is done or is disabled\n"
  1075. ));
  1076. if (InvalidHandleMeansFail) {
  1077. *InvalidHandleMeansFail = FALSE;
  1078. }
  1079. goto cleanup;
  1080. }
  1081. //
  1082. // form seperate strings for the directory and leaf
  1083. //
  1084. wcscpy (backupDir, backupFileOb);
  1085. p = wcsrchr (backupDir, L'\\');
  1086. if (p != NULL && p > wcschr (backupDir, L'\\')) {
  1087. *p = 0;
  1088. backupLeafFile = p + 1;
  1089. backupDirIsRoot = FALSE;
  1090. } else if (backupDir[0] == '\\') {
  1091. ASSERTMSG("This is very strange, we got a path in the NT root.", FALSE);
  1092. backupDir[1] = 0;
  1093. backupLeafFile = &backupDir[2];
  1094. backupDirIsRoot = TRUE;
  1095. }
  1096. //
  1097. // Open the source file
  1098. //
  1099. if (Create) {
  1100. //
  1101. // If not the root directory, create the directory now
  1102. //
  1103. if (!backupDirIsRoot) {
  1104. region = SppRegionFromFullNtName (backupDir, PartitionOrdinalCurrent, &subDir);
  1105. if (!region) {
  1106. KdPrintEx ((
  1107. DPFLTR_SETUP_ID,
  1108. DPFLTR_ERROR_LEVEL,
  1109. "SETUP: "__FUNCTION__" - Can't get region for backup image\n"
  1110. ));
  1111. } else {
  1112. SpNtNameFromRegion (region, ntRoot, ACTUAL_MAX_PATH * sizeof (WCHAR), PartitionOrdinalCurrent);
  1113. SpCreateDirectory (ntRoot, NULL, subDir, 0, 0);
  1114. }
  1115. }
  1116. //
  1117. // If journal pre-existed, then delete the incomplete backup image and
  1118. // journal
  1119. //
  1120. if (journalStatus == BACKUP_IN_PROGRESS) {
  1121. // error ignored for now -- will be caught below
  1122. SpDeleteFile (backupFileOb, NULL, NULL);
  1123. SpDeleteFile (backupJournalOb, NULL, NULL);
  1124. KdPrintEx((
  1125. DPFLTR_SETUP_ID,
  1126. DPFLTR_ERROR_LEVEL,
  1127. "SETUP: Restarting backup process\n"
  1128. ));
  1129. } else {
  1130. KdPrintEx((
  1131. DPFLTR_SETUP_ID,
  1132. DPFLTR_ERROR_LEVEL,
  1133. "BUGBUG: Backup doesn't exist\n"
  1134. ));
  1135. ASSERT (journalStatus == BACKUP_DOESNT_EXIST);
  1136. }
  1137. //
  1138. // Create a new journal file
  1139. //
  1140. INIT_OBJA (&obja, &unicodeString, backupJournalOb);
  1141. status = ZwCreateFile (
  1142. &journalHandle,
  1143. SYNCHRONIZE | FILE_GENERIC_WRITE,
  1144. &obja,
  1145. &ioStatusBlock,
  1146. NULL,
  1147. FILE_ATTRIBUTE_NORMAL,
  1148. 0,
  1149. FILE_CREATE,
  1150. FILE_SYNCHRONOUS_IO_NONALERT|FILE_WRITE_THROUGH,
  1151. NULL,
  1152. 0
  1153. );
  1154. if (NT_SUCCESS(status)) {
  1155. journalStatus = BACKUP_IN_PROGRESS;
  1156. SppWriteToFile (journalHandle, &journalStatus, sizeof (journalStatus), NULL);
  1157. ZwClose (journalHandle);
  1158. } else {
  1159. KdPrintEx ((
  1160. DPFLTR_SETUP_ID,
  1161. DPFLTR_ERROR_LEVEL,
  1162. "SETUP: Unable to create %ws\n",
  1163. backupJournalOb
  1164. ));
  1165. goto cleanup;
  1166. }
  1167. } else {
  1168. //
  1169. // If open attempt and journal exists, then fail
  1170. //
  1171. if (journalStatus != BACKUP_COMPLETE) {
  1172. KdPrintEx ((
  1173. DPFLTR_SETUP_ID,
  1174. DPFLTR_ERROR_LEVEL,
  1175. "SETUP: Can't restore incomplete backup image %ws\n",
  1176. backupFileOb
  1177. ));
  1178. goto cleanup;
  1179. }
  1180. }
  1181. //
  1182. // Create/Open backup image
  1183. //
  1184. imageHandle = (BACKUP_IMAGE_HANDLE)SpMemAlloc(sizeof(*imageHandle));
  1185. if (imageHandle == NULL) {
  1186. goto cleanup;
  1187. }
  1188. RtlZeroMemory(imageHandle, sizeof(*imageHandle));
  1189. if (Create) {
  1190. CabHandle = SpCabCreateCabinetW(backupDir, backupLeafFile, NULL, 0);
  1191. imageHandle->CloseCabinet = SpCabFlushAndCloseCabinet;
  1192. } else {
  1193. CabHandle = SpCabOpenCabinetW(backupFileOb);
  1194. imageHandle->CloseCabinet = SpCabCloseCabinet;
  1195. }
  1196. if (CabHandle == NULL || CabHandle == INVALID_HANDLE_VALUE) {
  1197. goto cleanup;
  1198. }
  1199. imageHandle->CabHandle = CabHandle;
  1200. Success = TRUE;
  1201. cleanup:
  1202. if (!Success) {
  1203. SppCloseBackupImage (imageHandle, NULL, NULL);
  1204. imageHandle = INVALID_HANDLE_VALUE;
  1205. }
  1206. SpMemFree (ntRoot);
  1207. SpMemFree (backupDir);
  1208. SpMemFree (backupFileOb);
  1209. SpMemFree (backupJournalOb);
  1210. return imageHandle;
  1211. }
  1212. #define BLOCKSIZE (65536*4)
  1213. BOOLEAN
  1214. SppPutFileInBackupImage (
  1215. IN BACKUP_IMAGE_HANDLE ImageHandle,
  1216. IN OUT PLARGE_INTEGER ImagePos,
  1217. IN OUT PBACKUP_IMAGE_HEADER ImageHeader,
  1218. IN PWSTR DosPath
  1219. )
  1220. {
  1221. PWSTR ntPath;
  1222. BACKUP_FILE_HEADER fileHeader;
  1223. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  1224. NTSTATUS status = STATUS_UNSUCCESSFUL;
  1225. IO_STATUS_BLOCK ioStatusBlock;
  1226. OBJECT_ATTRIBUTES obja;
  1227. UNICODE_STRING unicodeString;
  1228. FILE_STANDARD_INFORMATION stdInfo;
  1229. BOOLEAN fail = TRUE;
  1230. BOOLEAN truncate = FALSE;
  1231. BOOLEAN returnValue = FALSE;
  1232. PBYTE block = NULL;
  1233. INT bytesRead;
  1234. FILE_END_OF_FILE_INFORMATION eofInfo;
  1235. PWSTR fileName;
  1236. ntPath = SpMemAlloc (ACTUAL_MAX_PATH * sizeof (WCHAR));
  1237. if (!ntPath) {
  1238. KdPrintEx((
  1239. DPFLTR_SETUP_ID,
  1240. DPFLTR_ERROR_LEVEL,
  1241. "SETUP: Can't allocate buffer\n"
  1242. ));
  1243. goto cleanup;
  1244. }
  1245. eofInfo.EndOfFile.QuadPart = ImagePos->QuadPart;
  1246. KdPrintEx((
  1247. DPFLTR_SETUP_ID,
  1248. DPFLTR_TRACE_LEVEL,
  1249. "SETUP: Backing up %ws\n",
  1250. DosPath
  1251. ));
  1252. fileName = wcsrchr (DosPath, L'\\');
  1253. if (!fileName) {
  1254. fileName = DosPath;
  1255. } else {
  1256. fileName++;
  1257. }
  1258. SpDisplayStatusText (SP_STAT_BACKING_UP_WIN9X_FILE, DEFAULT_STATUS_ATTRIBUTE, fileName);
  1259. //
  1260. // Convert the backup file's DOS path into an NT path
  1261. //
  1262. if (!SpNtNameFromDosPath (
  1263. DosPath,
  1264. ntPath,
  1265. ACTUAL_MAX_PATH * sizeof (WCHAR),
  1266. PartitionOrdinalCurrent
  1267. )) {
  1268. KdPrintEx((
  1269. DPFLTR_SETUP_ID,
  1270. DPFLTR_ERROR_LEVEL,
  1271. "SETUP: Cannot convert path %ws to an NT path\n",
  1272. DosPath
  1273. ));
  1274. goto cleanup;
  1275. }
  1276. status = SpCabAddFileToCabinetW (ImageHandle->CabHandle, ntPath, DosPath);//ntPath
  1277. if (!NT_SUCCESS (status)) {
  1278. goto cleanup;
  1279. }
  1280. returnValue = TRUE;
  1281. cleanup:
  1282. if (!returnValue) {
  1283. //
  1284. // File could not be added to the image. Allow user to continue.
  1285. //
  1286. if (status != STATUS_OBJECT_NAME_NOT_FOUND &&
  1287. status != STATUS_OBJECT_NAME_INVALID &&
  1288. status != STATUS_OBJECT_PATH_INVALID &&
  1289. status != STATUS_OBJECT_PATH_NOT_FOUND &&
  1290. status != STATUS_FILE_IS_A_DIRECTORY
  1291. ) {
  1292. KdPrintEx((
  1293. DPFLTR_SETUP_ID,
  1294. DPFLTR_ERROR_LEVEL,
  1295. "SETUP: Can't add %ws to backup CAB (%08Xh)\n",
  1296. DosPath,
  1297. status
  1298. ));
  1299. if (SpNonCriticalErrorWithContinue (SP_SCRN_BACKUP_SAVE_FAILED, DosPath, (PWSTR) status)) {
  1300. returnValue = TRUE;
  1301. }
  1302. CLEAR_CLIENT_SCREEN();
  1303. } else {
  1304. //
  1305. // Ignore errors that can be caused by users altering the system
  1306. // while setup is running, or by bad migration dll info
  1307. //
  1308. returnValue = TRUE;
  1309. }
  1310. }
  1311. SpMemFree (ntPath);
  1312. return returnValue;
  1313. }
  1314. #if DBG
  1315. VOID
  1316. SpDbgPrintElapsedTime(
  1317. PCSTR Prefix,
  1318. CONST LARGE_INTEGER* ElapsedTime
  1319. )
  1320. {
  1321. TIME_FIELDS TimeFields;
  1322. RtlTimeToElapsedTimeFields((PLARGE_INTEGER)ElapsedTime, &TimeFields);
  1323. KdPrint(("%s: %d:%d.%d\n", Prefix, (int)TimeFields.Minute, (int)TimeFields.Second, (int)TimeFields.Milliseconds));
  1324. }
  1325. #endif
  1326. BOOLEAN
  1327. SpAddRollbackBootOption (
  1328. BOOLEAN DefaultBootOption
  1329. )
  1330. {
  1331. PWSTR data;
  1332. BOOLEAN result;
  1333. data = SpGetSectionKeyIndex (SifHandle, SIF_SETUPDATA, L"LoadIdentifierCancel", 0);
  1334. if (!data) {
  1335. SpFatalSifError (SifHandle, SIF_SETUPDATA, L"LoadIdentifierCancel",0,0);
  1336. }
  1337. result = SppCreateTextModeBootEntry (data, L"/rollback", DefaultBootOption);
  1338. return result;
  1339. }
  1340. BOOLEAN
  1341. SpBackUpWin9xFiles (
  1342. IN PVOID WinntSif,
  1343. IN TCOMP CompressionType
  1344. )
  1345. /*++
  1346. Routine Description:
  1347. SpBackUpWin9xFiles takes full DOS paths in the BACKUP.TXT file
  1348. and puts them in a temporary location specified in the WINNT.SIF file.
  1349. the format of this file is
  1350. backupfile1.ext
  1351. backupfile2.ext
  1352. ...
  1353. Arguments:
  1354. WinntSif: Handle to Winnt.Sif
  1355. Return Value:
  1356. TRUE if a backup image was made, FALSE otherwise.
  1357. --*/
  1358. {
  1359. WIN9XDATFILEENUM e;
  1360. BACKUP_IMAGE_HANDLE backupImage;
  1361. BACKUP_IMAGE_HEADER header;
  1362. LARGE_INTEGER imagePos;
  1363. PWSTR p;
  1364. BOOLEAN result = FALSE;
  1365. PWSTR journalFile = NULL;
  1366. PWSTR data;
  1367. IO_STATUS_BLOCK ioStatusBlock;
  1368. OBJECT_ATTRIBUTES obja;
  1369. UNICODE_STRING unicodeString;
  1370. HANDLE journalHandle;
  1371. JOURNALSTATUS journalStatus;
  1372. NTSTATUS status;
  1373. UINT currentFile;
  1374. UINT percentDone;
  1375. UINT fileCount;
  1376. PWSTR srcBootIni;
  1377. PWSTR backupBootIni;
  1378. BOOLEAN askForRetry = FALSE;
  1379. //
  1380. // Get the backup image path
  1381. //
  1382. p = SpGetSectionKeyIndex (
  1383. WinntSifHandle,
  1384. WINNT_DATA_W,
  1385. WINNT_D_BACKUP_LIST_W,
  1386. 0
  1387. );
  1388. if (!p) {
  1389. KdPrintEx((
  1390. DPFLTR_SETUP_ID,
  1391. DPFLTR_ERROR_LEVEL,
  1392. "SETUP: Backup file list is not specified; cannot perform a backup\n"
  1393. ));
  1394. goto cleanup;
  1395. }
  1396. journalFile = SpMemAlloc (MAX_PATH * sizeof (WCHAR));
  1397. if (!journalFile) {
  1398. KdPrintEx((
  1399. DPFLTR_SETUP_ID,
  1400. DPFLTR_ERROR_LEVEL,
  1401. "SETUP: Can't allocate journal buffer\n"
  1402. ));
  1403. goto cleanup;
  1404. }
  1405. //
  1406. // Open the backup image
  1407. //
  1408. backupImage = SppOpenBackupImage (
  1409. TRUE,
  1410. &header,
  1411. &imagePos,
  1412. journalFile,
  1413. CompressionType,
  1414. &askForRetry
  1415. );
  1416. if (backupImage == INVALID_HANDLE_VALUE) {
  1417. goto cleanup;
  1418. }
  1419. askForRetry = TRUE;
  1420. backupImage->CabHandle->CompressionType = CompressionType;
  1421. //
  1422. // Process all files listed in backup.txt
  1423. //
  1424. result = TRUE;
  1425. fileCount = 0;
  1426. if (SpEnumFirstWin9xFile (&e, WinntSif, p)) {
  1427. do {
  1428. fileCount++;
  1429. } while (SpEnumNextWin9xFile (&e));
  1430. }
  1431. SendSetupProgressEvent (BackupEvent, BackupStartEvent, &fileCount);
  1432. currentFile = 0;
  1433. if (SpEnumFirstWin9xFile (&e, WinntSif, p)) {
  1434. do {
  1435. if (!SppPutFileInBackupImage (backupImage, &imagePos, &header, e.CurLine)) {
  1436. result = FALSE;
  1437. break;
  1438. }
  1439. currentFile++;
  1440. ASSERT(fileCount);
  1441. percentDone = currentFile * 100 / fileCount;
  1442. SendSetupProgressEvent (
  1443. BackupEvent,
  1444. OneFileBackedUpEvent,
  1445. &percentDone
  1446. );
  1447. } while (SpEnumNextWin9xFile (&e));
  1448. } else {
  1449. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error in SpBackUpWin9xFiles No files to enumerate.\n"));
  1450. }
  1451. SendSetupProgressEvent (BackupEvent, BackupEndEvent, NULL);
  1452. //
  1453. // Close the backup image. We leave the journal file in all cases.
  1454. //
  1455. if (!SppCloseBackupImage (backupImage, &header, result ? journalFile : NULL)) {
  1456. result = FALSE;
  1457. }
  1458. if (result) {
  1459. //
  1460. // Backup was successful
  1461. //
  1462. askForRetry = FALSE;
  1463. //
  1464. // Remove the MS-DOS boot.ini entry, and add a cancel entry.
  1465. //
  1466. result = SpAddRollbackBootOption (FALSE);
  1467. if (result) {
  1468. data = SpGetSectionKeyIndex (SifHandle, SIF_SETUPDATA, L"LoadIdentifier", 0);
  1469. if (!data) {
  1470. SpFatalSifError (SifHandle, SIF_SETUPDATA, L"LoadIdentifier",0,0);
  1471. }
  1472. result = SppCreateTextModeBootEntry (data, NULL, TRUE);
  1473. }
  1474. if (result) {
  1475. result = SpFlushBootVars();
  1476. }
  1477. //
  1478. // Make a backup of setup in-progress boot.ini in ~BT directory, for
  1479. // use by PSS
  1480. //
  1481. if (!NtBootDevicePath) {
  1482. ASSERT(NtBootDevicePath);
  1483. result = FALSE;
  1484. }
  1485. if (result) {
  1486. ASSERT(ARRAYSIZE(TemporaryBuffer) >= (wcslen(NtBootDevicePath) + 1/*'\\'*/ + ARRAYSIZE(L"boot.ini")));
  1487. wcscpy (TemporaryBuffer, NtBootDevicePath);
  1488. SpConcatenatePaths (TemporaryBuffer, L"boot.ini");
  1489. srcBootIni = SpDupStringW (TemporaryBuffer);
  1490. if (!srcBootIni) {
  1491. result = FALSE;
  1492. }
  1493. }
  1494. if (result) {
  1495. ASSERT(ARRAYSIZE(TemporaryBuffer) >= (wcslen(NtBootDevicePath) + 1/*'\\'*/ + ARRAYSIZE(L"$WIN_NT$.~BT\\bootini.bak")));
  1496. wcscpy (TemporaryBuffer, NtBootDevicePath);
  1497. SpConcatenatePaths (TemporaryBuffer, L"$WIN_NT$.~BT\\bootini.bak");
  1498. backupBootIni = SpDupStringW (TemporaryBuffer);
  1499. if (!backupBootIni) {
  1500. SpMemFree (srcBootIni);
  1501. result = FALSE;
  1502. }
  1503. }
  1504. if (result) {
  1505. //
  1506. // If this fails, keep going.
  1507. //
  1508. SpCopyFileUsingNames (srcBootIni, backupBootIni, 0, COPY_NODECOMP|COPY_NOVERSIONCHECK);
  1509. SpMemFree (srcBootIni);
  1510. SpMemFree (backupBootIni);
  1511. }
  1512. }
  1513. cleanup:
  1514. if (askForRetry) {
  1515. //
  1516. // The backup image is bad. Notify the user but allow them continue.
  1517. // Delete the journal file so that any future restarts of textmode
  1518. // cause the backup process to be skipped.
  1519. //
  1520. //
  1521. SpNonCriticalErrorNoRetry (SP_SCRN_BACKUP_IMAGE_FAILED, NULL, NULL);
  1522. CLEAR_CLIENT_SCREEN();
  1523. //
  1524. // Create a new journal file, indicating that backup is disabled
  1525. //
  1526. INIT_OBJA (&obja, &unicodeString, journalFile);
  1527. SpDeleteFile (journalFile, NULL, NULL);
  1528. status = ZwCreateFile (
  1529. &journalHandle,
  1530. SYNCHRONIZE | FILE_GENERIC_WRITE,
  1531. &obja,
  1532. &ioStatusBlock,
  1533. NULL,
  1534. FILE_ATTRIBUTE_NORMAL,
  1535. 0,
  1536. FILE_CREATE,
  1537. FILE_SYNCHRONOUS_IO_NONALERT|FILE_WRITE_THROUGH,
  1538. NULL,
  1539. 0
  1540. );
  1541. if (NT_SUCCESS(status)) {
  1542. journalStatus = BACKUP_SKIPPED_BY_USER;
  1543. SppWriteToFile (journalHandle, &journalStatus, sizeof (journalStatus), NULL);
  1544. ZwClose (journalHandle);
  1545. }
  1546. }
  1547. SpMemFree (journalFile);
  1548. return result;
  1549. }
  1550. typedef struct tagHASHITEM {
  1551. struct tagHASHITEM *Next;
  1552. PCWSTR String;
  1553. } HASHITEM, *PHASHITEM;
  1554. typedef struct {
  1555. PHASHITEM HashItem;
  1556. INT BucketNumber;
  1557. BOOLEAN First;
  1558. } HASHITEM_ENUM, *PHASHITEM_ENUM;
  1559. HASHITEM g_UninstallHashTable[MAX_PATH];
  1560. UINT
  1561. SppComputeHash (
  1562. IN PCWSTR String
  1563. )
  1564. {
  1565. return MAX_PATH - 1 - (wcslen (String) % MAX_PATH);
  1566. }
  1567. PHASHITEM
  1568. SppFindInHashTable (
  1569. IN PCWSTR DosFilePath,
  1570. OUT PUINT OutHashValue, OPTIONAL
  1571. OUT PHASHITEM *LastItem OPTIONAL
  1572. )
  1573. {
  1574. UINT hashValue;
  1575. PHASHITEM item;
  1576. hashValue = SppComputeHash (DosFilePath);
  1577. if (OutHashValue) {
  1578. *OutHashValue = hashValue;
  1579. }
  1580. item = &g_UninstallHashTable[hashValue];
  1581. if (LastItem) {
  1582. *LastItem = NULL;
  1583. }
  1584. if (item->String) {
  1585. do {
  1586. if (_wcsicmp (item->String, DosFilePath) == 0) {
  1587. break;
  1588. }
  1589. if (LastItem) {
  1590. *LastItem = item;
  1591. }
  1592. item = item->Next;
  1593. } while (item);
  1594. } else {
  1595. item = NULL;
  1596. }
  1597. return item;
  1598. }
  1599. BOOLEAN
  1600. SppPutInHashTable (
  1601. IN PCWSTR DosFilePath
  1602. )
  1603. {
  1604. PHASHITEM newItem;
  1605. PHASHITEM parentItem;
  1606. UINT hashValue;
  1607. if (SppFindInHashTable (DosFilePath, &hashValue, &parentItem)) {
  1608. return TRUE;
  1609. }
  1610. if (!parentItem) {
  1611. g_UninstallHashTable[hashValue].String = SpDupStringW (DosFilePath);
  1612. return g_UninstallHashTable[hashValue].String != NULL;
  1613. }
  1614. newItem = SpMemAlloc (sizeof (HASHITEM));
  1615. if (!newItem) {
  1616. return FALSE;
  1617. }
  1618. newItem->Next = NULL;
  1619. newItem->String = SpDupStringW (DosFilePath);
  1620. parentItem->Next = newItem;
  1621. return TRUE;
  1622. }
  1623. BOOLEAN
  1624. SppPutParentsInHashTable (
  1625. IN PCWSTR DosFilePath
  1626. )
  1627. {
  1628. PCWSTR s;
  1629. PWSTR subPath;
  1630. PWSTR p;
  1631. BOOLEAN result = FALSE;
  1632. s = SpDupStringW (DosFilePath);
  1633. if (s) {
  1634. subPath = wcschr (s, L'\\');
  1635. if (subPath) {
  1636. subPath++;
  1637. for (;;) {
  1638. p = wcsrchr (subPath, L'\\');
  1639. if (p) {
  1640. *p = 0;
  1641. result = SppPutInHashTable (s);
  1642. } else {
  1643. break;
  1644. }
  1645. break; // for now, do not go all the way up the tree
  1646. }
  1647. }
  1648. SpMemFree ((PVOID) s);
  1649. }
  1650. return result;
  1651. }
  1652. PHASHITEM
  1653. SppEnumNextHashItem (
  1654. IN OUT PHASHITEM_ENUM EnumPtr
  1655. )
  1656. {
  1657. do {
  1658. if (!EnumPtr->HashItem) {
  1659. EnumPtr->BucketNumber += 1;
  1660. if (EnumPtr->BucketNumber >= MAX_PATH) {
  1661. break;
  1662. }
  1663. EnumPtr->HashItem = &g_UninstallHashTable[EnumPtr->BucketNumber];
  1664. if (EnumPtr->HashItem->String) {
  1665. EnumPtr->First = TRUE;
  1666. } else {
  1667. EnumPtr->HashItem = NULL;
  1668. }
  1669. } else {
  1670. EnumPtr->HashItem = EnumPtr->HashItem->Next;
  1671. EnumPtr->First = FALSE;
  1672. }
  1673. } while (!EnumPtr->HashItem);
  1674. return EnumPtr->HashItem;
  1675. }
  1676. PHASHITEM
  1677. SppEnumFirstHashItem (
  1678. OUT PHASHITEM_ENUM EnumPtr
  1679. )
  1680. {
  1681. EnumPtr->BucketNumber = -1;
  1682. EnumPtr->HashItem = NULL;
  1683. return SppEnumNextHashItem (EnumPtr);
  1684. }
  1685. VOID
  1686. SppEmptyHashTable (
  1687. VOID
  1688. )
  1689. {
  1690. HASHITEM_ENUM e;
  1691. PVOID freeMe = NULL;
  1692. if (SppEnumFirstHashItem (&e)) {
  1693. do {
  1694. ASSERT (e.HashItem->String);
  1695. SpMemFree ((PVOID) e.HashItem->String);
  1696. if (freeMe) {
  1697. SpMemFree (freeMe);
  1698. freeMe = NULL;
  1699. }
  1700. if (!e.First) {
  1701. freeMe = (PVOID) e.HashItem;
  1702. }
  1703. } while (SppEnumNextHashItem (&e));
  1704. }
  1705. if (freeMe) {
  1706. SpMemFree (freeMe);
  1707. }
  1708. RtlZeroMemory (g_UninstallHashTable, sizeof (g_UninstallHashTable));
  1709. }
  1710. BOOLEAN
  1711. SppEmptyDirProc (
  1712. IN PCWSTR Path,
  1713. IN PFILE_BOTH_DIR_INFORMATION DirInfo,
  1714. OUT PULONG ReturnData,
  1715. IN OUT PVOID DontCare
  1716. )
  1717. {
  1718. if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1719. return TRUE;
  1720. }
  1721. return FALSE;
  1722. }
  1723. BOOLEAN
  1724. SppIsDirEmpty (
  1725. IN PCWSTR NtPath
  1726. )
  1727. {
  1728. ENUMFILESRESULT result;
  1729. ULONG dontCare;
  1730. result = SpEnumFilesRecursive ((PWSTR) NtPath, SppEmptyDirProc, &dontCare, NULL);
  1731. return result == NormalReturn;
  1732. }
  1733. BOOLEAN
  1734. SppDelEmptyDirProc (
  1735. IN PCWSTR Path,
  1736. IN PFILE_BOTH_DIR_INFORMATION DirInfo,
  1737. OUT PULONG ReturnData,
  1738. IN OUT PVOID DontCare
  1739. )
  1740. {
  1741. PCWSTR subPath;
  1742. PWSTR p;
  1743. PWSTR end;
  1744. UINT bytesToCopy;
  1745. //
  1746. // If we find a file, fail. This must be checked before any deletion
  1747. // occurs.
  1748. //
  1749. if (!(DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1750. return TRUE;
  1751. }
  1752. //
  1753. // Join Path with the enumerated directory. Contain the path to MAX_PATH.
  1754. //
  1755. if(wcslen(Path) >= ARRAYSIZE(TemporaryBuffer)){
  1756. ASSERT(FALSE);
  1757. return TRUE;
  1758. }
  1759. wcscpy (TemporaryBuffer, Path);
  1760. if (DirInfo->FileNameLength) {
  1761. p = wcschr (TemporaryBuffer, 0);
  1762. bytesToCopy = DirInfo->FileNameLength;
  1763. end = (TemporaryBuffer + (ACTUAL_MAX_PATH) - 2) - (bytesToCopy / sizeof (WCHAR));
  1764. if (!p || p > end) {
  1765. KdPrintEx((
  1766. DPFLTR_SETUP_ID,
  1767. DPFLTR_ERROR_LEVEL,
  1768. "SETUP: Enumeration of %ws became too long\n",
  1769. Path
  1770. ));
  1771. return FALSE;
  1772. }
  1773. *p++ = L'\\';
  1774. RtlCopyMemory (p, DirInfo->FileName, bytesToCopy);
  1775. ASSERT(ARRAYSIZE(TemporaryBuffer) > (bytesToCopy / sizeof(WCHAR)));
  1776. p[bytesToCopy / sizeof(WCHAR)] = '\0';
  1777. }
  1778. //
  1779. // Duplicate temp buffer and call ourselves recursively to delete
  1780. // any contained subdirs
  1781. //
  1782. subPath = SpDupStringW (TemporaryBuffer);
  1783. if (!subPath) {
  1784. KdPrintEx((
  1785. DPFLTR_SETUP_ID,
  1786. DPFLTR_ERROR_LEVEL,
  1787. "SETUP: SpDupStringW failed to allocate memory for %d bytes",
  1788. wcslen(TemporaryBuffer) * sizeof(WCHAR)));
  1789. return FALSE;
  1790. }
  1791. SppDelEmptyDir (subPath);
  1792. SpMemFree ((PVOID) subPath);
  1793. return TRUE;
  1794. }
  1795. BOOLEAN
  1796. SppDelEmptyDir (
  1797. IN PCWSTR NtPath
  1798. )
  1799. {
  1800. ENUMFILESRESULT result;
  1801. ULONG dontCare;
  1802. NTSTATUS status;
  1803. //
  1804. // Remove any empty subdirectories in NtPath
  1805. //
  1806. result = SpEnumFiles ((PWSTR) NtPath, SppDelEmptyDirProc, &dontCare, NULL);
  1807. if (result != NormalReturn) {
  1808. KdPrintEx((
  1809. DPFLTR_SETUP_ID,
  1810. DPFLTR_ERROR_LEVEL,
  1811. "SETUP: Failed to enumerate contents of %ws - status 0x%08X\n",
  1812. NtPath,
  1813. result
  1814. ));
  1815. }
  1816. //
  1817. // Now remove this subdirectory
  1818. //
  1819. status = SpSetAttributes ((PWSTR) NtPath, FILE_ATTRIBUTE_NORMAL);
  1820. if (!NT_SUCCESS (status)) {
  1821. KdPrintEx((
  1822. DPFLTR_SETUP_ID,
  1823. DPFLTR_ERROR_LEVEL,
  1824. "SETUP: Can't alter attributes of %ws - status 0x%08X\n",
  1825. NtPath,
  1826. status
  1827. ));
  1828. }
  1829. status = SpDeleteFileEx (
  1830. NtPath,
  1831. NULL,
  1832. NULL,
  1833. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  1834. FILE_OPEN_FOR_BACKUP_INTENT
  1835. );
  1836. if (!NT_SUCCESS (status)){
  1837. KdPrintEx((
  1838. DPFLTR_SETUP_ID,
  1839. DPFLTR_ERROR_LEVEL,
  1840. "SETUP: Can't delete %ws - status 0x%08X\n",
  1841. NtPath,
  1842. status
  1843. ));
  1844. }
  1845. return NT_SUCCESS (status);
  1846. }
  1847. VOID
  1848. SppCleanEmptyDirs (
  1849. VOID
  1850. )
  1851. {
  1852. HASHITEM_ENUM e;
  1853. PWSTR ntPath;
  1854. PWSTR p;
  1855. NTSTATUS result;
  1856. //
  1857. // Enumerate the length-sorted hash table
  1858. //
  1859. ntPath = SpMemAlloc (ACTUAL_MAX_PATH * sizeof (WCHAR));
  1860. if (!ntPath) {
  1861. return;
  1862. }
  1863. if (SppEnumFirstHashItem (&e)) {
  1864. do {
  1865. ASSERT (e.HashItem->String);
  1866. //
  1867. // Convert String into NT path
  1868. //
  1869. if (!SpNtNameFromDosPath (
  1870. (PWSTR) e.HashItem->String,
  1871. ntPath,
  1872. ACTUAL_MAX_PATH * sizeof (WCHAR),
  1873. PartitionOrdinalCurrent
  1874. )) {
  1875. KdPrintEx((
  1876. DPFLTR_SETUP_ID,
  1877. DPFLTR_ERROR_LEVEL,
  1878. "SETUP: Cannot convert path %ws to an NT path\n",
  1879. e.HashItem->String
  1880. ));
  1881. continue;
  1882. }
  1883. //
  1884. // Does it exist? If not, skip it.
  1885. //
  1886. if (!SpFileExists (ntPath, TRUE)) {
  1887. continue;
  1888. }
  1889. //
  1890. // Find the root emtpy dir. Then blow it away, including any empty
  1891. // subdirs it might have.
  1892. //
  1893. if (SppIsDirEmpty (ntPath)) {
  1894. if (!SppDelEmptyDir (ntPath)) {
  1895. KdPrintEx((
  1896. DPFLTR_SETUP_ID,
  1897. DPFLTR_ERROR_LEVEL,
  1898. "SETUP: Unable to delete empty dir %ws\n",
  1899. ntPath
  1900. ));
  1901. }
  1902. else {
  1903. //
  1904. // find the first non-empty path
  1905. //
  1906. p = wcsrchr (ntPath, L'\\');
  1907. while (p) {
  1908. *p = 0;
  1909. if (!SppIsDirEmpty (ntPath)) {
  1910. *p = L'\\';
  1911. break;
  1912. }
  1913. else{
  1914. //
  1915. // remove this empty tree
  1916. //
  1917. if (!SppDelEmptyDir (ntPath)) {
  1918. KdPrintEx((
  1919. DPFLTR_SETUP_ID,
  1920. DPFLTR_ERROR_LEVEL,
  1921. "SETUP: Unable to delete empty parent dir %ws\n",
  1922. ntPath
  1923. ));
  1924. break;
  1925. }
  1926. }
  1927. p = wcsrchr (ntPath, L'\\');
  1928. }
  1929. }
  1930. }
  1931. } while (SppEnumNextHashItem (&e));
  1932. }
  1933. SpMemFree (ntPath);
  1934. }
  1935. PDISK_REGION
  1936. SppRegionFromFullNtName (
  1937. IN PWSTR NtName,
  1938. IN PartitionOrdinalType OrdinalType,
  1939. OUT PWSTR *Path OPTIONAL
  1940. )
  1941. {
  1942. WCHAR ntRoot[ACTUAL_MAX_PATH];
  1943. PWSTR p;
  1944. PWSTR end;
  1945. //
  1946. // NtName is in the format of
  1947. //
  1948. // \Device\harddisk<n>\partition<m>\subdir
  1949. //
  1950. // and we need to separate the two.
  1951. //
  1952. if(wcslen(NtName) >= ARRAYSIZE(ntRoot)){
  1953. ASSERT(FALSE);
  1954. return NULL;
  1955. }
  1956. wcscpy (ntRoot, NtName);
  1957. // p points to \Device\harddisk<n>\partition<m>\subdir
  1958. p = wcschr (ntRoot + 1, L'\\');
  1959. if (p) {
  1960. // p points to \harddisk<n>\partition<m>\subdir
  1961. p = wcschr (p + 1, L'\\');
  1962. if (p) {
  1963. // p points to \partition<m>\subdir
  1964. end = p;
  1965. p = wcschr (p + 1, L'\\');
  1966. if (!p) {
  1967. p = wcschr (end, 0);
  1968. }
  1969. }
  1970. }
  1971. if (p) {
  1972. // p points to \subdir or '\0'
  1973. *p = 0;
  1974. if (Path) {
  1975. *Path = NtName + (p - ntRoot);
  1976. }
  1977. return SpRegionFromNtName (ntRoot, OrdinalType);
  1978. }
  1979. return NULL;
  1980. }
  1981. BOOLEAN
  1982. SppCreateTextModeBootEntry (
  1983. IN PWSTR LoadIdentifierString,
  1984. IN PWSTR OsLoadOptions, OPTIONAL
  1985. IN BOOLEAN Default
  1986. )
  1987. /*++
  1988. Routine Description:
  1989. SppCreateTextModeBootEntry makes another boot.ini entry for textmode.
  1990. This is used to create the boot.ini entry that triggers rollback in
  1991. an incomplete setup scenario.
  1992. Arguments:
  1993. LoadIdentifierString - Specifies the localized text to put in the boot menu.
  1994. OsLoadOptions - Specifies options to associate with the boot option,
  1995. such as /rollback.
  1996. Default - Specifies TRUE if the entry should be the default
  1997. boot option
  1998. Return Value:
  1999. TRUE if boot.ini was updated, FALSE otherwise.
  2000. --*/
  2001. {
  2002. PWSTR bootVars[MAXBOOTVARS];
  2003. PWSTR defaultBootEntry = L"C:\\$WIN_NT$.~BT\\bootsect.dat";
  2004. PWSTR defaultArc = L"C:\\$WIN_NT$.~BT\\";
  2005. PWSTR defaultFile = L"bootsect.dat";
  2006. PDISK_REGION CColonRegion;
  2007. UINT defaultSignature;
  2008. CColonRegion = SpPtValidSystemPartition();
  2009. if (!CColonRegion) {
  2010. KdPrintEx((
  2011. DPFLTR_SETUP_ID,
  2012. DPFLTR_ERROR_LEVEL,
  2013. "SETUP: Unable to find region of drive C."
  2014. ));
  2015. }
  2016. //
  2017. // Create a boot set
  2018. //
  2019. bootVars[OSLOADOPTIONS] = SpDupStringW (OsLoadOptions ? OsLoadOptions : L"");
  2020. bootVars[LOADIDENTIFIER] = SpMemAlloc((wcslen(LoadIdentifierString)+3)*sizeof(WCHAR));
  2021. bootVars[LOADIDENTIFIER][0] = L'\"';
  2022. wcscpy (bootVars[LOADIDENTIFIER] + 1, LoadIdentifierString);
  2023. wcscat (bootVars[LOADIDENTIFIER], L"\"");
  2024. bootVars[OSLOADER] = SpDupStringW (defaultBootEntry);
  2025. bootVars[OSLOADPARTITION] = SpDupStringW (defaultArc);
  2026. bootVars[SYSTEMPARTITION] = SpDupStringW (defaultArc);
  2027. bootVars[OSLOADFILENAME] = SpDupStringW (defaultFile);
  2028. if (CColonRegion->DiskNumber != 0xffffffff) {
  2029. defaultSignature = HardDisks[CColonRegion->DiskNumber].Signature;
  2030. } else {
  2031. defaultSignature = 0;
  2032. }
  2033. SpAddBootSet (bootVars, Default, defaultSignature);
  2034. return TRUE;
  2035. }
  2036. BOOL
  2037. SppRestoreBackedUpFileNotification (
  2038. PCWSTR FileName
  2039. )
  2040. {
  2041. //KdPrint((__FUNCTION__" %ls\n", FileName));
  2042. return TRUE;
  2043. }
  2044. VOID
  2045. SppRestoreBackedUpFiles (
  2046. IN PVOID WinntSif
  2047. )
  2048. {
  2049. BOOL Success = FALSE;
  2050. BACKUP_IMAGE_HANDLE backupImage = NULL;
  2051. BACKUP_IMAGE_HEADER header = { 0 };
  2052. LARGE_INTEGER imagePos = { 0 };
  2053. backupImage = SppOpenBackupImage (FALSE, &header, &imagePos, NULL, tcompTYPE_MSZIP, NULL);
  2054. if (backupImage == INVALID_HANDLE_VALUE) {
  2055. return;
  2056. }
  2057. Success = SpCabExtractAllFilesExW(backupImage->CabHandle, L"", SppRestoreBackedUpFileNotification);
  2058. SppCloseBackupImage (backupImage, NULL, NULL);
  2059. }
  2060. DWORD Spwtoi (
  2061. IN LPCWSTR String)
  2062. {
  2063. DWORD rVal = 0;
  2064. //
  2065. // While on a number, build up rVal.
  2066. //
  2067. while (String && *String && *String >= L'0' && *String <= L'9') {
  2068. rVal = rVal * 10 + (*String - L'0');
  2069. String++;
  2070. }
  2071. return rVal;
  2072. }
  2073. BOOL
  2074. pParseLineForDirNameAndAttributes(
  2075. IN PCWSTR LineForParse,
  2076. OUT PWSTR DirName,
  2077. IN ULONG CchDirNameSize,
  2078. OUT DWORD * DirAttributes
  2079. )
  2080. {
  2081. int i;
  2082. int iLen;
  2083. if(!LineForParse || !DirName){
  2084. ASSERT(FALSE);
  2085. return FALSE;
  2086. }
  2087. for(i = 0, iLen = wcslen(LineForParse); i < iLen; i++)
  2088. {
  2089. if(LineForParse[i] == ','){
  2090. break;
  2091. }
  2092. }
  2093. if(i == iLen){
  2094. if(wcslen(LineForParse) >= CchDirNameSize){
  2095. ASSERT(FALSE);
  2096. return FALSE;
  2097. }
  2098. wcscpy(DirName, LineForParse);
  2099. }
  2100. else{
  2101. if(i >= (int)CchDirNameSize){
  2102. ASSERT(FALSE);
  2103. return FALSE;
  2104. }
  2105. wcsncpy(DirName, LineForParse, i);DirName[i] = '\0';
  2106. if(DirAttributes){
  2107. *DirAttributes = Spwtoi((PCWSTR)&LineForParse[i + 1]);
  2108. }
  2109. }
  2110. return TRUE;
  2111. }
  2112. VOID
  2113. SppMkEmptyDirs (
  2114. IN PVOID WinntSif,
  2115. IN PCWSTR DosDirListPath
  2116. )
  2117. {
  2118. WIN9XDATFILEENUM e;
  2119. PDISK_REGION region = NULL;
  2120. NTSTATUS Status = STATUS_SUCCESS;
  2121. WCHAR ntName[ACTUAL_MAX_PATH];
  2122. WCHAR ntRoot[ACTUAL_MAX_PATH];
  2123. PWSTR subDir = NULL;
  2124. UINT dirAttributes;
  2125. WCHAR dirName[ACTUAL_MAX_PATH];
  2126. //
  2127. // Blow away files or empty directories
  2128. //
  2129. if (SpEnumFirstWin9xFile (&e, WinntSif, DosDirListPath)) {
  2130. do {
  2131. //
  2132. // Convert e.CurLine from a DOS path to an NT path
  2133. //
  2134. dirAttributes = 0;
  2135. if(!pParseLineForDirNameAndAttributes(e.CurLine, dirName, ARRAYSIZE(dirName), &dirAttributes)){
  2136. ASSERT(FALSE);
  2137. continue;
  2138. }
  2139. if (!SpNtNameFromDosPath (
  2140. dirName,
  2141. ntName,
  2142. sizeof (ntName),
  2143. PartitionOrdinalCurrent
  2144. )) {
  2145. KdPrintEx((
  2146. DPFLTR_SETUP_ID,
  2147. DPFLTR_ERROR_LEVEL,
  2148. "SETUP: " __FUNCTION__ ": Cannot convert path %ws to an NT path\n",
  2149. dirName
  2150. ));
  2151. } else {
  2152. region = SppRegionFromFullNtName (ntName, PartitionOrdinalCurrent, &subDir);
  2153. if (!region) {
  2154. KdPrintEx ((
  2155. DPFLTR_SETUP_ID,
  2156. DPFLTR_ERROR_LEVEL,
  2157. "SETUP: "__FUNCTION__" - Can't get region for empty dirs\n"
  2158. ));
  2159. } else{
  2160. SpNtNameFromRegion (region, ntRoot, sizeof(ntRoot), PartitionOrdinalCurrent);
  2161. SpCreateDirectory (ntRoot, NULL, subDir, dirAttributes, 0);
  2162. SpSetFileAttributesW(ntName, dirAttributes);
  2163. }
  2164. }
  2165. } while (SpEnumNextWin9xFile(&e));
  2166. } else {
  2167. KdPrintEx((
  2168. DPFLTR_SETUP_ID,
  2169. DPFLTR_ERROR_LEVEL,
  2170. "SETUP: " __FUNCTION__ ": No files to enumerate.\n"
  2171. ));
  2172. }
  2173. }
  2174. VOID
  2175. SpRemoveExtraBootIniEntry (
  2176. VOID
  2177. )
  2178. {
  2179. PWSTR bootVars[MAXBOOTVARS];
  2180. PWSTR defaultBootEntry = L"C:\\$WIN_NT$.~BT\\bootsect.dat";
  2181. PWSTR defaultArc = L"C:\\$WIN_NT$.~BT\\";
  2182. PWSTR defaultFile = L"bootsect.dat";
  2183. PDISK_REGION CColonRegion;
  2184. //
  2185. // Remove the boot set for text mode
  2186. //
  2187. RtlZeroMemory (bootVars, sizeof(bootVars));
  2188. bootVars[OSLOADOPTIONS] = L"";
  2189. bootVars[OSLOADER] = defaultBootEntry;
  2190. bootVars[OSLOADPARTITION] = defaultArc;
  2191. bootVars[SYSTEMPARTITION] = defaultArc;
  2192. bootVars[OSLOADFILENAME] = defaultFile;
  2193. SpDeleteBootSet (bootVars, NULL);
  2194. }
  2195. VOID
  2196. SppMakeLegacyBootIni (
  2197. IN PDISK_REGION TargetRegion
  2198. )
  2199. {
  2200. PWSTR data;
  2201. PWSTR bootVars[MAXBOOTVARS];
  2202. WCHAR sysPart[MAX_PATH];
  2203. UINT signature;
  2204. //
  2205. // Reset the entire boot.ini file
  2206. //
  2207. RtlZeroMemory (bootVars, sizeof(bootVars));
  2208. SpDeleteBootSet (bootVars, NULL);
  2209. //
  2210. // Build new boot.ini entry
  2211. //
  2212. // LOADIDENTIFIER - friendly name
  2213. data = SpGetSectionKeyIndex (SifHandle, SIF_SETUPDATA, L"LoadIdentifierWin9x", 0);
  2214. if (!data) {
  2215. SpFatalSifError (SifHandle, SIF_SETUPDATA, L"LoadIdentifierWin9x",0,0);
  2216. }
  2217. bootVars[LOADIDENTIFIER] = SpMemAlloc((wcslen(data)+3)*sizeof(WCHAR));
  2218. bootVars[LOADIDENTIFIER][0] = L'\"';
  2219. wcscpy (bootVars[LOADIDENTIFIER] + 1, data);
  2220. wcscat (bootVars[LOADIDENTIFIER], L"\"");
  2221. // OSLOADER - c:\ntldr (in ARC format)
  2222. SpArcNameFromRegion (
  2223. TargetRegion,
  2224. sysPart,
  2225. sizeof(sysPart),
  2226. PartitionOrdinalCurrent,
  2227. PrimaryArcPath
  2228. );
  2229. data = TemporaryBuffer;
  2230. ASSERT(ARRAYSIZE(TemporaryBuffer) >= (ARRAYSIZE(sysPart) + ARRAYSIZE(L"ntldr")));
  2231. wcscpy (data, sysPart);
  2232. SpConcatenatePaths (data, L"ntldr");
  2233. bootVars[OSLOADER] = SpDupStringW (data);
  2234. // OSLOADPARTITION - "c:\"
  2235. data[0] = TargetRegion->DriveLetter;
  2236. data[1] = L':';
  2237. data[2] = L'\\';
  2238. data[3] = 0;
  2239. if (data[0] != L'C' && data[0] != L'D' && data[0] != L'c' && data[0] != L'd') {
  2240. data[0] = L'C';
  2241. }
  2242. bootVars[OSLOADPARTITION] = SpDupStringW (data);
  2243. // SYSTEMPARTITION - same as OSLOADPARTITION
  2244. bootVars[SYSTEMPARTITION] = SpDupStringW (data);
  2245. // OSLOADFILENAME - empty
  2246. bootVars[OSLOADFILENAME] = SpDupStringW (L"");
  2247. // OSLOADOPTIONS - empty
  2248. bootVars[OSLOADOPTIONS] = SpDupStringW (L"");
  2249. // signature
  2250. if (TargetRegion->DiskNumber != 0xffffffff) {
  2251. signature = HardDisks[TargetRegion->DiskNumber].Signature;
  2252. } else {
  2253. signature = 0;
  2254. }
  2255. // add to boot.ini (takes ownership of allocations above)
  2256. SpAddBootSet (bootVars, TRUE, signature);
  2257. // flush boot.ini
  2258. SpCompleteBootListConfig (TargetRegion->DriveLetter);
  2259. }
  2260. BOOLEAN
  2261. SpExecuteWin9xRollback (
  2262. IN PVOID WinntSifHandle,
  2263. IN PWSTR BootDeviceNtPath
  2264. )
  2265. {
  2266. PWSTR data;
  2267. PDISK_REGION bootRegion;
  2268. ULONG i = 0;
  2269. PCWSTR Directory = NULL;
  2270. PWSTR NtNameFromDosPath = NULL;
  2271. //
  2272. // Perform rollback
  2273. //
  2274. // step 1: delete NT files
  2275. data = SpGetSectionKeyIndex (
  2276. WinntSifHandle,
  2277. SIF_DATA,
  2278. WINNT_D_ROLLBACK_DELETE_W,
  2279. 0
  2280. );
  2281. if (data) {
  2282. SppDeleteWin9xFilesWorker (WinntSifHandle, data, NULL, TRUE);
  2283. SppCleanEmptyDirs();
  2284. }
  2285. TESTHOOK(1003); // use 2003 in the answer file to hit this
  2286. // step 2: move Win9x files back to original locations
  2287. data = SpGetSectionKeyIndex (
  2288. WinntSifHandle,
  2289. SIF_DATA,
  2290. WINNT_D_ROLLBACK_MOVE_W,
  2291. 0
  2292. );
  2293. if (data) {
  2294. SppMoveWin9xFilesWorker (WinntSifHandle, data, TRUE);
  2295. }
  2296. TESTHOOK(1004); // use 2004 in the answer file to hit this
  2297. // step 3: blow away NT-specific subdirectories
  2298. data = SpGetSectionKeyIndex (
  2299. WinntSifHandle,
  2300. SIF_DATA,
  2301. WINNT_D_ROLLBACK_DELETE_DIR_W,
  2302. 0
  2303. );
  2304. if (data) {
  2305. SppDeleteWin9xFilesWorker (WinntSifHandle, NULL, data, TRUE);
  2306. }
  2307. TESTHOOK(1005); // use 2005 in the answer file to hit this
  2308. // step 4: restore files that were backed up
  2309. SppRestoreBackedUpFiles (WinntSifHandle);
  2310. TESTHOOK(1006); // use 2006 in the answer file to hit this
  2311. // step 5: wipe out dirs made empty
  2312. SppCleanEmptyDirs();
  2313. TESTHOOK(1007); // use 2007 in the answer file to hit this
  2314. // step 6: generate original empty dirs
  2315. data = SpGetSectionKeyIndex (
  2316. WinntSifHandle,
  2317. SIF_DATA,
  2318. L"RollbackMkDirs",
  2319. 0
  2320. );
  2321. if (data) {
  2322. SppMkEmptyDirs (WinntSifHandle, data);
  2323. }
  2324. TESTHOOK(1008); // use 2008 in the answer file to hit this
  2325. //
  2326. // step 7: clean up boot loader
  2327. //
  2328. bootRegion = SpRegionFromNtName (BootDeviceNtPath, PartitionOrdinalCurrent);
  2329. if (bootRegion) {
  2330. SppMakeLegacyBootIni (bootRegion);
  2331. } else {
  2332. SpBugCheck(SETUP_BUGCHECK_BOOTPATH,0,0,0);
  2333. }
  2334. SppEmptyHashTable();
  2335. return TRUE;
  2336. }
  2337. VOID
  2338. SppMoveWin9xFilesWorker (
  2339. IN PVOID WinntSif,
  2340. IN PCWSTR MoveSection,
  2341. IN BOOLEAN Rollback
  2342. )
  2343. /*++
  2344. Routine Description:
  2345. SpMoveWin9xFiles takes full DOS paths in the WIN9XMOV.TXT file
  2346. and puts them in a temporary location also specified in this file.
  2347. the format of this file is
  2348. oldpath
  2349. temppath
  2350. ...
  2351. oldpath can be either a directory or file, temppath can only be a directory (which may
  2352. not exist yet).
  2353. Arguments:
  2354. WinntSif: Handle to Winnt.Sif
  2355. Return Value:
  2356. None. Errors ignored.
  2357. --*/
  2358. {
  2359. WCHAR SourceFileOrDir[ACTUAL_MAX_PATH];
  2360. PWSTR DestFileOrDir;
  2361. WIN9XDATFILEENUM e;
  2362. if (SpEnumFirstWin9xFile(&e,WinntSif, MoveSection)) {
  2363. do {
  2364. if(wcslen(e.CurLine) >= ARRAYSIZE(SourceFileOrDir)){
  2365. ASSERT(FALSE);
  2366. continue;
  2367. }
  2368. wcscpy (SourceFileOrDir, e.CurLine);
  2369. if (!SpEnumNextWin9xFile(&e)) {
  2370. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error moving win9x files. Improper Win9x dat file."));
  2371. return;
  2372. }
  2373. DestFileOrDir = e.CurLine;
  2374. if (Rollback) {
  2375. SppPutParentsInHashTable (SourceFileOrDir);
  2376. }
  2377. // There's little chance for failure, because in Win95 we've already
  2378. // verified the source exists and the destination does not exist.
  2379. // The only way this can fail is if the hard disk craps out.
  2380. SpMigMoveFileOrDir (SourceFileOrDir, DestFileOrDir);
  2381. } while (SpEnumNextWin9xFile(&e));
  2382. }
  2383. else {
  2384. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error in SpWin9xMovFiles No files to enum in.\n"));
  2385. }
  2386. }
  2387. VOID
  2388. SpMoveWin9xFiles (
  2389. IN PVOID WinntSif
  2390. )
  2391. {
  2392. SppMoveWin9xFilesWorker (WinntSif, WINNT32_D_WIN9XMOV_FILE_W, FALSE);
  2393. }
  2394. VOID
  2395. SppDeleteWin9xFilesWorker (
  2396. IN PVOID WinntSif,
  2397. IN PCWSTR FileSection, OPTIONAL
  2398. IN PCWSTR DirSection, OPTIONAL
  2399. IN BOOLEAN Rollback
  2400. )
  2401. /*++
  2402. Routine Description:
  2403. SpDeleteWin9xFiles deletes files/empty directories specified by full DOS
  2404. paths in WIN9XDEL.TXT (install) or DELFILES.TXT (uninstall).
  2405. Each line in this file contains one path and is delimeted by a \r\n.
  2406. Arguments:
  2407. WinntSif: Handle to Winnt.Sif
  2408. Return Value:
  2409. None. Errors ignored.
  2410. --*/
  2411. {
  2412. WIN9XDATFILEENUM e;
  2413. PDISK_REGION region;
  2414. NTSTATUS Status = STATUS_SUCCESS;
  2415. //
  2416. // Blow away files or empty directories
  2417. //
  2418. if (FileSection && SpEnumFirstWin9xFile(&e,WinntSif,FileSection)) {
  2419. do {
  2420. if (Rollback) {
  2421. SppPutParentsInHashTable (e.CurLine);
  2422. }
  2423. SpMigDeleteFile (e.CurLine);
  2424. } while (SpEnumNextWin9xFile(&e));
  2425. } else {
  2426. KdPrintEx((
  2427. DPFLTR_SETUP_ID,
  2428. DPFLTR_ERROR_LEVEL,
  2429. "SETUP: " __FUNCTION__ ": No files to enumerate.\n"
  2430. ));
  2431. }
  2432. //
  2433. // Remove entire subdirectory trees.
  2434. //
  2435. if (DirSection && SpEnumFirstWin9xFile (&e, WinntSif, DirSection)) {
  2436. do {
  2437. region = SpRegionFromDosName (e.CurLine);
  2438. if (region) {
  2439. SpDeleteExistingTargetDir (region, e.CurLine + 2, TRUE, SP_SCRN_CLEARING_OLD_WINNT);
  2440. if (Rollback) {
  2441. SppPutParentsInHashTable (e.CurLine);
  2442. }
  2443. }
  2444. } while (SpEnumNextWin9xFile (&e));
  2445. } else {
  2446. KdPrintEx((
  2447. DPFLTR_SETUP_ID,
  2448. DPFLTR_ERROR_LEVEL,
  2449. "SETUP: No Directories to delete for win9xupg.\n"
  2450. ));
  2451. }
  2452. }
  2453. VOID
  2454. SpDeleteWin9xFiles (
  2455. IN PVOID WinntSif
  2456. )
  2457. {
  2458. SppDeleteWin9xFilesWorker (WinntSif, WINNT32_D_WIN9XDEL_FILE_W, WINNT32_D_W9XDDIR_FILE_W, FALSE);
  2459. }
  2460. //
  2461. // Win9x Drive Letter mapping specific structs, typedefs, and defines
  2462. //
  2463. typedef struct _WIN9XDRIVELETTERINFO WIN9XDRIVELETTERINFO,*PWIN9XDRIVELETTERINFO;
  2464. struct _WIN9XDRIVELETTERINFO {
  2465. BOOL StatusFlag; // Internal routine use.
  2466. DWORD Drive; // 0 - 25, 0 = 'A', etc.
  2467. DWORD Type; // Media type. Gathered by GetDriveType on Win9x.
  2468. LPCWSTR Identifier; // Media type dependent string identifier.
  2469. PWIN9XDRIVELETTERINFO Next; // Next drive letter.
  2470. };
  2471. #define NUMDRIVELETTERS 26
  2472. #define DEBUGSTATUS(string,status) \
  2473. if (!NT_SUCCESS(status)) KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP (DEBUGSTATUS) %ws %u (%x)\n",(string),(status),(status)))
  2474. //
  2475. // FALSE indicates a drive letter is available,
  2476. // TRUE indicates that a drive letter is already
  2477. // assigned to a system resource.
  2478. //
  2479. BOOL g_DriveLetters[NUMDRIVELETTERS];
  2480. PDISK_REGION
  2481. SpFirstPartitionedRegion (
  2482. IN PDISK_REGION Region,
  2483. IN BOOLEAN Primary
  2484. )
  2485. {
  2486. while (Region) {
  2487. if (Primary) {
  2488. if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
  2489. break;
  2490. }
  2491. } else {
  2492. if (SPPT_IS_REGION_LOGICAL_DRIVE(Region)) {
  2493. break;
  2494. }
  2495. }
  2496. Region = Region -> Next;
  2497. }
  2498. return Region;
  2499. }
  2500. PDISK_REGION
  2501. SpNextPartitionedRegion (
  2502. IN PDISK_REGION Region,
  2503. IN BOOLEAN Primary
  2504. )
  2505. {
  2506. if (Region) {
  2507. return SpFirstPartitionedRegion (Region->Next, Primary);
  2508. }
  2509. return NULL;
  2510. }
  2511. #if 0
  2512. VOID
  2513. SpOutputDriveLettersToRegionsMap(
  2514. VOID
  2515. )
  2516. {
  2517. //
  2518. // This is a debug function. Will be removed.
  2519. //
  2520. DWORD disk;
  2521. PDISK_REGION pRegion;
  2522. WCHAR tempBuffer[MAX_PATH];
  2523. for(disk=0; disk<HardDiskCount; disk++) {
  2524. pRegion = SpFirstPartitionedRegion(PartitionedDisks[disk].PrimaryDiskRegions, TRUE);
  2525. while(pRegion) {
  2526. SpNtNameFromRegion(pRegion,tempBuffer,sizeof(tempBuffer),PartitionOrdinalCurrent);
  2527. if (pRegion -> DriveLetter == 0) {
  2528. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: No drive letter for %ws.\n",tempBuffer));
  2529. }
  2530. else {
  2531. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: %ws maps to drive letter %wc\n",tempBuffer,pRegion -> DriveLetter));
  2532. }
  2533. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: %ws Info: Disk Num: %u Start: %u\n",tempBuffer,pRegion -> DiskNumber,pRegion -> StartSector));
  2534. pRegion = SpNextPartitionedRegion(pRegion, TRUE);
  2535. }
  2536. pRegion = SpFirstPartitionedRegion(PartitionedDisks[disk].PrimaryDiskRegions, FALSE);
  2537. while(pRegion) {
  2538. SpNtNameFromRegion(pRegion,tempBuffer,sizeof(tempBuffer),PartitionOrdinalCurrent);
  2539. if (pRegion -> DriveLetter == 0) {
  2540. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: No drive letter for %ws.\n",tempBuffer));
  2541. }
  2542. else {
  2543. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: %ws maps to drive letter %wc\n",tempBuffer,pRegion -> DriveLetter));
  2544. }
  2545. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: %ws Info: Disk Num: %u Start: %u\n",tempBuffer,pRegion -> DiskNumber,pRegion -> StartSector));
  2546. pRegion = SpNextPartitionedRegion(pRegion, FALSE);
  2547. }
  2548. }
  2549. }
  2550. #endif
  2551. WCHAR
  2552. SpGetNextDriveLetter (
  2553. IN WCHAR LastLetter
  2554. )
  2555. {
  2556. WCHAR rChar = 0;
  2557. DWORD index = LastLetter - L'A';
  2558. //
  2559. // Find the next unused drive letter.
  2560. //
  2561. while (index < NUMDRIVELETTERS && g_DriveLetters[index]) {
  2562. index++;
  2563. }
  2564. if (index < NUMDRIVELETTERS) {
  2565. //
  2566. // A valid letter was found.
  2567. // Set it as the return drive letter and mark its place in the table as used
  2568. //
  2569. rChar = (WCHAR) index + L'A';
  2570. g_DriveLetters[index] = TRUE;
  2571. }
  2572. return rChar;
  2573. }
  2574. VOID
  2575. SpAssignDriveLettersToRemainingPartitions (
  2576. VOID
  2577. )
  2578. /*++
  2579. Routine Description:
  2580. Assigns drive letters to partitions which have not yet received
  2581. the drive letter
  2582. NOTE : This is a modified version of SpGuessDriveLetters().
  2583. Arguments:
  2584. None
  2585. Return Value:
  2586. None
  2587. --*/
  2588. {
  2589. ULONG Disk;
  2590. BOOLEAN DriveLettersPresent = TRUE;
  2591. PDISK_REGION *PrimaryPartitions;
  2592. WCHAR DriveLetter;
  2593. PDISK_REGION pRegion;
  2594. ULONG Index;
  2595. PPARTITIONED_DISK PartDisk;
  2596. //
  2597. // Allocate adequate memory for region pointers to primary partitions
  2598. // on all disks
  2599. //
  2600. PrimaryPartitions = SpMemAlloc(PTABLE_DIMENSION * HardDiskCount * sizeof(PDISK_REGION));
  2601. if(!PrimaryPartitions) {
  2602. KdPrintEx((DPFLTR_SETUP_ID,
  2603. DPFLTR_ERROR_LEVEL,
  2604. "SETUP: Can't allocate memory for drive letter assignment\n"));
  2605. return;
  2606. }
  2607. RtlZeroMemory(PrimaryPartitions,PTABLE_DIMENSION * HardDiskCount * sizeof(PDISK_REGION));
  2608. //
  2609. // Go through each disk and fill up the primary partition
  2610. // region(s) in the array
  2611. //
  2612. for(Disk=0; Disk < HardDiskCount; Disk++) {
  2613. ULONG ActiveIndex = (ULONG)-1;
  2614. PartDisk = PartitionedDisks + Disk;
  2615. //
  2616. // Skip removable media. If a Disk is off-line it's hard to imagine
  2617. // that we'll actually have any partitioned spaces on it so
  2618. // we don't do any special checks here for that condition.
  2619. //
  2620. if(!(PartDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA)) {
  2621. for(pRegion=SPPT_GET_PRIMARY_DISK_REGION(Disk); pRegion; pRegion=pRegion->Next) {
  2622. //
  2623. // We only care about partitioned spaces that have yet to receive
  2624. // a drive letter.
  2625. //
  2626. if (SPPT_IS_REGION_PRIMARY_PARTITION(pRegion) && !pRegion -> DriveLetter) {
  2627. //
  2628. // This guy gets a drive letter.
  2629. //
  2630. ASSERT(pRegion->TablePosition <= PTABLE_DIMENSION);
  2631. PrimaryPartitions[(Disk*PTABLE_DIMENSION) + pRegion->TablePosition - 1] = pRegion;
  2632. //
  2633. // Do not save active flag on NEC98
  2634. //
  2635. if (!IsNEC_98) { //NEC98
  2636. if (SPPT_IS_REGION_ACTIVE_PARTITION(pRegion) && (ActiveIndex != (ULONG)(-1))) {
  2637. ActiveIndex = pRegion->TablePosition - 1;
  2638. }
  2639. } //NEC98
  2640. }
  2641. }
  2642. //
  2643. // Do not check active flag on NEC98
  2644. //
  2645. if (!IsNEC_98) { //NEC98
  2646. //
  2647. // If we found an active partition, move it to the start of
  2648. // the list for this drive unless it's already at the start.
  2649. //
  2650. if((ActiveIndex != (ULONG)(-1)) && ActiveIndex) {
  2651. PDISK_REGION ActiveRegion;
  2652. ASSERT(ActiveIndex < PTABLE_DIMENSION);
  2653. ActiveRegion = PrimaryPartitions[(Disk*PTABLE_DIMENSION) + ActiveIndex];
  2654. RtlMoveMemory(
  2655. &PrimaryPartitions[(Disk*PTABLE_DIMENSION)+1],
  2656. &PrimaryPartitions[(Disk*PTABLE_DIMENSION)],
  2657. (ActiveIndex) * sizeof(PDISK_REGION)
  2658. );
  2659. PrimaryPartitions[Disk*PTABLE_DIMENSION] = ActiveRegion;
  2660. }
  2661. } //NEC98
  2662. }
  2663. }
  2664. if (IsNEC_98 && DriveAssignFromA) { //NEC98
  2665. DriveLetter = L'A'; // First valid hard dive letter for legacy NEC assign.
  2666. } else {
  2667. DriveLetter = L'C'; // First valid hard dive letter.
  2668. } //NEC98
  2669. //
  2670. // Assign drive letters to the first primary partitions
  2671. // for each non-removable on-line Disk.
  2672. //
  2673. for(Disk=0; Disk<HardDiskCount; Disk++) {
  2674. for(Index=0; Index<PTABLE_DIMENSION; Index++) {
  2675. PDISK_REGION Region = PrimaryPartitions[(Disk*PTABLE_DIMENSION) + Index];
  2676. if(Region) {
  2677. DriveLetter = SpGetNextDriveLetter(DriveLetter);
  2678. if (DriveLetter && !Region->DriveLetter) {
  2679. Region->DriveLetter = DriveLetter;
  2680. //
  2681. // Done with the region
  2682. //
  2683. PrimaryPartitions[(Disk*PTABLE_DIMENSION) + Index] = NULL;
  2684. break;
  2685. } else {
  2686. DriveLettersPresent = FALSE;
  2687. break;
  2688. }
  2689. }
  2690. }
  2691. }
  2692. //
  2693. // For each disk, assign drive letters to all the logical drives.
  2694. // For removable drives, we assume a single partition, and that
  2695. // partition gets a drive letter as if it were a logical drive.
  2696. //
  2697. for(Disk=0; DriveLettersPresent && (Disk < HardDiskCount); Disk++) {
  2698. PartDisk = &PartitionedDisks[Disk];
  2699. if(PartDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA) {
  2700. //
  2701. // Give the first primary partition the drive letter
  2702. // and ignore other partitions. Even if there are no
  2703. // partitions, reserve a drive letter.
  2704. //
  2705. for(pRegion=SPPT_GET_PRIMARY_DISK_REGION(Disk); pRegion; pRegion=pRegion->Next) {
  2706. if(SPPT_IS_REGION_PRIMARY_PARTITION(pRegion) && !pRegion->DriveLetter) {
  2707. DriveLetter = SpGetNextDriveLetter(DriveLetter);
  2708. if (DriveLetter) {
  2709. pRegion->DriveLetter = DriveLetter;
  2710. break;
  2711. }
  2712. else {
  2713. DriveLettersPresent = FALSE;
  2714. break;
  2715. }
  2716. }
  2717. }
  2718. } else {
  2719. for(pRegion=SPPT_GET_PRIMARY_DISK_REGION(Disk); pRegion; pRegion=pRegion->Next) {
  2720. if(SPPT_IS_REGION_LOGICAL_DRIVE(pRegion) && pRegion->DriveLetter == 0) {
  2721. //
  2722. // This guy gets a drive letter.
  2723. //
  2724. DriveLetter = SpGetNextDriveLetter(DriveLetter);
  2725. if (DriveLetter) {
  2726. pRegion->DriveLetter = DriveLetter;
  2727. } else {
  2728. DriveLettersPresent = FALSE;
  2729. break;
  2730. }
  2731. }
  2732. }
  2733. }
  2734. }
  2735. //
  2736. // For each non-removable on-line disk, assign drive letters
  2737. // to all remaining primary partitions.
  2738. //
  2739. for (Disk=0; DriveLettersPresent && (Disk < HardDiskCount); Disk++) {
  2740. for(Index=0; Index<PTABLE_DIMENSION; Index++) {
  2741. PDISK_REGION Region = PrimaryPartitions[(Disk*PTABLE_DIMENSION)+Index];
  2742. if (Region && !Region->DriveLetter) {
  2743. DriveLetter = SpGetNextDriveLetter(DriveLetter);
  2744. if (DriveLetter) {
  2745. Region->DriveLetter = DriveLetter;
  2746. } else {
  2747. DriveLettersPresent = FALSE;
  2748. break;
  2749. }
  2750. }
  2751. }
  2752. }
  2753. SpMemFree(PrimaryPartitions);
  2754. #if 0
  2755. SpOutputDriveLettersToRegionsMap();
  2756. #endif
  2757. }
  2758. BOOL
  2759. SpCheckRegionForMatchWithWin9xData(
  2760. IN PDISK_REGION Region,
  2761. IN DWORD DriveToMatch
  2762. )
  2763. {
  2764. NTSTATUS ntStatus;
  2765. HANDLE fileHandle;
  2766. OBJECT_ATTRIBUTES attributes;
  2767. IO_STATUS_BLOCK ioStatus;
  2768. UNICODE_STRING filePath;
  2769. WCHAR tempBuffer[MAX_PATH];
  2770. DWORD sigFileDrive;
  2771. ASSERT(DriveToMatch < NUMDRIVELETTERS);
  2772. //
  2773. // Initialize sigFileDrive to an invalid drive.
  2774. //
  2775. sigFileDrive = NUMDRIVELETTERS;
  2776. //
  2777. // Create Unicode string for the path to the region.
  2778. SpNtNameFromRegion(Region,
  2779. tempBuffer,
  2780. sizeof(tempBuffer) - sizeof(WINNT_WIN95UPG_DRVLTR_W),
  2781. PartitionOrdinalCurrent);
  2782. //
  2783. // Get the file creation times of the $DRVLTR$.~_~ file.
  2784. //
  2785. wcscat(tempBuffer,L"\\");
  2786. wcscat(tempBuffer,WINNT_WIN95UPG_DRVLTR_W);
  2787. RtlInitUnicodeString(&filePath,tempBuffer);
  2788. InitializeObjectAttributes(
  2789. &attributes,
  2790. &filePath,
  2791. OBJ_CASE_INSENSITIVE,
  2792. NULL,
  2793. NULL
  2794. );
  2795. //
  2796. // Attempt to open the signature file.
  2797. //
  2798. ntStatus = ZwCreateFile (
  2799. &fileHandle,
  2800. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  2801. &attributes,
  2802. &ioStatus,
  2803. 0,
  2804. 0,
  2805. 0,
  2806. FILE_OPEN,
  2807. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  2808. NULL,
  2809. 0
  2810. );
  2811. if (NT_SUCCESS(ntStatus)) {
  2812. //
  2813. // Read the drive letter from this signature file, then close it.
  2814. //
  2815. ntStatus = ZwReadFile (
  2816. fileHandle,
  2817. NULL,
  2818. NULL,
  2819. NULL,
  2820. &ioStatus,
  2821. &sigFileDrive,
  2822. sizeof(DWORD),
  2823. NULL,
  2824. NULL
  2825. );
  2826. ZwClose(fileHandle);
  2827. }
  2828. //
  2829. // Print error message if we have a bad status.
  2830. //
  2831. if (!NT_SUCCESS(ntStatus)) {
  2832. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "Could not open win9x signature file %ws [Nt Status: %u (%x)]\n",
  2833. tempBuffer,ntStatus,ntStatus));
  2834. }
  2835. return sigFileDrive == DriveToMatch;
  2836. }
  2837. VOID
  2838. SpAssignOtherDriveLettersToMatchWin9x(
  2839. IN PWIN9XDRIVELETTERINFO Win9xOtherDrives
  2840. )
  2841. {
  2842. PWIN9XDRIVELETTERINFO curDrive;
  2843. if (IsNEC_98) {
  2844. WCHAR openPath[MAX_PATH+1];
  2845. HANDLE fdHandle;
  2846. DWORD numberOfFloppys;
  2847. OBJECT_ATTRIBUTES objectAttributes;
  2848. UNICODE_STRING unicodeString;
  2849. IO_STATUS_BLOCK ioStatusBlock;
  2850. NTSTATUS openStatus;
  2851. NTSTATUS status;
  2852. DWORD index, i;
  2853. PWIN9XDRIVELETTERINFO pOtherDrives[NUMDRIVELETTERS];
  2854. //
  2855. // Encount number of floppy device.
  2856. //
  2857. numberOfFloppys = 0;
  2858. do {
  2859. swprintf(openPath,L"\\device\\floppy%u",numberOfFloppys);
  2860. INIT_OBJA(&objectAttributes,&unicodeString,openPath);
  2861. openStatus = ZwCreateFile(
  2862. &fdHandle,
  2863. SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  2864. &objectAttributes,
  2865. &ioStatusBlock,
  2866. NULL, // allocation size
  2867. FILE_ATTRIBUTE_NORMAL,
  2868. FILE_SHARE_VALID_FLAGS, // full sharing
  2869. FILE_OPEN,
  2870. FILE_SYNCHRONOUS_IO_NONALERT,
  2871. NULL, // no EAs
  2872. 0
  2873. );
  2874. if(NT_SUCCESS(openStatus)) {
  2875. //
  2876. // Increment count of CdRoms and close this handle.
  2877. //
  2878. numberOfFloppys++;
  2879. ZwClose(fdHandle);
  2880. }
  2881. else{
  2882. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open handle to %ws. %u (%x)\n",openPath,openStatus,openStatus));
  2883. }
  2884. } while(numberOfFloppys < NUMDRIVELETTERS && NT_SUCCESS(openStatus));
  2885. //
  2886. // At first, initialize temporary array.
  2887. //
  2888. for (i = 0;i < NUMDRIVELETTERS; i++) {
  2889. pOtherDrives[i] = NULL;
  2890. }
  2891. for (curDrive = Win9xOtherDrives;curDrive;curDrive = curDrive -> Next) {
  2892. pOtherDrives[curDrive -> Drive] = curDrive;
  2893. }
  2894. //
  2895. // Map floppy letter from begining of OtherDrives.
  2896. // On Win9x, floppy letter should be assigned before the other removables.
  2897. //
  2898. index = 0;
  2899. for (i = 0;i < NUMDRIVELETTERS; i++) {
  2900. if (index < numberOfFloppys) {
  2901. if (pOtherDrives[i]) {
  2902. //
  2903. // Need to map the floppys.
  2904. // It will be migrated by ftdisk.sys.
  2905. //
  2906. swprintf(openPath,L"\\device\\floppy%u",index);
  2907. //
  2908. // We use SpDiskRegistryAssignCdRomLetter() for map Floppy Letter too.
  2909. //
  2910. status = SpDiskRegistryAssignCdRomLetter(openPath,
  2911. (WCHAR)((WCHAR) (pOtherDrives[i] -> Drive) + L'A'));
  2912. index++;
  2913. }
  2914. }
  2915. else{
  2916. break;
  2917. }
  2918. }
  2919. }
  2920. for (curDrive = Win9xOtherDrives;curDrive;curDrive = curDrive -> Next) {
  2921. //
  2922. // Simply reserve the drive letter.
  2923. //
  2924. g_DriveLetters[curDrive -> Drive] = TRUE;
  2925. }
  2926. }
  2927. VOID
  2928. SpAssignCdRomDriveLettersToMatchWin9x(
  2929. IN PWIN9XDRIVELETTERINFO Win9xCdRoms
  2930. )
  2931. {
  2932. PWIN9XDRIVELETTERINFO curDrive;
  2933. SCSI_ADDRESS win9xAddress;
  2934. SCSI_ADDRESS ntCdAddresses[NUMDRIVELETTERS];
  2935. BOOL cdMapped[NUMDRIVELETTERS];
  2936. PWSTR curIdPtr;
  2937. WCHAR openPath[MAX_PATH+1];
  2938. HANDLE cdHandle;
  2939. INT numberOfCdRoms;
  2940. OBJECT_ATTRIBUTES objectAttributes;
  2941. UNICODE_STRING unicodeString;
  2942. IO_STATUS_BLOCK ioStatusBlock;
  2943. NTSTATUS openStatus;
  2944. NTSTATUS readStatus;
  2945. NTSTATUS status;
  2946. INT index;
  2947. //
  2948. // Clear out the ntCdDescriptions structure.
  2949. //
  2950. RtlZeroMemory(ntCdAddresses,sizeof(ntCdAddresses));
  2951. RtlZeroMemory(cdMapped,sizeof(cdMapped));
  2952. //
  2953. // gather scsi cdrom data.
  2954. //
  2955. numberOfCdRoms = 0;
  2956. for (index=0, openStatus=STATUS_SUCCESS;
  2957. ((index < NUMDRIVELETTERS) && NT_SUCCESS(openStatus));
  2958. index++) {
  2959. swprintf(openPath,L"\\device\\cdrom%u",index);
  2960. INIT_OBJA(&objectAttributes,&unicodeString,openPath);
  2961. openStatus = ZwCreateFile(
  2962. &cdHandle,
  2963. SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  2964. &objectAttributes,
  2965. &ioStatusBlock,
  2966. NULL, // allocation size
  2967. FILE_ATTRIBUTE_NORMAL,
  2968. FILE_SHARE_VALID_FLAGS, // full sharing
  2969. FILE_OPEN,
  2970. FILE_SYNCHRONOUS_IO_NONALERT,
  2971. NULL, // no EAs
  2972. 0
  2973. );
  2974. if(NT_SUCCESS(openStatus)) {
  2975. //
  2976. // Successfully opened a handle to the device, now, get the address information.
  2977. //
  2978. readStatus = ZwDeviceIoControlFile(
  2979. cdHandle,
  2980. NULL,
  2981. NULL,
  2982. NULL,
  2983. &ioStatusBlock,
  2984. IOCTL_SCSI_GET_ADDRESS,
  2985. NULL,
  2986. 0,
  2987. &(ntCdAddresses[numberOfCdRoms]),
  2988. sizeof(SCSI_ADDRESS)
  2989. );
  2990. if(!NT_SUCCESS(readStatus)) {
  2991. KdPrintEx((DPFLTR_SETUP_ID,
  2992. DPFLTR_ERROR_LEVEL,
  2993. "SETUP: Unable to get scsi address info for cd-rom %u (%x)\n",
  2994. index,
  2995. readStatus));
  2996. }
  2997. //
  2998. // Increment count of CdRoms
  2999. //
  3000. numberOfCdRoms++;
  3001. ZwClose(cdHandle);
  3002. } else {
  3003. KdPrintEx((DPFLTR_SETUP_ID,
  3004. DPFLTR_ERROR_LEVEL,
  3005. "SETUP: Unable to open handle to %ws. (%x)\n",
  3006. openPath,
  3007. openStatus));
  3008. }
  3009. }
  3010. //
  3011. // if we didn't find any CD-ROMs we have nothing to do
  3012. //
  3013. if (!numberOfCdRoms) {
  3014. return;
  3015. }
  3016. //
  3017. // Now, fill in a similar array of win9x drives..
  3018. //
  3019. for (curDrive = Win9xCdRoms;curDrive;curDrive = curDrive -> Next) {
  3020. //
  3021. // assume the drive is not mapped
  3022. //
  3023. curDrive -> StatusFlag = TRUE;
  3024. //
  3025. // Check to see if this is a SCSI device.
  3026. //
  3027. if (curDrive -> Identifier) {
  3028. curIdPtr = (PWSTR) curDrive -> Identifier;
  3029. //
  3030. // Collect the Win9x Address data.
  3031. //
  3032. win9xAddress.PortNumber = (UCHAR) Spwtoi(curIdPtr);
  3033. curIdPtr = wcschr(curIdPtr,L'^');
  3034. curIdPtr++;
  3035. win9xAddress.TargetId = (UCHAR) Spwtoi(curIdPtr);
  3036. curIdPtr = wcschr(curIdPtr,L'^');
  3037. curIdPtr++;
  3038. win9xAddress.Lun = (UCHAR) Spwtoi(curIdPtr);
  3039. //
  3040. // Now, loop through SCSI CD-Roms until a matching one is found.
  3041. //
  3042. for (index = 0; index < numberOfCdRoms; index++) {
  3043. if(!ntCdAddresses[index].Length){
  3044. continue;
  3045. }
  3046. if (win9xAddress.PortNumber == ntCdAddresses[index].PortNumber &&
  3047. win9xAddress.TargetId == ntCdAddresses[index].TargetId &&
  3048. win9xAddress.Lun == ntCdAddresses[index].Lun) {
  3049. if (cdMapped[index]) {
  3050. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error: \\device\\cdrom%u already mapped..ignored.\n",index));
  3051. }
  3052. //
  3053. // Map the cdrom.
  3054. //
  3055. swprintf(openPath,L"\\device\\cdrom%u",index);
  3056. status = SpDiskRegistryAssignCdRomLetter(openPath,
  3057. (WCHAR) ((WCHAR) (curDrive -> Drive) + L'A'));
  3058. ASSERT(curDrive->Drive < NUMDRIVELETTERS);
  3059. g_DriveLetters[curDrive -> Drive] = TRUE;
  3060. cdMapped[index] = TRUE;
  3061. curDrive -> StatusFlag = FALSE;
  3062. break;
  3063. }
  3064. }
  3065. } else {
  3066. curDrive -> StatusFlag = TRUE;
  3067. }
  3068. }
  3069. index = numberOfCdRoms - 1;
  3070. for (curDrive = Win9xCdRoms;curDrive;curDrive = curDrive -> Next) {
  3071. //
  3072. // If we haven't found a direct map yet, we'll any remaining drives.. This fixes the
  3073. // single IDE cdrom case. It could result in some reordering in multiple IDE CDRom
  3074. // systems. Still, this is the best we can do here.
  3075. //
  3076. if (curDrive -> StatusFlag) {
  3077. while (index >= 0 && cdMapped[index] == TRUE) {
  3078. index--;
  3079. }
  3080. if (index < 0){
  3081. break;
  3082. }
  3083. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Forcing Win9x CDRom Mapping for \\device\\cdrom%u, even though a direct match was not found.\n",index));
  3084. swprintf(openPath,L"\\device\\cdrom%u",index);
  3085. status = SpDiskRegistryAssignCdRomLetter(openPath,
  3086. (WCHAR) ((WCHAR) (curDrive -> Drive) + L'A'));
  3087. g_DriveLetters[curDrive -> Drive] = TRUE;
  3088. cdMapped[index] = TRUE;
  3089. index--;
  3090. }
  3091. }
  3092. }
  3093. VOID
  3094. SpAssignHardDriveLettersToMatchWin9x (
  3095. IN PWIN9XDRIVELETTERINFO Win9xHardDrives
  3096. )
  3097. {
  3098. PWIN9XDRIVELETTERINFO win9xDrive;
  3099. DWORD diskIndex;
  3100. PDISK_REGION region;
  3101. PPARTITIONED_DISK disk;
  3102. DWORD numMatchingRegions;
  3103. PDISK_REGION matchingRegion;
  3104. //
  3105. // Clear all partition drive letter informations.
  3106. // Note: This was copypasted from sppartit.c:SpGuessDriveLetters()
  3107. //
  3108. for(diskIndex=0; diskIndex<HardDiskCount; diskIndex++) {
  3109. for(region=PartitionedDisks[diskIndex].PrimaryDiskRegions; region; region=region->Next) {
  3110. region->DriveLetter = 0;
  3111. }
  3112. for(region=PartitionedDisks[diskIndex].ExtendedDiskRegions; region; region=region->Next) {
  3113. region->DriveLetter = 0;
  3114. }
  3115. }
  3116. //
  3117. // Iterate through the drives found in the winnt.sif file.
  3118. //
  3119. for (win9xDrive = Win9xHardDrives; win9xDrive; win9xDrive = win9xDrive -> Next) {
  3120. //
  3121. // find the partition that matches that drive.
  3122. //
  3123. numMatchingRegions = 0;
  3124. matchingRegion = NULL;
  3125. for(diskIndex=0; diskIndex<HardDiskCount; diskIndex++) {
  3126. disk = &PartitionedDisks[diskIndex];
  3127. //
  3128. // First, search through primary disk regions.
  3129. //
  3130. region = SpFirstPartitionedRegion(PartitionedDisks[diskIndex].PrimaryDiskRegions, TRUE);
  3131. while(region) {
  3132. if (SpCheckRegionForMatchWithWin9xData(region,win9xDrive -> Drive)) {
  3133. if (!matchingRegion) {
  3134. matchingRegion = region;
  3135. }
  3136. numMatchingRegions++;
  3137. }
  3138. region = SpNextPartitionedRegion(region, TRUE);
  3139. }
  3140. //
  3141. // Then, search through secondary disk regions.
  3142. //
  3143. region = SpFirstPartitionedRegion(PartitionedDisks[diskIndex].PrimaryDiskRegions, FALSE);
  3144. while(region) {
  3145. if (SpCheckRegionForMatchWithWin9xData(region,win9xDrive -> Drive)) {
  3146. if (!matchingRegion) {
  3147. matchingRegion = region;
  3148. }
  3149. numMatchingRegions++;
  3150. }
  3151. region = SpNextPartitionedRegion(region, FALSE);
  3152. }
  3153. }
  3154. if (numMatchingRegions == 1) {
  3155. //
  3156. // Found what we were looking for. Assign the win9x Drive letter
  3157. // to this region.
  3158. //
  3159. matchingRegion -> DriveLetter = L'A' + (WCHAR) win9xDrive -> Drive;
  3160. ASSERT(win9xDrive->Drive < NUMDRIVELETTERS);
  3161. g_DriveLetters[win9xDrive -> Drive] = TRUE;
  3162. }
  3163. else if (numMatchingRegions > 1) {
  3164. //
  3165. // We are in trouble. print an error.
  3166. //
  3167. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: More than one drive matches Win9x drive.\n"));
  3168. } else {
  3169. //
  3170. // Big trouble. No regions matched the data collected on Windows 95.
  3171. //
  3172. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Could not find a drive matching Win9x.\n"));
  3173. }
  3174. }
  3175. }
  3176. VOID
  3177. SpRegisterHardDriveLetters (
  3178. VOID
  3179. )
  3180. {
  3181. BOOL rf;
  3182. PDISK_REGION curRegion;
  3183. BOOL wasExtended;
  3184. DWORD diskIndex;
  3185. PPARTITIONED_DISK disk;
  3186. LARGE_INTEGER startingOffset;
  3187. LARGE_INTEGER length;
  3188. UCHAR driveLetter;
  3189. for(diskIndex=0; diskIndex<HardDiskCount; diskIndex++) {
  3190. disk = &PartitionedDisks[diskIndex];
  3191. //
  3192. // Skip removable media. If a disk is off-line it's hard to imagine
  3193. // that we'll actually have any partitioned spaces on it so
  3194. // we don't do any special checks here for that condition.
  3195. //
  3196. if(!(disk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA)) {
  3197. //
  3198. // First, do all of the primary disk regions for this disk.
  3199. //
  3200. curRegion = SpFirstPartitionedRegion(PartitionedDisks[diskIndex].PrimaryDiskRegions, TRUE);
  3201. while(curRegion) {
  3202. //
  3203. // We only care about partitioned spaces that have drive letters.
  3204. //
  3205. if(curRegion->PartitionedSpace && curRegion -> DriveLetter) {
  3206. //
  3207. // Collect information needed for call to DiskRegistryAssignDriveLetter
  3208. //
  3209. SpGetPartitionStartingOffsetAndLength(
  3210. diskIndex,
  3211. curRegion,
  3212. FALSE,
  3213. &startingOffset,
  3214. &length
  3215. );
  3216. driveLetter = (UCHAR) ('A' + (curRegion -> DriveLetter - L'A'));
  3217. rf = SpDiskRegistryAssignDriveLetter(
  3218. disk -> HardDisk -> Signature,
  3219. startingOffset,
  3220. length,
  3221. driveLetter
  3222. );
  3223. if (!rf) {
  3224. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DiskRegistryAssignDriveLetter call failed.\n"));
  3225. }
  3226. else {
  3227. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Added sticky letter %c to Disk Registry.\n",driveLetter));
  3228. }
  3229. }
  3230. curRegion = SpNextPartitionedRegion(curRegion, TRUE);
  3231. }
  3232. //
  3233. // Now, do all of the extended disk regions.
  3234. //
  3235. curRegion = SpFirstPartitionedRegion(PartitionedDisks[diskIndex].PrimaryDiskRegions, FALSE);
  3236. while(curRegion) {
  3237. //
  3238. // We only care about partitioned spaces that have drive letters.
  3239. //
  3240. if(curRegion->PartitionedSpace && curRegion -> DriveLetter) {
  3241. //
  3242. // Collect information needed for call to DiskRegistryAssignDriveLetter
  3243. //
  3244. SpGetPartitionStartingOffsetAndLength(
  3245. diskIndex,
  3246. curRegion,
  3247. TRUE,
  3248. &startingOffset,
  3249. &length
  3250. );
  3251. driveLetter = (UCHAR) ('A' + (curRegion -> DriveLetter - L'A'));
  3252. rf = SpDiskRegistryAssignDriveLetter(
  3253. disk -> HardDisk -> Signature,
  3254. startingOffset,
  3255. length,
  3256. driveLetter
  3257. );
  3258. if (!rf) {
  3259. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DiskRegistryAssignDriveLetter call failed.\n"));
  3260. }
  3261. else {
  3262. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Added sticky letter %c to Disk Registry.\n",driveLetter));
  3263. }
  3264. }
  3265. curRegion = SpNextPartitionedRegion(curRegion, FALSE);
  3266. }
  3267. }
  3268. }
  3269. }
  3270. #define WIN9XHARDDRIVES 0
  3271. #define WIN9XCDROMS 1
  3272. #define WIN9XOTHERS 2
  3273. #define WIN9XNUMDRIVETYPES 3
  3274. VOID
  3275. SpAssignDriveLettersToMatchWin9x (
  3276. IN PVOID WinntSif
  3277. )
  3278. {
  3279. PWIN9XDRIVELETTERINFO win9xDrive = NULL;
  3280. PWIN9XDRIVELETTERINFO win9xDrives[WIN9XNUMDRIVETYPES];
  3281. DWORD index;
  3282. DWORD lineCount;
  3283. PWSTR driveString;
  3284. PWSTR dataString;
  3285. PWSTR curString;
  3286. DWORD drive;
  3287. DWORD type;
  3288. DWORD driveType;
  3289. //
  3290. // Read in the data on hard disks that was collected during the Detection
  3291. // phase of Win95 setup. This data is stored in the winnt.sif file
  3292. // in the [Win9x.DriveLetterInfo] section.
  3293. lineCount = SpCountLinesInSection(WinntSif,WINNT_D_WIN9XDRIVES_W);
  3294. if (!lineCount) {
  3295. //
  3296. // No information in the winnt.sif file, so nothing to do. Get out of here early.
  3297. //
  3298. return;
  3299. }
  3300. //
  3301. // build Disk Registry information. This will be used to store
  3302. // sticky drive letters.
  3303. //
  3304. SpBuildDiskRegistry();
  3305. //
  3306. // Build a list of usable drive letters. All drive letters should be
  3307. // initially usable exceptr for 'A' and 'B'
  3308. // For NEC98, hard drive letter usually assigned from 'A'.
  3309. // So we don't set TRUE in that case.
  3310. //
  3311. RtlZeroMemory(g_DriveLetters,sizeof(g_DriveLetters));
  3312. if( !IsNEC_98 || !DriveAssignFromA) {
  3313. g_DriveLetters[0] = g_DriveLetters[1] = TRUE;
  3314. }
  3315. RtlZeroMemory(win9xDrives,sizeof(win9xDrives));
  3316. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Win9x Drive Letters to map: %u\n", lineCount));
  3317. for (index = 0;index < lineCount; index++) {
  3318. //
  3319. // The Drive Number is in the key.
  3320. //
  3321. driveString = SpGetKeyName (
  3322. WinntSif,
  3323. WINNT_D_WIN9XDRIVES_W,
  3324. index
  3325. );
  3326. //
  3327. // This conditional _should_ always be true. but, just in case..
  3328. //
  3329. if (driveString) {
  3330. drive = Spwtoi(driveString);
  3331. //
  3332. // Now, get the type of this drive.
  3333. //
  3334. dataString = SpGetSectionKeyIndex (
  3335. WinntSif,
  3336. WINNT_D_WIN9XDRIVES_W,
  3337. driveString,
  3338. 0
  3339. );
  3340. if (dataString) {
  3341. curString = dataString;
  3342. if (*curString != L',') {
  3343. type = Spwtoi(curString);
  3344. }
  3345. //
  3346. // Advance dataString to the start of the identifier string.
  3347. //
  3348. curString = wcschr(curString,L',');
  3349. if (curString) {
  3350. //
  3351. // Pass the ','
  3352. //
  3353. *curString++;
  3354. }
  3355. }
  3356. else {
  3357. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Could not retrieve type for Win9x drive %ws\n",driveString));
  3358. type = DOSDEVICE_DRIVE_UNKNOWN;
  3359. }
  3360. //
  3361. // Now, add this drive to the list of win9x drives that we are
  3362. // dealing with.
  3363. //
  3364. win9xDrive = SpMemAlloc(sizeof(WIN9XDRIVELETTERINFO));
  3365. if (win9xDrive) {
  3366. //
  3367. // assign all of the gathered data.
  3368. //
  3369. win9xDrive -> Drive = drive;
  3370. win9xDrive -> Type = type;
  3371. win9xDrive -> Identifier = curString;
  3372. //
  3373. // place this drive into the list of drives of its type.
  3374. //
  3375. switch (type) {
  3376. case DOSDEVICE_DRIVE_FIXED:
  3377. driveType = WIN9XHARDDRIVES;
  3378. break;
  3379. case DOSDEVICE_DRIVE_CDROM:
  3380. driveType = WIN9XCDROMS;
  3381. break;
  3382. default:
  3383. driveType = WIN9XOTHERS;
  3384. break;
  3385. }
  3386. win9xDrive -> Next = win9xDrives[driveType];
  3387. win9xDrives[driveType] = win9xDrive;
  3388. }
  3389. else {
  3390. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Could not allocate memory for Win9x drive letter information.\n"));
  3391. //
  3392. // No use sticking around.
  3393. //
  3394. goto c0;
  3395. }
  3396. }
  3397. else {
  3398. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Could not find drive string in winnt.sif line.\n"));
  3399. goto c0;
  3400. }
  3401. }
  3402. //
  3403. // First, and most importantly, assign the drive letters for hard disks.
  3404. // If this is done incorrectly, setup may fail.
  3405. //
  3406. if (win9xDrives[WIN9XHARDDRIVES]) {
  3407. SpAssignHardDriveLettersToMatchWin9x (win9xDrives[WIN9XHARDDRIVES]);
  3408. }
  3409. //
  3410. // Secondly, assign drive letters for any CD-Roms.
  3411. //
  3412. if (win9xDrives[WIN9XCDROMS]) {
  3413. SpAssignCdRomDriveLettersToMatchWin9x(win9xDrives[WIN9XCDROMS]);
  3414. }
  3415. //
  3416. // Third, if possible, assign drive letters for other devices.
  3417. //
  3418. if (win9xDrives[WIN9XOTHERS]) {
  3419. SpAssignOtherDriveLettersToMatchWin9x(win9xDrives[WIN9XOTHERS]);
  3420. }
  3421. //
  3422. // Assign drive letters for any HDD partitions that have not been
  3423. // previously mapped. (These are drives unknown to Win9x.)
  3424. //
  3425. SpAssignDriveLettersToRemainingPartitions();
  3426. //
  3427. // Now, write all hard drive information into the disk registry.
  3428. //
  3429. SpRegisterHardDriveLetters();
  3430. c0:
  3431. ;
  3432. }
  3433. VOID
  3434. SpWin9xOverrideGuiModeCodePage (
  3435. HKEY NlsRegKey
  3436. )
  3437. {
  3438. PWSTR data;
  3439. NTSTATUS status;
  3440. WCHAR fileName[MAX_PATH];
  3441. data = SpGetSectionKeyIndex (
  3442. WinntSifHandle,
  3443. SIF_DATA,
  3444. WINNT_D_GUICODEPAGEOVERRIDE_W,
  3445. 0
  3446. );
  3447. if (!data) {
  3448. //
  3449. // Nothing to do.
  3450. //
  3451. return;
  3452. }
  3453. if(ARRAYSIZE(fileName) < (wcslen(data) + ARRAYSIZE(L"c_.nls"))){
  3454. return;
  3455. }
  3456. wcscpy (fileName, L"c_");
  3457. wcscat (fileName, data);
  3458. wcscat (fileName, L".nls");
  3459. status = SpOpenSetValueAndClose (NlsRegKey, L"CodePage", data, STRING_VALUE(fileName));
  3460. if(!NT_SUCCESS(status)) {
  3461. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "Setup: Unable to override the code page for GUI mode. Some strings may be incorrect.\n"));
  3462. return;
  3463. }
  3464. status = SpOpenSetValueAndClose (NlsRegKey, L"CodePage", L"Acp", STRING_VALUE(data));
  3465. if(!NT_SUCCESS(status)) {
  3466. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "Setup: Unable to override the ACP for GUI mode. Some strings may be incorrect.\n"));
  3467. return;
  3468. }
  3469. }
  3470. BOOLEAN
  3471. SpIsWindowsUpgrade(
  3472. IN PVOID SifFileHandle
  3473. )
  3474. /*++
  3475. Routine Description:
  3476. Determines whether we are upgrading Windows 3.x or Windows 9x.
  3477. Arguments:
  3478. SifFileHandle : Handle to WINNT.SIF file which has
  3479. the appropriate 3.x/9x upgrade flag value
  3480. Return Value:
  3481. TRUE : if upgrading Windows 3.x or 9X
  3482. FALSE : otherwise
  3483. --*/
  3484. {
  3485. BOOLEAN Result = FALSE;
  3486. PWSTR Value = 0;
  3487. Value = SpGetSectionKeyIndex(SifFileHandle, SIF_DATA,
  3488. WINNT_D_WIN95UPGRADE_W, 0);
  3489. if (!Value) {
  3490. Value = SpGetSectionKeyIndex(SifFileHandle, SIF_DATA,
  3491. WINNT_D_WIN31UPGRADE_W, 0);
  3492. }
  3493. if (Value)
  3494. Result = (_wcsicmp(Value, WINNT_A_YES_W) == 0);
  3495. return Result;
  3496. }