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.

1852 lines
54 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. fileops.c
  5. Abstract:
  6. Miscellaneous file operations.
  7. Entry points:
  8. Delnode
  9. Author:
  10. Ted Miller (tedm) 5-Apr-1995
  11. Revision History:
  12. --*/
  13. #include "setupp.h"
  14. //
  15. // This include is needed for ValidateAndChecksumFile()
  16. //
  17. #include <imagehlp.h>
  18. #include <shlwapi.h>
  19. #pragma hdrstop
  20. VOID
  21. pSetInstallAttributes(
  22. VOID
  23. )
  24. /*++
  25. Routine Description:
  26. Set default attributes on a huge list of files. The shell
  27. had been doing this, but it's probably better to do it here
  28. so that the the user doesn't have his attributes reset everytime
  29. he logs in.
  30. Arguments:
  31. None.
  32. Return Value:
  33. None.
  34. --*/
  35. {
  36. #define _R (FILE_ATTRIBUTE_READONLY)
  37. #define _S (FILE_ATTRIBUTE_SYSTEM)
  38. #define _H (FILE_ATTRIBUTE_HIDDEN)
  39. #define _SH (_S | _H)
  40. #define _SHR (_S | _H | _R)
  41. struct {
  42. WCHAR FileName[20];
  43. BOOL DeleteIfEmpty;
  44. DWORD Attributes;
  45. } FilesToFix[] = {
  46. // { L"X:\\autoexec.bat", TRUE, _H }, 16bit apps break if hidden: jarbats bug148787
  47. { L"X:\\autoexec.000", TRUE, _SH },
  48. { L"X:\\autoexec.old", TRUE, _SH },
  49. { L"X:\\autoexec.bak", TRUE, _SH },
  50. { L"X:\\autoexec.dos", TRUE, _SH },
  51. { L"X:\\autoexec.win", TRUE, _SH },
  52. // { L"X:\\config.sys", TRUE, _H }, 16bit apps break if hidden: jarbats bug 148787
  53. { L"X:\\config.dos", TRUE, _SH },
  54. { L"X:\\config.win", TRUE, _SH },
  55. { L"X:\\command.com", FALSE, _SH },
  56. { L"X:\\command.dos", FALSE, _SH },
  57. { L"X:\\logo.sys", FALSE, _SH },
  58. { L"X:\\msdos.---", FALSE, _SH }, // Win9x backup of msdos.*
  59. { L"X:\\boot.ini", FALSE, _SH },
  60. { L"X:\\boot.bak", FALSE, _SH },
  61. { L"X:\\boot.---", FALSE, _SH },
  62. { L"X:\\bootsect.dos", FALSE, _SH },
  63. { L"X:\\bootlog.txt", FALSE, _SH }, // Win9x first boot log
  64. { L"X:\\bootlog.prv", FALSE, _SH },
  65. { L"X:\\ffastun.ffa", FALSE, _SH }, // Office 97 only used hidden, O2K uses SH
  66. { L"X:\\ffastun.ffl", FALSE, _SH },
  67. { L"X:\\ffastun.ffx", FALSE, _SH },
  68. { L"X:\\ffastun0.ffx", FALSE, _SH },
  69. { L"X:\\ffstunt.ffl", FALSE, _SH },
  70. { L"X:\\sms.ini", FALSE, _SH }, // SMS
  71. { L"X:\\sms.new", FALSE, _SH },
  72. { L"X:\\sms_time.dat", FALSE, _SH },
  73. { L"X:\\smsdel.dat", FALSE, _SH },
  74. { L"X:\\mpcsetup.log", FALSE, _H }, // Microsoft Proxy Server
  75. { L"X:\\detlog.txt", FALSE, _SH }, // Win9x PNP detection log
  76. { L"X:\\detlog.old", FALSE, _SH }, // Win9x PNP detection log
  77. { L"X:\\setuplog.txt", FALSE, _SH }, // Win9x setup log
  78. { L"X:\\setuplog.old", FALSE, _SH }, // Win9x setup log
  79. { L"X:\\suhdlog.dat", FALSE, _SH }, // Win9x setup log
  80. { L"X:\\suhdlog.---", FALSE, _SH }, // Win9x setup log
  81. { L"X:\\suhdlog.bak", FALSE, _SH }, // Win9x setup log
  82. { L"X:\\system.1st", FALSE, _SH }, // Win95 system.dat backup
  83. { L"X:\\netlog.txt", FALSE, _SH }, // Win9x network setup log file
  84. { L"X:\\setup.aif", FALSE, _SH }, // NT4 unattended setup script
  85. { L"X:\\catlog.wci", FALSE, _H }, // index server folder
  86. { L"X:\\cmsstorage.lst", FALSE, _SH }, // Microsoft Media Manager
  87. };
  88. WCHAR szWinDir[MAX_PATH];
  89. DWORD i, j;
  90. DWORD Result;
  91. //
  92. // Get the drive letter that we installed on.
  93. //
  94. Result = GetWindowsDirectory(szWinDir, MAX_PATH);
  95. if( Result == 0) {
  96. MYASSERT(FALSE);
  97. return;
  98. }
  99. for( i = 0; i < (sizeof(FilesToFix)/sizeof(FilesToFix[0])); i++ ) {
  100. //
  101. // First we need to fixup the path. This is really gross, but lots
  102. // of these files will be on the system partition and lots will be
  103. // on the partition where we installed, which may not be the same.
  104. // Rather than figuring out which of these live on which partition
  105. // and ensuring that this is true for all flavors of NT, just
  106. // process both locations.
  107. //
  108. for( j = 0; j < 2; j++ ) {
  109. if( j & 1 ) {
  110. FilesToFix[i].FileName[0] = szWinDir[0];
  111. } else {
  112. #if defined(_AMD64_) || defined(_X86_)
  113. FilesToFix[i].FileName[0] = x86SystemPartitionDrive;
  114. #else
  115. FilesToFix[i].FileName[0] = L'C';
  116. #endif
  117. }
  118. //
  119. // Now set the attributes.
  120. //
  121. SetFileAttributes( FilesToFix[i].FileName, FilesToFix[i].Attributes );
  122. }
  123. }
  124. }
  125. DWORD
  126. TreeCopy(
  127. IN PCWSTR SourceDir,
  128. IN PCWSTR TargetDir
  129. )
  130. {
  131. DWORD d;
  132. WCHAR Pattern[MAX_PATH];
  133. WCHAR NewTarget[MAX_PATH];
  134. WIN32_FIND_DATA FindData;
  135. HANDLE FindHandle;
  136. //
  137. // First create the target directory if it doesn't already exist.
  138. //
  139. if(!CreateDirectory(TargetDir,NULL)) {
  140. d = GetLastError();
  141. if(d != ERROR_ALREADY_EXISTS) {
  142. return(d);
  143. }
  144. }
  145. //
  146. // Copy each file in the source directory to the target directory.
  147. // If any directories are encountered along the way recurse to copy them
  148. // as they are encountered.
  149. //
  150. // Start by forming the search pattern, which is <sourcedir>\*.
  151. //
  152. lstrcpyn(Pattern,SourceDir,MAX_PATH);
  153. pSetupConcatenatePaths(Pattern,L"*",MAX_PATH,NULL);
  154. //
  155. // Start the search.
  156. //
  157. FindHandle = FindFirstFile(Pattern,&FindData);
  158. if(FindHandle == INVALID_HANDLE_VALUE) {
  159. d = NO_ERROR;
  160. } else {
  161. do {
  162. //
  163. // Form the full name of the file or directory we just found
  164. // as well as its name in the target.
  165. //
  166. lstrcpyn(Pattern,SourceDir,MAX_PATH);
  167. pSetupConcatenatePaths(Pattern,FindData.cFileName,MAX_PATH,NULL);
  168. lstrcpyn(NewTarget,TargetDir,MAX_PATH);
  169. pSetupConcatenatePaths(NewTarget,FindData.cFileName,MAX_PATH,NULL);
  170. if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  171. //
  172. // The current match is a directory. Recurse into it unless
  173. // it's . or ...
  174. //
  175. if(lstrcmp(FindData.cFileName,TEXT("." )) && lstrcmp(FindData.cFileName,TEXT(".."))) {
  176. d = TreeCopy(Pattern,NewTarget);
  177. } else {
  178. d = NO_ERROR;
  179. }
  180. } else {
  181. //
  182. // The current match is not a directory -- so copy it.
  183. //
  184. SetFileAttributes(NewTarget,FILE_ATTRIBUTE_NORMAL);
  185. d = CopyFile(Pattern,NewTarget,FALSE) ? NO_ERROR : GetLastError();
  186. }
  187. } while((d==NO_ERROR) && FindNextFile(FindHandle,&FindData));
  188. FindClose(FindHandle);
  189. }
  190. return(d);
  191. }
  192. VOID
  193. DelSubNodes(
  194. IN PCWSTR Directory
  195. )
  196. {
  197. WCHAR Pattern[MAX_PATH];
  198. WIN32_FIND_DATA FindData;
  199. HANDLE FindHandle;
  200. //
  201. // Delete each file in the given directory, but DO NOT remove the directory itself.
  202. // If any directories are encountered along the way recurse to delete them
  203. // as they are encountered.
  204. //
  205. // Start by forming the search pattern, which is <currentdir>\*.
  206. //
  207. lstrcpyn(Pattern,Directory,MAX_PATH);
  208. pSetupConcatenatePaths(Pattern,L"*",MAX_PATH,NULL);
  209. //
  210. // Start the search.
  211. //
  212. FindHandle = FindFirstFile(Pattern,&FindData);
  213. if(FindHandle != INVALID_HANDLE_VALUE) {
  214. do {
  215. //
  216. // Form the full name of the file or directory we just found.
  217. //
  218. lstrcpyn(Pattern,Directory,MAX_PATH);
  219. pSetupConcatenatePaths(Pattern,FindData.cFileName,MAX_PATH,NULL);
  220. //
  221. // Remove read-only atttribute if it's there.
  222. //
  223. if(FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
  224. SetFileAttributes(Pattern,FILE_ATTRIBUTE_NORMAL);
  225. }
  226. if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  227. //
  228. // The current match is a directory. Recurse into it unless
  229. // it's . or ...
  230. //
  231. if(lstrcmp(FindData.cFileName,TEXT("." )) && lstrcmp(FindData.cFileName,TEXT(".."))) {
  232. Delnode(Pattern);
  233. }
  234. } else {
  235. //
  236. // The current match is not a directory -- so delete it.
  237. //
  238. if(!DeleteFile(Pattern)) {
  239. SetuplogError(
  240. LogSevWarning,
  241. SETUPLOG_USE_MESSAGEID,
  242. MSG_LOG_DELNODE_FAIL,
  243. Pattern, NULL,
  244. SETUPLOG_USE_MESSAGEID,
  245. MSG_LOG_X_PARAM_RETURNED_WINERR,
  246. szDeleteFile,
  247. GetLastError(),
  248. Pattern,
  249. NULL,NULL);
  250. }
  251. }
  252. } while(FindNextFile(FindHandle,&FindData));
  253. FindClose(FindHandle);
  254. }
  255. }
  256. VOID
  257. Delnode(
  258. IN PCWSTR Directory
  259. )
  260. {
  261. WCHAR Pattern[MAX_PATH];
  262. WIN32_FIND_DATA FindData;
  263. HANDLE FindHandle;
  264. //
  265. // Delete each file in the given directory, then remove the directory itself.
  266. // If any directories are encountered along the way recurse to delete them
  267. // as they are encountered.
  268. //
  269. // Start by forming the search pattern, which is <currentdir>\*.
  270. //
  271. lstrcpyn(Pattern,Directory,MAX_PATH);
  272. pSetupConcatenatePaths(Pattern,L"*",MAX_PATH,NULL);
  273. //
  274. // Start the search.
  275. //
  276. FindHandle = FindFirstFile(Pattern,&FindData);
  277. if(FindHandle != INVALID_HANDLE_VALUE) {
  278. do {
  279. //
  280. // Form the full name of the file or directory we just found.
  281. //
  282. lstrcpyn(Pattern,Directory,MAX_PATH);
  283. pSetupConcatenatePaths(Pattern,FindData.cFileName,MAX_PATH,NULL);
  284. //
  285. // Remove read-only atttribute if it's there.
  286. //
  287. if(FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
  288. SetFileAttributes(Pattern,FILE_ATTRIBUTE_NORMAL);
  289. }
  290. if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  291. if( (FindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
  292. if( !RemoveDirectory(Pattern)) {
  293. SetuplogError(
  294. LogSevWarning,
  295. SETUPLOG_USE_MESSAGEID,
  296. MSG_LOG_DELNODE_FAIL,
  297. Pattern, NULL,
  298. SETUPLOG_USE_MESSAGEID,
  299. MSG_LOG_X_PARAM_RETURNED_WINERR,
  300. szRemoveDirectory,
  301. GetLastError(),
  302. Pattern,
  303. NULL,NULL);
  304. }
  305. } else {
  306. //
  307. // The current match is a directory. Recurse into it unless
  308. // it's . or ...
  309. //
  310. if(lstrcmp(FindData.cFileName,TEXT("." )) && lstrcmp(FindData.cFileName,TEXT(".."))) {
  311. Delnode(Pattern);
  312. }
  313. }
  314. } else {
  315. //
  316. // The current match is not a directory -- so delete it.
  317. //
  318. if(!DeleteFile(Pattern)) {
  319. SetuplogError(
  320. LogSevWarning,
  321. SETUPLOG_USE_MESSAGEID,
  322. MSG_LOG_DELNODE_FAIL,
  323. Pattern, NULL,
  324. SETUPLOG_USE_MESSAGEID,
  325. MSG_LOG_X_PARAM_RETURNED_WINERR,
  326. szDeleteFile,
  327. GetLastError(),
  328. Pattern,
  329. NULL,NULL);
  330. }
  331. }
  332. } while(FindNextFile(FindHandle,&FindData));
  333. FindClose(FindHandle);
  334. }
  335. //
  336. // Remove the directory we just emptied out. Ignore errors.
  337. //
  338. SetFileAttributes(Directory,FILE_ATTRIBUTE_NORMAL);
  339. RemoveDirectory(Directory);
  340. }
  341. VOID
  342. RemoveServicePackEntries(
  343. HKEY hKey
  344. )
  345. /*
  346. This routine takes in the Handle to the Software\Microsoft\Windows NT\CurrentVersion\Hotfix\ServicePackUninstall
  347. key and then enumerates each value entry under it.
  348. It then takes the value data and appends that to the
  349. "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" and delnodes that key. This
  350. way we have an extensible mechanism to always cleanup the Uninstall keys for ServicePacks.
  351. */
  352. {
  353. #define UNINSTALLKEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
  354. #define UNINSTALLKEYLEN (sizeof(UNINSTALLKEY) / sizeof(WCHAR) - 1)
  355. DWORD Status,MaxValueName=0,MaxValue=0,Values=0,i;
  356. DWORD TempMaxNameSize, TempMaxDataSize;
  357. PWSTR ValueName, ValueData;
  358. Status = RegQueryInfoKey( hKey,
  359. NULL,
  360. NULL,
  361. NULL,
  362. NULL,
  363. NULL,
  364. NULL,
  365. &Values,
  366. &MaxValueName,
  367. &MaxValue,
  368. NULL,
  369. NULL );
  370. //Account forterminating null
  371. if( Status == ERROR_SUCCESS ){
  372. MaxValueName += 2;
  373. MaxValue = MaxValue + 2 + lstrlen(UNINSTALLKEY);
  374. ValueName = MyMalloc( MaxValueName * sizeof(WCHAR) );
  375. ValueData = MyMalloc( MaxValue * sizeof(WCHAR) );
  376. if( !ValueName || !ValueData )
  377. return;
  378. lstrcpy( ValueData, UNINSTALLKEY );
  379. for (i=0; i < Values; i++){
  380. TempMaxNameSize = MaxValueName;
  381. TempMaxDataSize = MaxValue;
  382. Status = RegEnumValue( hKey,
  383. i,
  384. ValueName,
  385. &TempMaxNameSize,
  386. NULL,
  387. NULL,
  388. (LPBYTE)(ValueData+lstrlen(UNINSTALLKEY)),
  389. &TempMaxDataSize
  390. );
  391. // Don't do delnode if valuedata is null
  392. if( Status == ERROR_SUCCESS && ValueData[lstrlen(UNINSTALLKEY)] ){
  393. pSetupRegistryDelnode( HKEY_LOCAL_MACHINE, ValueData );
  394. }
  395. }
  396. }
  397. MyFree( ValueName );
  398. MyFree( ValueData );
  399. return;
  400. }
  401. VOID
  402. RemoveHotfixData(
  403. VOID
  404. )
  405. {
  406. WCHAR Path[MAX_PATH];
  407. WCHAR KBNumber[64];
  408. WCHAR UninstallKey[MAX_PATH];
  409. DWORD i = 0;
  410. DWORD prefixSize = 0;
  411. DWORD Status, SubKeys;
  412. HKEY hKey, SvcPckKey;
  413. REGVALITEM SoftwareKeyItems[1];
  414. //
  415. //For each hotfix, the registry info is stored under
  416. // HKLM\Software\Microsoft\Windows NT\CurrentVersion\Hotfix\<KB#>
  417. // and the files are stored under
  418. // %windir%\$NtUninstall<KB#>$
  419. //
  420. //Enumerate the hotfix key and remove the files and registry entries for each hotfix.
  421. //
  422. #define HOTFIXAPPKEY L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix"
  423. Status = RegOpenKey(HKEY_LOCAL_MACHINE, HOTFIXAPPKEY, &hKey);
  424. if( Status != ERROR_SUCCESS ) {
  425. return;
  426. }
  427. Status = RegQueryInfoKey( hKey,
  428. NULL,
  429. NULL,
  430. NULL,
  431. &SubKeys,
  432. NULL,
  433. NULL,
  434. NULL,
  435. NULL,
  436. NULL,
  437. NULL,
  438. NULL );
  439. if(Status == ERROR_SUCCESS) {
  440. Status = GetWindowsDirectory(Path, MAX_PATH);
  441. if(Status == 0) {
  442. MYASSERT(FALSE);
  443. return;
  444. }
  445. pSetupConcatenatePaths(Path,L"$NtUninstall",MAX_PATH,&prefixSize);
  446. lstrcpy(UninstallKey, UNINSTALLKEY);
  447. for( i = 0; i < SubKeys; i++ ) {
  448. Status = RegEnumKey(hKey, i, KBNumber, sizeof(KBNumber) / sizeof(KBNumber[0]));
  449. if (Status == ERROR_SUCCESS) {
  450. if( !lstrcmpi( KBNumber, TEXT("ServicePackUninstall") ) ){
  451. Status = RegOpenKey(hKey,KBNumber,&SvcPckKey);
  452. if( Status == ERROR_SUCCESS ){
  453. RemoveServicePackEntries(SvcPckKey);
  454. RegCloseKey(SvcPckKey);
  455. }
  456. }else{
  457. lstrcpyn(Path + prefixSize - 1, KBNumber, MAX_PATH - prefixSize);
  458. lstrcat(Path, L"$");
  459. Delnode(Path);
  460. //
  461. // Remove the entry from the Add/Remove Programs key.
  462. // UNINSTALLKEY ends with '\\'
  463. //
  464. lstrcpy(UninstallKey + UNINSTALLKEYLEN, KBNumber);
  465. pSetupRegistryDelnode(HKEY_LOCAL_MACHINE, UninstallKey);
  466. }
  467. }
  468. }
  469. }
  470. RegCloseKey(hKey);
  471. pSetupRegistryDelnode(HKEY_LOCAL_MACHINE, HOTFIXAPPKEY);
  472. //
  473. // delete HKLM\SOFTWARE\Microsoft\Updates\Windows 2000 key since it contains entries for SPs/QFEs for win2k
  474. //
  475. pSetupRegistryDelnode(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Updates\\Windows 2000");
  476. //
  477. // We need to hack something for Exchange because they check for
  478. // a hotfix (irregardless of the OS version...
  479. //
  480. i = 1;
  481. SoftwareKeyItems[0].Name = L"Installed";
  482. SoftwareKeyItems[0].Data = &i;
  483. SoftwareKeyItems[0].Size = sizeof(DWORD);
  484. SoftwareKeyItems[0].Type = REG_DWORD;
  485. SetGroupOfValues(HKEY_LOCAL_MACHINE,L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q147222",SoftwareKeyItems,1);
  486. }
  487. VOID
  488. DeleteLocalSource(
  489. VOID
  490. )
  491. {
  492. WCHAR str[4];
  493. if(WinntBased && !AllowRollback) {
  494. if(SourcePath[0] && (SourcePath[1] == L':') && (SourcePath[2] == L'\\')) {
  495. lstrcpyn(str,SourcePath,4);
  496. if(GetDriveType(str) != DRIVE_CDROM) {
  497. Delnode(SourcePath);
  498. #ifdef _X86_
  499. if (IsNEC_98 && !lstrcmpi(&SourcePath[2], pwLocalSource)) {
  500. HKEY hkey;
  501. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"System\\Setup",0,MAXIMUM_ALLOWED,&hkey) == NO_ERROR) {
  502. RegDeleteValue(hkey, L"ForcePlatform");
  503. RegCloseKey(hkey);
  504. }
  505. }
  506. #endif
  507. }
  508. }
  509. //
  510. // Remove %systemroot%\winsxs\setuppolicies before rebooting
  511. //
  512. {
  513. WCHAR SetupPoliciesPath[MAX_PATH];
  514. GetSystemWindowsDirectoryW(SetupPoliciesPath, MAX_PATH);
  515. pSetupConcatenatePaths(SetupPoliciesPath, L"WinSxS\\SetupPolicies", MAX_PATH, NULL);
  516. Delnode(SetupPoliciesPath);
  517. }
  518. #if defined(_AMD64_) || defined(_X86_)
  519. //
  520. // Get rid of floppyless boot stuff.
  521. //
  522. if(FloppylessBootPath[0]) {
  523. WCHAR Path[MAX_PATH];
  524. //
  525. // NEC98 should back boot related files in \$WIN_NT$.~BU,
  526. // to restore boot files for keep original OS in each partition.
  527. //
  528. if (IsNEC_98) { //NEC98
  529. lstrcpy(Path,FloppylessBootPath);
  530. pSetupConcatenatePaths(Path,L"$WIN_NT$.~BU",MAX_PATH,NULL);
  531. Delnode(Path);
  532. } //NEC98
  533. lstrcpy(Path,FloppylessBootPath);
  534. pSetupConcatenatePaths(Path,L"$WIN_NT$.~BT",MAX_PATH,NULL);
  535. Delnode(Path);
  536. lstrcpy(Path,FloppylessBootPath);
  537. pSetupConcatenatePaths(Path,L"$LDR$",MAX_PATH,NULL);
  538. SetFileAttributes(Path,FILE_ATTRIBUTE_NORMAL);
  539. DeleteFile(Path);
  540. lstrcpy(Path,FloppylessBootPath);
  541. pSetupConcatenatePaths(Path,L"TXTSETUP.SIF",MAX_PATH,NULL);
  542. SetFileAttributes(Path,FILE_ATTRIBUTE_NORMAL);
  543. DeleteFile(Path);
  544. //
  545. // Get rid of arc loader files.
  546. //
  547. if( !IsArc() ) {
  548. lstrcpy(Path,FloppylessBootPath);
  549. pSetupConcatenatePaths(Path,L"ARCLDR.EXE",MAX_PATH,NULL);
  550. SetFileAttributes(Path,FILE_ATTRIBUTE_NORMAL);
  551. DeleteFile(Path);
  552. lstrcpy(Path,FloppylessBootPath);
  553. pSetupConcatenatePaths(Path,L"ARCSETUP.EXE",MAX_PATH,NULL);
  554. SetFileAttributes(Path,FILE_ATTRIBUTE_NORMAL);
  555. DeleteFile(Path);
  556. }
  557. }
  558. //
  559. // get rid of the boot.bak file
  560. //
  561. {
  562. WCHAR szBootBak[] = L"?:\\BOOT.BAK";
  563. szBootBak[0] = x86SystemPartitionDrive;
  564. SetFileAttributes(szBootBak,FILE_ATTRIBUTE_NORMAL);
  565. DeleteFile(szBootBak);
  566. }
  567. #endif // defined(_AMD64_) || defined(_X86_)
  568. #if defined(_IA64_)
  569. //
  570. // Get rid of SETUPLDR
  571. //
  572. {
  573. WCHAR Path[MAX_PATH];
  574. UNICODE_STRING UnicodeString;
  575. WCHAR Buffer[MAX_PATH];
  576. PWCHAR pwChar;
  577. PWSTR NtPath;
  578. BOOLEAN OldPriv, DontCare;
  579. OBJECT_ATTRIBUTES ObjAttrib;
  580. Buffer[0] = UNICODE_NULL;
  581. //
  582. // Make sure we have privilege to get/set nvram vars.
  583. //
  584. RtlAdjustPrivilege(
  585. SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
  586. TRUE,
  587. FALSE,
  588. &OldPriv
  589. );
  590. RtlInitUnicodeString(&UnicodeString,L"SYSTEMPARTITION");
  591. NtQuerySystemEnvironmentValue(
  592. &UnicodeString,
  593. Buffer,
  594. sizeof(Buffer)/sizeof(WCHAR),
  595. NULL
  596. );
  597. //
  598. // Restore previous privilege.
  599. //
  600. RtlAdjustPrivilege(
  601. SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
  602. OldPriv,
  603. FALSE,
  604. &DontCare
  605. );
  606. //
  607. // Strip everything from ';' to end of string since previous strings
  608. // are appended to the current string and are separated by ';'.
  609. //
  610. pwChar = Buffer;
  611. while ((*pwChar != L'\0') && (*pwChar != L';')) {
  612. pwChar++;
  613. }
  614. *pwChar = L'\0';
  615. NtPath = ArcDevicePathToNtPath(Buffer);
  616. if (NtPath) {
  617. lstrcpy(Path,NtPath);
  618. pSetupConcatenatePaths(Path,SETUPLDR,MAX_PATH,NULL);
  619. RtlInitUnicodeString(&UnicodeString,Path);
  620. InitializeObjectAttributes(
  621. &ObjAttrib,
  622. &UnicodeString,
  623. OBJ_CASE_INSENSITIVE,
  624. NULL,
  625. NULL
  626. );
  627. NtDeleteFile(&ObjAttrib);
  628. MyFree( NtPath );
  629. }
  630. }
  631. #endif // defined(_IA64_)
  632. }
  633. }
  634. BOOL
  635. ValidateAndChecksumFile(
  636. IN PCTSTR Filename,
  637. OUT PBOOLEAN IsNtImage,
  638. OUT PULONG Checksum,
  639. OUT PBOOLEAN Valid
  640. )
  641. /*++
  642. Routine Description:
  643. Calculate a checksum value for a file using the standard
  644. nt image checksum method. If the file is an nt image, validate
  645. the image using the partial checksum in the image header. If the
  646. file is not an nt image, it is simply defined as valid.
  647. If we encounter an i/o error while checksumming, then the file
  648. is declared invalid.
  649. Arguments:
  650. Filename - supplies full NT path of file to check.
  651. IsNtImage - Receives flag indicating whether the file is an
  652. NT image file.
  653. Checksum - receives 32-bit checksum value.
  654. Valid - receives flag indicating whether the file is a valid
  655. image (for nt images) and that we can read the image.
  656. Return Value:
  657. BOOL - Returns TRUE if the flie was validated, and in this case,
  658. IsNtImage, Checksum, and Valid will contain the result of
  659. the validation.
  660. This function will return FALSE, if the file could not be
  661. validated, and in this case, the caller should call GetLastError()
  662. to find out why this function failed.
  663. --*/
  664. {
  665. DWORD Error;
  666. PVOID BaseAddress;
  667. ULONG FileSize;
  668. HANDLE hFile,hSection;
  669. PIMAGE_NT_HEADERS NtHeaders;
  670. ULONG HeaderSum;
  671. //
  672. // Assume not an image and failure.
  673. //
  674. *IsNtImage = FALSE;
  675. *Checksum = 0;
  676. *Valid = FALSE;
  677. //
  678. // Open and map the file for read access.
  679. //
  680. Error = pSetupOpenAndMapFileForRead( Filename,
  681. &FileSize,
  682. &hFile,
  683. &hSection,
  684. &BaseAddress );
  685. if( Error != ERROR_SUCCESS ) {
  686. SetLastError( Error );
  687. return(FALSE);
  688. }
  689. if( FileSize == 0 ) {
  690. *IsNtImage = FALSE;
  691. *Checksum = 0;
  692. *Valid = TRUE;
  693. CloseHandle( hFile );
  694. return(TRUE);
  695. }
  696. try {
  697. NtHeaders = CheckSumMappedFile(BaseAddress,FileSize,&HeaderSum,Checksum);
  698. } except(EXCEPTION_EXECUTE_HANDLER) {
  699. *Checksum = 0;
  700. NtHeaders = NULL;
  701. }
  702. //
  703. // If the file is not an image and we got this far (as opposed to encountering
  704. // an i/o error) then the checksum is declared valid. If the file is an image,
  705. // then its checksum may or may not be valid.
  706. //
  707. if(NtHeaders) {
  708. *IsNtImage = TRUE;
  709. *Valid = HeaderSum ? (*Checksum == HeaderSum) : TRUE;
  710. } else {
  711. *Valid = TRUE;
  712. }
  713. pSetupUnmapAndCloseFile( hFile, hSection, BaseAddress );
  714. return( TRUE );
  715. }
  716. DWORD
  717. QueryHardDiskNumber(
  718. IN UCHAR DriveLetter
  719. )
  720. {
  721. WCHAR driveName[10];
  722. HANDLE h;
  723. BOOL b;
  724. STORAGE_DEVICE_NUMBER number;
  725. DWORD bytes;
  726. driveName[0] = '\\';
  727. driveName[1] = '\\';
  728. driveName[2] = '.';
  729. driveName[3] = '\\';
  730. driveName[4] = DriveLetter;
  731. driveName[5] = ':';
  732. driveName[6] = 0;
  733. h = CreateFile(driveName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  734. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  735. INVALID_HANDLE_VALUE);
  736. if (h == INVALID_HANDLE_VALUE) {
  737. return (DWORD) -1;
  738. }
  739. b = DeviceIoControl(h, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
  740. &number, sizeof(number), &bytes, NULL);
  741. CloseHandle(h);
  742. if (!b) {
  743. return (DWORD) -1;
  744. }
  745. return number.DeviceNumber;
  746. }
  747. BOOL
  748. ExtendPartition(
  749. IN WCHAR DriveLetter,
  750. IN ULONG SizeMB OPTIONAL
  751. )
  752. /*++
  753. Routine Description:
  754. This function will extend a partition.
  755. We'll do this in the following way:
  756. 1. Figure out if the partition is NTFS.
  757. 2. Figure out if there's any unpartitioned space behind
  758. the partition the user is asking us to extend.
  759. 3. How much space is available?
  760. 4. Extend the partition
  761. 5. Extend the filesystem (inform him the partition is bigger).
  762. Arguments:
  763. DriveLetter - Supplies the driveletter for the partition
  764. that we'll be extending.
  765. SizeMB - if specified, indicates the size in MB by which
  766. the partition will grow. If not specified, the
  767. partition grows to encompass all the free space
  768. in the adjacent free space.
  769. Return Value:
  770. Boolean value indicating whether anything actually changed.
  771. --*/
  772. {
  773. #define LEAVE_FREE_BUFFER (5 * (1024*1024))
  774. HANDLE h;
  775. PARTITION_INFORMATION_EX PartitionInfo;
  776. BOOL b;
  777. DWORD Bytes;
  778. DISK_GEOMETRY Geometry;
  779. DISK_GROW_PARTITION GrowInfo;
  780. TCHAR PhysicalName[MAX_PATH];
  781. TCHAR DosName[10];
  782. LARGE_INTEGER BytesAvailable;
  783. LARGE_INTEGER OurPartitionEndingLocation;
  784. DWORD i;
  785. PDRIVE_LAYOUT_INFORMATION_EX DriveLayout;
  786. //
  787. // =====================================
  788. // 1. Figure out if the partition is NTFS.
  789. // =====================================
  790. //
  791. DosName[0] = DriveLetter;
  792. DosName[1] = TEXT(':');
  793. DosName[2] = TEXT('\\');
  794. DosName[3] = TEXT('\0');
  795. b = GetVolumeInformation(
  796. DosName,
  797. NULL,0, // don't care about volume name
  798. NULL, // ...or serial #
  799. &i, // ...or max component length
  800. &i, // ... or flags
  801. PhysicalName,
  802. sizeof(PhysicalName)/sizeof(TCHAR)
  803. );
  804. if( !b ) {
  805. return FALSE;
  806. }
  807. if(lstrcmpi(PhysicalName,TEXT("NTFS"))) {
  808. //
  809. // Our partition isn't NTFS. Bail.
  810. //
  811. DbgPrintEx( DPFLTR_SETUP_ID,
  812. DPFLTR_INFO_LEVEL,
  813. "ExtendPartition: %ws is not NTFS volume\n",
  814. DosName);
  815. return FALSE;
  816. }
  817. //
  818. // Now initialize the name for this partition and
  819. // the name for this drive.
  820. //
  821. wsprintf( DosName, TEXT("\\\\.\\%c:"), DriveLetter );
  822. wsprintf( PhysicalName, TEXT("\\\\.\\PhysicalDrive%u"), QueryHardDiskNumber( (UCHAR)DriveLetter) );
  823. //
  824. // =====================================
  825. // 2. Figure out if there's any unpartitioned space behind
  826. // the partition the user is asking us to extend.
  827. // =====================================
  828. //
  829. //
  830. // Get a handle to the disk so we can start examination.
  831. //
  832. h = CreateFile( PhysicalName,
  833. GENERIC_READ | GENERIC_WRITE,
  834. FILE_SHARE_READ | FILE_SHARE_WRITE,
  835. NULL,
  836. OPEN_EXISTING,
  837. FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING,
  838. NULL );
  839. if( h == INVALID_HANDLE_VALUE ) {
  840. DbgPrintEx( DPFLTR_SETUP_ID,
  841. DPFLTR_INFO_LEVEL,
  842. "ExtendPartition: %X Error while opening %ws\n",
  843. GetLastError(),
  844. PhysicalName);
  845. return FALSE;
  846. }
  847. //
  848. // Get the disk's layout information. We aren't
  849. // sure how big of a buffer we need, so brute-force it.
  850. //
  851. {
  852. DWORD DriveLayoutSize = 1024;
  853. PVOID p;
  854. DriveLayout = MyMalloc(DriveLayoutSize);
  855. if( !DriveLayout ) {
  856. CloseHandle( h );
  857. return FALSE;
  858. }
  859. retry:
  860. b = DeviceIoControl( h,
  861. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  862. NULL,
  863. 0,
  864. (PVOID)DriveLayout,
  865. DriveLayoutSize,
  866. &Bytes,
  867. NULL );
  868. if( !b ) {
  869. DWORD LastError = GetLastError();
  870. if (LastError == ERROR_INSUFFICIENT_BUFFER) {
  871. DriveLayoutSize += 1024;
  872. if(p = MyRealloc((PVOID)DriveLayout,DriveLayoutSize)) {
  873. (PVOID)DriveLayout = p;
  874. } else {
  875. goto cleanexit0;
  876. }
  877. goto retry;
  878. } else {
  879. DbgPrintEx( DPFLTR_SETUP_ID,
  880. DPFLTR_INFO_LEVEL,
  881. "ExtendPartition: %X Error while getting drive layout for %ws\n",
  882. LastError,
  883. PhysicalName);
  884. goto cleanexit0;
  885. }
  886. }
  887. }
  888. CloseHandle( h );
  889. h = INVALID_HANDLE_VALUE;
  890. //
  891. // DriveLayout now is full of most of the information we
  892. // need, including an array of partition information. But
  893. // we aren't sure which partition is ours. We need to
  894. // get info on our specific partition, then match it
  895. // against the entry inside DriveLayout.
  896. //
  897. //
  898. // Open a handle to the partition.
  899. //
  900. h = CreateFile( DosName,
  901. GENERIC_READ,
  902. FILE_SHARE_READ | FILE_SHARE_WRITE,
  903. NULL,
  904. OPEN_EXISTING,
  905. FILE_ATTRIBUTE_NORMAL,
  906. INVALID_HANDLE_VALUE );
  907. if( h == INVALID_HANDLE_VALUE ) {
  908. DbgPrintEx( DPFLTR_SETUP_ID,
  909. DPFLTR_INFO_LEVEL,
  910. "ExtendPartition: %X Error while opening %ws\n",
  911. GetLastError(),
  912. DosName);
  913. return FALSE;
  914. }
  915. //
  916. // Load info about our partition.
  917. //
  918. b = DeviceIoControl( h,
  919. IOCTL_DISK_GET_PARTITION_INFO_EX,
  920. NULL,
  921. 0,
  922. &PartitionInfo,
  923. sizeof(PartitionInfo),
  924. &Bytes,
  925. NULL );
  926. if( !b ) {
  927. DbgPrintEx( DPFLTR_SETUP_ID,
  928. DPFLTR_INFO_LEVEL,
  929. "ExtendPartition: %X Error while getting %ws's partition information\n",
  930. GetLastError(),
  931. DosName);
  932. goto cleanexit0;
  933. }
  934. //
  935. // Might as well get the geometry info on the disk too.
  936. //
  937. b = DeviceIoControl( h,
  938. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  939. NULL,
  940. 0,
  941. &Geometry,
  942. sizeof(Geometry),
  943. &Bytes,
  944. NULL );
  945. if( !b ) {
  946. DbgPrintEx( DPFLTR_SETUP_ID,
  947. DPFLTR_INFO_LEVEL,
  948. "ExtendPartition: %X Error while getting %ws's drive geometry\n",
  949. GetLastError(),
  950. DosName);
  951. goto cleanexit0;
  952. }
  953. CloseHandle( h );
  954. h = INVALID_HANDLE_VALUE;
  955. //
  956. // =====================================
  957. // 3. How much space is available?
  958. // =====================================
  959. //
  960. //
  961. // We're ready to actually verify that there's rooom for us to grow.
  962. // If we're the last partition on the disk, we need to see if there's
  963. // any room behind us (i.e. any unpartitioned space). If we're not
  964. // the last partition, we need to see if there's any space between where
  965. // our partition ends and the next partition begins.
  966. //
  967. // This is really gross, but DriveLayout->PartitionCount will likely be 4
  968. // even if there's really only 1 formatted partition on the disk. We also
  969. // don't want to take the chance that the partitions aren't ordered by their
  970. // location on the disk. So we need to go cycle through the partitions
  971. // again and manually find the one that starts right after ours.
  972. //
  973. OurPartitionEndingLocation.QuadPart = PartitionInfo.StartingOffset.QuadPart + PartitionInfo.PartitionLength.QuadPart;
  974. //
  975. // Initialize BytesAvailable based on the space from where our partition ends to where
  976. // the disk ends. This is the best case and we can only get smaller sizes, so this
  977. // is safe.
  978. //
  979. BytesAvailable.QuadPart = UInt32x32To64( Geometry.BytesPerSector, Geometry.SectorsPerTrack );
  980. BytesAvailable.QuadPart = BytesAvailable.QuadPart * (ULONGLONG)(Geometry.TracksPerCylinder);
  981. BytesAvailable.QuadPart = BytesAvailable.QuadPart * Geometry.Cylinders.QuadPart;
  982. //
  983. // Check if the value of End of Partition is beyond the Disk size.
  984. // If we do not have this check we find that the partition gets corrupted as
  985. // IOCTL_DISK_GROW_PARTITION does not check the validity of the value
  986. // passed to it. This condition (of a negative grow) would arise because of a
  987. // rounding off(to the lower value) up to a cylinder by
  988. // IOCTL_DISK_GET_DRIVE_GEOMETRY.
  989. //
  990. if (BytesAvailable.QuadPart <= OurPartitionEndingLocation.QuadPart) {
  991. b = FALSE;
  992. goto cleanexit0;
  993. }
  994. BytesAvailable.QuadPart = BytesAvailable.QuadPart - OurPartitionEndingLocation.QuadPart;
  995. for( i = 0; i < DriveLayout->PartitionCount; i++ ) {
  996. if( (DriveLayout->PartitionEntry[i].StartingOffset.QuadPart > OurPartitionEndingLocation.QuadPart) &&
  997. ((DriveLayout->PartitionEntry[i].StartingOffset.QuadPart - OurPartitionEndingLocation.QuadPart) < BytesAvailable.QuadPart) ) {
  998. //
  999. // This partition is starting after ours and it's also the closest one we've found
  1000. // to our ending location.
  1001. //
  1002. BytesAvailable.QuadPart = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart - OurPartitionEndingLocation.QuadPart;
  1003. }
  1004. }
  1005. //
  1006. // Reserve the space at the disk end only for MBR disks
  1007. //
  1008. if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR) {
  1009. //
  1010. // If we don't have at least 5MB available, don't even bother. If we do, leave the last
  1011. // 5MB free for later use as a dynamic volume.
  1012. //
  1013. if( BytesAvailable.QuadPart < (ULONGLONG)(LEAVE_FREE_BUFFER) ) {
  1014. goto cleanexit0;
  1015. } else {
  1016. BytesAvailable.QuadPart = BytesAvailable.QuadPart - (ULONGLONG)(LEAVE_FREE_BUFFER);
  1017. }
  1018. }
  1019. //
  1020. // See if the user has asked us to extend by some known value...
  1021. //
  1022. if( SizeMB ) {
  1023. //
  1024. // Yes. Make sure we have atleast this much space to extend.
  1025. //
  1026. if( (LONGLONG)(SizeMB * (1024*1024)) < BytesAvailable.QuadPart ) {
  1027. BytesAvailable.QuadPart = UInt32x32To64( SizeMB, (1024*1024) );
  1028. }
  1029. }
  1030. //
  1031. // =====================================
  1032. // 4. Extend the partition
  1033. // =====================================
  1034. //
  1035. //
  1036. // Get a handle to the disk.
  1037. //
  1038. h = CreateFile( PhysicalName,
  1039. GENERIC_READ | GENERIC_WRITE,
  1040. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1041. NULL,
  1042. OPEN_EXISTING,
  1043. FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING,
  1044. NULL );
  1045. if( h == INVALID_HANDLE_VALUE ) {
  1046. DbgPrintEx( DPFLTR_SETUP_ID,
  1047. DPFLTR_INFO_LEVEL,
  1048. "ExtendPartition: %X Error while opening %ws\n",
  1049. GetLastError(),
  1050. PhysicalName);
  1051. return FALSE;
  1052. }
  1053. //
  1054. // Fill in the datastructure we'll be sending to the IOCTL.
  1055. //
  1056. GrowInfo.PartitionNumber = PartitionInfo.PartitionNumber;
  1057. GrowInfo.BytesToGrow = BytesAvailable;
  1058. //
  1059. // Do it.
  1060. //
  1061. b = DeviceIoControl( h,
  1062. IOCTL_DISK_GROW_PARTITION,
  1063. &GrowInfo,
  1064. sizeof(GrowInfo),
  1065. NULL,
  1066. 0,
  1067. &Bytes,
  1068. NULL );
  1069. if( !b ) {
  1070. DbgPrintEx( DPFLTR_SETUP_ID,
  1071. DPFLTR_INFO_LEVEL,
  1072. "ExtendPartition: %X Error while growing %ws partition\n",
  1073. GetLastError(),
  1074. PhysicalName);
  1075. goto cleanexit0;
  1076. }
  1077. CloseHandle( h );
  1078. h = INVALID_HANDLE_VALUE;
  1079. //
  1080. // =====================================
  1081. // 5. Extend the filesystem (inform him the partition is bigger).
  1082. // =====================================
  1083. //
  1084. //
  1085. // Get a handle to the partition.
  1086. //
  1087. h = CreateFile( DosName,
  1088. GENERIC_READ,
  1089. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1090. NULL,
  1091. OPEN_EXISTING,
  1092. FILE_ATTRIBUTE_NORMAL,
  1093. INVALID_HANDLE_VALUE );
  1094. if( h == INVALID_HANDLE_VALUE ) {
  1095. DbgPrintEx( DPFLTR_SETUP_ID,
  1096. DPFLTR_INFO_LEVEL,
  1097. "ExtendPartition: %X Error while opening %ws\n",
  1098. GetLastError(),
  1099. DosName);
  1100. goto cleanexit0;
  1101. }
  1102. //
  1103. // Gather some info on the partition.
  1104. //
  1105. b = DeviceIoControl( h,
  1106. IOCTL_DISK_GET_PARTITION_INFO_EX,
  1107. NULL,
  1108. 0,
  1109. &PartitionInfo,
  1110. sizeof(PartitionInfo),
  1111. &Bytes,
  1112. NULL );
  1113. if( !b ) {
  1114. DbgPrintEx( DPFLTR_SETUP_ID,
  1115. DPFLTR_INFO_LEVEL,
  1116. "ExtendPartition: %X Error while getting %ws's partition information\n",
  1117. GetLastError(),
  1118. DosName);
  1119. goto cleanexit0;
  1120. }
  1121. //
  1122. // Grow the volume.
  1123. //
  1124. BytesAvailable.QuadPart = PartitionInfo.PartitionLength.QuadPart / Geometry.BytesPerSector;
  1125. b = DeviceIoControl( h,
  1126. FSCTL_EXTEND_VOLUME,
  1127. &BytesAvailable,
  1128. sizeof(BytesAvailable),
  1129. NULL,
  1130. 0,
  1131. &Bytes,
  1132. NULL );
  1133. if( !b ) {
  1134. DbgPrintEx( DPFLTR_SETUP_ID,
  1135. DPFLTR_INFO_LEVEL,
  1136. "ExtendPartition: %X Error while extending volume %ws\n",
  1137. GetLastError(),
  1138. DosName);
  1139. goto cleanexit0;
  1140. }
  1141. cleanexit0:
  1142. if( h != INVALID_HANDLE_VALUE ) {
  1143. CloseHandle( h );
  1144. }
  1145. //
  1146. // If we successfully extended the partition
  1147. // then mark the global flag to remove any
  1148. // stale volume information, at the end of setup.
  1149. //
  1150. if (b) {
  1151. PartitionExtended = TRUE;
  1152. }
  1153. return b;
  1154. }
  1155. BOOL
  1156. SetupExtendPartition(
  1157. IN WCHAR DriveLetter,
  1158. IN ULONG SizeMB OPTIONAL
  1159. )
  1160. {
  1161. BOOL b;
  1162. if ( b = ExtendPartition(DriveLetter, SizeMB) )
  1163. {
  1164. RemoveStaleVolumes();
  1165. PartitionExtended = FALSE;
  1166. }
  1167. return b;
  1168. }
  1169. BOOL
  1170. DoFilesMatch(
  1171. IN PCWSTR File1,
  1172. IN PCWSTR File2
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. Compares two files to each other to see if they are identical.
  1177. Arguments:
  1178. File1 - First file to compare
  1179. File2 - Second file to compare
  1180. Return Value:
  1181. BOOL - Returns TRUE if the files match. If the both of the files are zero
  1182. length, then we still return TRUE.
  1183. --*/
  1184. {
  1185. DWORD FirstFileSize, SecondFileSize;
  1186. HANDLE FirstFileHandle, FirstMappingHandle;
  1187. HANDLE SecondFileHandle, SecondMappingHandle;
  1188. PVOID FirstBaseAddress, SecondBaseAddress;
  1189. BOOL RetVal = FALSE;
  1190. if( (pSetupOpenAndMapFileForRead(
  1191. File1,
  1192. &FirstFileSize,
  1193. &FirstFileHandle,
  1194. &FirstMappingHandle,
  1195. &FirstBaseAddress) == NO_ERROR)
  1196. && (pSetupOpenAndMapFileForRead(
  1197. File1,
  1198. &SecondFileSize,
  1199. &SecondFileHandle,
  1200. &SecondMappingHandle,
  1201. &SecondBaseAddress) == NO_ERROR) ) {
  1202. if (FirstFileSize == SecondFileSize ) {
  1203. if (FirstFileSize != 0) {
  1204. //
  1205. // protect against inpage IO error
  1206. //
  1207. try {
  1208. RetVal = !memcmp(
  1209. FirstBaseAddress,
  1210. SecondBaseAddress,
  1211. FirstFileSize
  1212. );
  1213. } except(EXCEPTION_EXECUTE_HANDLER) {
  1214. RetVal = FALSE;
  1215. }
  1216. }
  1217. }
  1218. pSetupUnmapAndCloseFile(
  1219. FirstFileHandle,
  1220. FirstMappingHandle,
  1221. FirstBaseAddress
  1222. );
  1223. pSetupUnmapAndCloseFile(
  1224. SecondFileHandle,
  1225. SecondMappingHandle,
  1226. SecondBaseAddress
  1227. );
  1228. }
  1229. return (RetVal);
  1230. }
  1231. DWORD
  1232. RemoveStaleVolumes(
  1233. VOID
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. This routine walks through all the volumes and deletes the one
  1238. which are marked for reinstall.
  1239. NOTE : Use the function carefully because it will nuke all
  1240. the entries related to the volume from the registry, iff the volume
  1241. says it needs to be reinstalled.
  1242. Arguments:
  1243. None.
  1244. Return Value:
  1245. Appropriate Win32 error code.
  1246. --*/
  1247. {
  1248. const TCHAR *VolumeKeyName = TEXT("System\\CurrentControlSet\\Enum\\Storage\\Volume");
  1249. const TCHAR *ClassKeyName = TEXT("System\\CurrentControlSet\\Control\\Class");
  1250. DWORD ErrorCode;
  1251. HKEY VolumeKey = NULL;
  1252. HKEY ClassKey = NULL;
  1253. ULONG Index = 0;
  1254. ULONG VolumesFixedCount = 0;
  1255. TCHAR SubKeyName[MAX_PATH*2];
  1256. DWORD SubKeyLength;
  1257. FILETIME SubKeyTime;
  1258. //
  1259. // Open the Volume key
  1260. //
  1261. ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1262. VolumeKeyName,
  1263. 0,
  1264. KEY_ALL_ACCESS,
  1265. &VolumeKey);
  1266. if (VolumeKey == NULL) {
  1267. ErrorCode = ERROR_INVALID_HANDLE;
  1268. }
  1269. if (ErrorCode != ERROR_SUCCESS) {
  1270. return ErrorCode;
  1271. }
  1272. //
  1273. // Open the Class key
  1274. //
  1275. ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1276. ClassKeyName,
  1277. 0,
  1278. KEY_ALL_ACCESS,
  1279. &ClassKey);
  1280. if (ClassKey == NULL) {
  1281. ErrorCode = ERROR_INVALID_HANDLE;
  1282. }
  1283. if (ErrorCode != ERROR_SUCCESS) {
  1284. RegCloseKey(VolumeKey);
  1285. return ErrorCode;
  1286. }
  1287. //
  1288. // Enumerate each subkey of the opened key
  1289. //
  1290. while (TRUE) {
  1291. SubKeyName[0] = 0;
  1292. SubKeyLength = sizeof(SubKeyName) / sizeof(SubKeyName[0]);
  1293. ErrorCode = RegEnumKeyEx(VolumeKey,
  1294. Index,
  1295. SubKeyName,
  1296. &SubKeyLength,
  1297. NULL,
  1298. NULL,
  1299. NULL,
  1300. &SubKeyTime);
  1301. if (ErrorCode == ERROR_SUCCESS) {
  1302. TCHAR FullSubKeyName[MAX_PATH*4];
  1303. DWORD SubErrorCode;
  1304. HKEY CurrentSubKey = NULL;
  1305. GUID VolumeGuid = {0};
  1306. TCHAR VolumeGuidStr[MAX_PATH] = {0};
  1307. DWORD DrvInstance = -1;
  1308. BOOL DeleteKey = FALSE;
  1309. BOOL DeleteClassInstance = FALSE;
  1310. BOOL IncrementKeyIndex = TRUE;
  1311. _tcscpy(FullSubKeyName, VolumeKeyName);
  1312. _tcscat(FullSubKeyName, TEXT("\\"));
  1313. _tcscat(FullSubKeyName, SubKeyName);
  1314. SubErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1315. FullSubKeyName,
  1316. 0,
  1317. KEY_ALL_ACCESS,
  1318. &CurrentSubKey);
  1319. if (SubErrorCode == ERROR_SUCCESS) {
  1320. //
  1321. // Read the ConfigFlags value
  1322. //
  1323. DWORD ConfigFlags = 0;
  1324. DWORD Type = REG_DWORD;
  1325. DWORD BufferSize = sizeof(DWORD);
  1326. SubErrorCode = RegQueryValueEx(CurrentSubKey,
  1327. TEXT("ConfigFlags"),
  1328. NULL,
  1329. &Type,
  1330. (PBYTE)&ConfigFlags,
  1331. &BufferSize);
  1332. if (SubErrorCode == ERROR_SUCCESS) {
  1333. DeleteKey = (ConfigFlags & (CONFIGFLAG_REINSTALL | CONFIGFLAG_FINISH_INSTALL));
  1334. if (DeleteKey) {
  1335. Type = REG_BINARY;
  1336. BufferSize = sizeof(VolumeGuid);
  1337. //
  1338. // Read the GUID & DrvInst values
  1339. //
  1340. SubErrorCode = RegQueryValueEx(CurrentSubKey,
  1341. TEXT("GUID"),
  1342. NULL,
  1343. &Type,
  1344. (PBYTE)&VolumeGuid,
  1345. &BufferSize);
  1346. if (SubErrorCode == ERROR_SUCCESS) {
  1347. Type = REG_DWORD;
  1348. BufferSize = sizeof(DWORD);
  1349. SubErrorCode = RegQueryValueEx(CurrentSubKey,
  1350. TEXT("DrvInst"),
  1351. NULL,
  1352. &Type,
  1353. (PBYTE)&DrvInstance,
  1354. &BufferSize);
  1355. DeleteClassInstance =
  1356. (SubErrorCode == ERROR_SUCCESS) &&
  1357. (DrvInstance != -1);
  1358. }
  1359. }
  1360. }
  1361. //
  1362. // Close the current subkey since we don't need it anymore
  1363. //
  1364. RegCloseKey(CurrentSubKey);
  1365. //
  1366. // Delete after we close the current key
  1367. //
  1368. if (DeleteKey) {
  1369. SubErrorCode = SHDeleteKey(HKEY_LOCAL_MACHINE,
  1370. FullSubKeyName);
  1371. if (SubErrorCode == ERROR_SUCCESS) {
  1372. VolumesFixedCount++;
  1373. IncrementKeyIndex = FALSE;
  1374. }
  1375. }
  1376. //
  1377. // Delete the instance key under class also if needed
  1378. //
  1379. if (DeleteClassInstance &&
  1380. (pSetupStringFromGuid(&VolumeGuid,
  1381. VolumeGuidStr,
  1382. sizeof(VolumeGuidStr)/sizeof(VolumeGuidStr[0])) == ERROR_SUCCESS)) {
  1383. _stprintf(FullSubKeyName,
  1384. TEXT("System\\CurrentControlSet\\Control\\Class\\%ws\\%04d"),
  1385. VolumeGuidStr,
  1386. DrvInstance);
  1387. SubErrorCode = SHDeleteKey(HKEY_LOCAL_MACHINE,
  1388. FullSubKeyName);
  1389. }
  1390. }
  1391. if (IncrementKeyIndex) {
  1392. Index++;
  1393. }
  1394. } else {
  1395. break; // we couldn't enumerate further sub keys
  1396. }
  1397. }
  1398. RegCloseKey(ClassKey);
  1399. RegCloseKey(VolumeKey);
  1400. //
  1401. // If we fixed at least a single volume then assume things
  1402. // went fine
  1403. //
  1404. if (VolumesFixedCount > 0) {
  1405. ErrorCode = ERROR_SUCCESS;
  1406. }
  1407. return ErrorCode;
  1408. }
  1409. #define MAX_NT_PATH (MAX_PATH + 4)//"\\??\\"
  1410. #define UNDO_FILE_NAME L"UNDO_GUIMODE.TXT"
  1411. VOID
  1412. RemoveAllPendingOperationsOnRestartOfGUIMode(
  1413. VOID
  1414. )
  1415. {
  1416. WCHAR undoFilePath[MAX_PATH];
  1417. if(!GetWindowsDirectoryW(undoFilePath, ARRAYSIZE(undoFilePath))){
  1418. ASSERT(FALSE);
  1419. return;
  1420. }
  1421. wcscat(undoFilePath, L"\\system32\\");
  1422. wcscat(undoFilePath, UNDO_FILE_NAME);
  1423. SetFileAttributes(undoFilePath, FILE_ATTRIBUTE_NORMAL);
  1424. DeleteFile(undoFilePath);
  1425. }
  1426. BOOL
  1427. RenameOnRestartOfGUIMode(
  1428. IN PCWSTR pPathName,
  1429. IN PCWSTR pPathNameNew
  1430. )
  1431. {
  1432. DWORD Size;
  1433. BOOL result;
  1434. WCHAR undoFilePath[MAX_PATH];
  1435. WCHAR RenameOperationBuffer[2 * (MAX_NT_PATH + 2/*'\r\n'*/)];
  1436. HANDLE fileUndo;
  1437. BYTE signUnicode[] = {0xff, 0xfe};
  1438. if(!pPathName){
  1439. return FALSE;
  1440. }
  1441. if(!GetWindowsDirectoryW(undoFilePath, ARRAYSIZE(undoFilePath))){
  1442. return FALSE;
  1443. }
  1444. wcscat(undoFilePath, L"\\system32\\" UNDO_FILE_NAME);
  1445. wsprintfW(RenameOperationBuffer, L"\\??\\%s\r\n", pPathName);
  1446. if(pPathNameNew){
  1447. wsprintfW(RenameOperationBuffer + wcslen(RenameOperationBuffer),
  1448. L"\\??\\%s",
  1449. pPathNameNew);
  1450. }
  1451. wcscat(RenameOperationBuffer, L"\r\n");
  1452. fileUndo = CreateFileW(undoFilePath,
  1453. GENERIC_WRITE,
  1454. FILE_SHARE_READ,
  1455. NULL,
  1456. OPEN_ALWAYS,
  1457. FILE_ATTRIBUTE_NORMAL,
  1458. NULL);
  1459. if(INVALID_HANDLE_VALUE == fileUndo){
  1460. return FALSE;
  1461. }
  1462. if(!SetFilePointer(fileUndo, 0, NULL, FILE_END)){
  1463. result = WriteFile(fileUndo, signUnicode, sizeof(signUnicode), &Size, NULL);
  1464. }
  1465. else {
  1466. result = TRUE;
  1467. }
  1468. if(result){
  1469. result = WriteFile(fileUndo,
  1470. RenameOperationBuffer,
  1471. wcslen(RenameOperationBuffer) * sizeof(WCHAR),
  1472. &Size,
  1473. NULL);
  1474. }
  1475. CloseHandle(fileUndo);
  1476. return result;
  1477. }
  1478. BOOL
  1479. DeleteOnRestartOfGUIMode(
  1480. IN PCWSTR pPathName
  1481. )
  1482. {
  1483. return RenameOnRestartOfGUIMode(pPathName, NULL);
  1484. }