Source code of Windows XP (NT5)
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.

1812 lines
51 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. #ifdef _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. //
  292. // The current match is a directory. Recurse into it unless
  293. // it's . or ...
  294. //
  295. if(lstrcmp(FindData.cFileName,TEXT("." )) && lstrcmp(FindData.cFileName,TEXT(".."))) {
  296. Delnode(Pattern);
  297. }
  298. } else {
  299. //
  300. // The current match is not a directory -- so delete it.
  301. //
  302. if(!DeleteFile(Pattern)) {
  303. SetuplogError(
  304. LogSevWarning,
  305. SETUPLOG_USE_MESSAGEID,
  306. MSG_LOG_DELNODE_FAIL,
  307. Pattern, NULL,
  308. SETUPLOG_USE_MESSAGEID,
  309. MSG_LOG_X_PARAM_RETURNED_WINERR,
  310. szDeleteFile,
  311. GetLastError(),
  312. Pattern,
  313. NULL,NULL);
  314. }
  315. }
  316. } while(FindNextFile(FindHandle,&FindData));
  317. FindClose(FindHandle);
  318. }
  319. //
  320. // Remove the directory we just emptied out. Ignore errors.
  321. //
  322. SetFileAttributes(Directory,FILE_ATTRIBUTE_NORMAL);
  323. RemoveDirectory(Directory);
  324. }
  325. VOID
  326. RemoveServicePackEntries(
  327. HKEY hKey
  328. )
  329. /*
  330. This routine takes in the Handle to the Software\Microsoft\Windows NT\CurrentVersion\Hotfix\ServicePackUninstall
  331. key and then enumerates each value entry under it.
  332. It then takes the value data and appends that to the
  333. "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" and delnodes that key. This
  334. way we have an extensible mechanism to always cleanup the Uninstall keys for ServicePacks.
  335. */
  336. {
  337. #define UNINSTALLKEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
  338. #define UNINSTALLKEYLEN (sizeof(UNINSTALLKEY) / sizeof(WCHAR) - 1)
  339. DWORD Status,MaxValueName=0,MaxValue=0,Values=0,i;
  340. DWORD TempMaxNameSize, TempMaxDataSize;
  341. PWSTR ValueName, ValueData;
  342. Status = RegQueryInfoKey( hKey,
  343. NULL,
  344. NULL,
  345. NULL,
  346. NULL,
  347. NULL,
  348. NULL,
  349. &Values,
  350. &MaxValueName,
  351. &MaxValue,
  352. NULL,
  353. NULL );
  354. //Account forterminating null
  355. if( Status == ERROR_SUCCESS ){
  356. MaxValueName += 2;
  357. MaxValue = MaxValue + 2 + lstrlen(UNINSTALLKEY);
  358. ValueName = MyMalloc( MaxValueName * sizeof(WCHAR) );
  359. ValueData = MyMalloc( MaxValue * sizeof(WCHAR) );
  360. if( !ValueName || !ValueData )
  361. return;
  362. lstrcpy( ValueData, UNINSTALLKEY );
  363. for (i=0; i < Values; i++){
  364. TempMaxNameSize = MaxValueName;
  365. TempMaxDataSize = MaxValue;
  366. Status = RegEnumValue( hKey,
  367. i,
  368. ValueName,
  369. &TempMaxNameSize,
  370. NULL,
  371. NULL,
  372. (LPBYTE)(ValueData+lstrlen(UNINSTALLKEY)),
  373. &TempMaxDataSize
  374. );
  375. if( Status == ERROR_SUCCESS ){
  376. pSetupRegistryDelnode( HKEY_LOCAL_MACHINE, ValueData );
  377. }
  378. }
  379. }
  380. MyFree( ValueName );
  381. MyFree( ValueData );
  382. return;
  383. }
  384. VOID
  385. RemoveHotfixData(
  386. VOID
  387. )
  388. {
  389. WCHAR Path[MAX_PATH];
  390. WCHAR KBNumber[64];
  391. WCHAR UninstallKey[MAX_PATH];
  392. DWORD i = 0;
  393. DWORD prefixSize = 0;
  394. DWORD Status, SubKeys;
  395. HKEY hKey, SvcPckKey;
  396. REGVALITEM SoftwareKeyItems[1];
  397. //
  398. //For each hotfix, the registry info is stored under
  399. // HKLM\Software\Microsoft\Windows NT\CurrentVersion\Hotfix\<KB#>
  400. // and the files are stored under
  401. // %windir%\$NtUninstall<KB#>$
  402. //
  403. //Enumerate the hotfix key and remove the files and registry entries for each hotfix.
  404. //
  405. #define HOTFIXAPPKEY L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix"
  406. Status = RegOpenKey(HKEY_LOCAL_MACHINE, HOTFIXAPPKEY, &hKey);
  407. if( Status != ERROR_SUCCESS ) {
  408. return;
  409. }
  410. Status = RegQueryInfoKey( hKey,
  411. NULL,
  412. NULL,
  413. NULL,
  414. &SubKeys,
  415. NULL,
  416. NULL,
  417. NULL,
  418. NULL,
  419. NULL,
  420. NULL,
  421. NULL );
  422. if(Status == ERROR_SUCCESS) {
  423. Status = GetWindowsDirectory(Path, MAX_PATH);
  424. if(Status == 0) {
  425. MYASSERT(FALSE);
  426. return;
  427. }
  428. pSetupConcatenatePaths(Path,L"$NtUninstall",MAX_PATH,&prefixSize);
  429. lstrcpy(UninstallKey, UNINSTALLKEY);
  430. for( i = 0; i < SubKeys; i++ ) {
  431. Status = RegEnumKey(hKey, i, KBNumber, sizeof(KBNumber) / sizeof(KBNumber[0]));
  432. if (Status == ERROR_SUCCESS) {
  433. if( !lstrcmpi( KBNumber, TEXT("ServicePackUninstall") ) ){
  434. Status = RegOpenKey(hKey,KBNumber,&SvcPckKey);
  435. if( Status == ERROR_SUCCESS ){
  436. RemoveServicePackEntries(SvcPckKey);
  437. RegCloseKey(SvcPckKey);
  438. }
  439. }else{
  440. lstrcpyn(Path + prefixSize - 1, KBNumber, MAX_PATH - prefixSize);
  441. lstrcat(Path, L"$");
  442. Delnode(Path);
  443. //
  444. // Remove the entry from the Add/Remove Programs key.
  445. // UNINSTALLKEY ends with '\\'
  446. //
  447. lstrcpy(UninstallKey + UNINSTALLKEYLEN, KBNumber);
  448. pSetupRegistryDelnode(HKEY_LOCAL_MACHINE, UninstallKey);
  449. }
  450. }
  451. }
  452. }
  453. RegCloseKey(hKey);
  454. pSetupRegistryDelnode(HKEY_LOCAL_MACHINE, HOTFIXAPPKEY);
  455. //
  456. // delete HKLM\SOFTWARE\Microsoft\Updates\Windows 2000 key since it contains entries for SPs/QFEs for win2k
  457. //
  458. pSetupRegistryDelnode(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Updates\\Windows 2000");
  459. //
  460. // We need to hack something for Exchange because they check for
  461. // a hotfix (irregardless of the OS version...
  462. //
  463. i = 1;
  464. SoftwareKeyItems[0].Name = L"Installed";
  465. SoftwareKeyItems[0].Data = &i;
  466. SoftwareKeyItems[0].Size = sizeof(DWORD);
  467. SoftwareKeyItems[0].Type = REG_DWORD;
  468. SetGroupOfValues(HKEY_LOCAL_MACHINE,L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q147222",SoftwareKeyItems,1);
  469. }
  470. VOID
  471. DeleteLocalSource(
  472. VOID
  473. )
  474. {
  475. WCHAR str[4];
  476. if(WinntBased && !AllowRollback) {
  477. if(SourcePath[0] && (SourcePath[1] == L':') && (SourcePath[2] == L'\\')) {
  478. lstrcpyn(str,SourcePath,4);
  479. if(GetDriveType(str) != DRIVE_CDROM) {
  480. Delnode(SourcePath);
  481. #ifdef _X86_
  482. if (IsNEC_98 && !lstrcmpi(&SourcePath[2], pwLocalSource)) {
  483. HKEY hkey;
  484. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"System\\Setup",0,MAXIMUM_ALLOWED,&hkey) == NO_ERROR) {
  485. RegDeleteValue(hkey, L"ForcePlatform");
  486. RegCloseKey(hkey);
  487. }
  488. }
  489. #endif
  490. }
  491. }
  492. #if defined(_AMD64_) || defined(_X86_)
  493. //
  494. // Get rid of floppyless boot stuff.
  495. //
  496. if(FloppylessBootPath[0]) {
  497. WCHAR Path[MAX_PATH];
  498. //
  499. // NEC98 should back boot related files in \$WIN_NT$.~BU,
  500. // to restore boot files for keep original OS in each partition.
  501. //
  502. if (IsNEC_98) { //NEC98
  503. lstrcpy(Path,FloppylessBootPath);
  504. pSetupConcatenatePaths(Path,L"$WIN_NT$.~BU",MAX_PATH,NULL);
  505. Delnode(Path);
  506. } //NEC98
  507. lstrcpy(Path,FloppylessBootPath);
  508. pSetupConcatenatePaths(Path,L"$WIN_NT$.~BT",MAX_PATH,NULL);
  509. Delnode(Path);
  510. lstrcpy(Path,FloppylessBootPath);
  511. pSetupConcatenatePaths(Path,L"$LDR$",MAX_PATH,NULL);
  512. SetFileAttributes(Path,FILE_ATTRIBUTE_NORMAL);
  513. DeleteFile(Path);
  514. lstrcpy(Path,FloppylessBootPath);
  515. pSetupConcatenatePaths(Path,L"TXTSETUP.SIF",MAX_PATH,NULL);
  516. SetFileAttributes(Path,FILE_ATTRIBUTE_NORMAL);
  517. DeleteFile(Path);
  518. //
  519. // Get rid of arc loader files.
  520. //
  521. if( !IsArc() ) {
  522. lstrcpy(Path,FloppylessBootPath);
  523. pSetupConcatenatePaths(Path,L"ARCLDR.EXE",MAX_PATH,NULL);
  524. SetFileAttributes(Path,FILE_ATTRIBUTE_NORMAL);
  525. DeleteFile(Path);
  526. lstrcpy(Path,FloppylessBootPath);
  527. pSetupConcatenatePaths(Path,L"ARCSETUP.EXE",MAX_PATH,NULL);
  528. SetFileAttributes(Path,FILE_ATTRIBUTE_NORMAL);
  529. DeleteFile(Path);
  530. }
  531. }
  532. //
  533. // get rid of the boot.bak file
  534. //
  535. {
  536. WCHAR szBootBak[] = L"?:\\BOOT.BAK";
  537. szBootBak[0] = x86SystemPartitionDrive;
  538. SetFileAttributes(szBootBak,FILE_ATTRIBUTE_NORMAL);
  539. DeleteFile(szBootBak);
  540. }
  541. #endif // defined(_AMD64_) || defined(_X86_)
  542. #if defined(_IA64_)
  543. //
  544. // Get rid of SETUPLDR
  545. //
  546. {
  547. WCHAR Path[MAX_PATH];
  548. UNICODE_STRING UnicodeString;
  549. WCHAR Buffer[MAX_PATH];
  550. PWCHAR pwChar;
  551. PWSTR NtPath;
  552. BOOLEAN OldPriv, DontCare;
  553. OBJECT_ATTRIBUTES ObjAttrib;
  554. Buffer[0] = UNICODE_NULL;
  555. //
  556. // Make sure we have privilege to get/set nvram vars.
  557. //
  558. RtlAdjustPrivilege(
  559. SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
  560. TRUE,
  561. FALSE,
  562. &OldPriv
  563. );
  564. RtlInitUnicodeString(&UnicodeString,L"SYSTEMPARTITION");
  565. NtQuerySystemEnvironmentValue(
  566. &UnicodeString,
  567. Buffer,
  568. sizeof(Buffer)/sizeof(WCHAR),
  569. NULL
  570. );
  571. //
  572. // Restore previous privilege.
  573. //
  574. RtlAdjustPrivilege(
  575. SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
  576. OldPriv,
  577. FALSE,
  578. &DontCare
  579. );
  580. //
  581. // Strip everything from ';' to end of string since previous strings
  582. // are appended to the current string and are separated by ';'.
  583. //
  584. pwChar = Buffer;
  585. while ((*pwChar != L'\0') && (*pwChar != L';')) {
  586. pwChar++;
  587. }
  588. *pwChar = L'\0';
  589. NtPath = ArcDevicePathToNtPath(Buffer);
  590. if (NtPath) {
  591. lstrcpy(Path,NtPath);
  592. pSetupConcatenatePaths(Path,SETUPLDR,MAX_PATH,NULL);
  593. RtlInitUnicodeString(&UnicodeString,Path);
  594. InitializeObjectAttributes(
  595. &ObjAttrib,
  596. &UnicodeString,
  597. OBJ_CASE_INSENSITIVE,
  598. NULL,
  599. NULL
  600. );
  601. NtDeleteFile(&ObjAttrib);
  602. MyFree( NtPath );
  603. }
  604. }
  605. #endif // defined(_IA64_)
  606. }
  607. }
  608. BOOL
  609. ValidateAndChecksumFile(
  610. IN PCTSTR Filename,
  611. OUT PBOOLEAN IsNtImage,
  612. OUT PULONG Checksum,
  613. OUT PBOOLEAN Valid
  614. )
  615. /*++
  616. Routine Description:
  617. Calculate a checksum value for a file using the standard
  618. nt image checksum method. If the file is an nt image, validate
  619. the image using the partial checksum in the image header. If the
  620. file is not an nt image, it is simply defined as valid.
  621. If we encounter an i/o error while checksumming, then the file
  622. is declared invalid.
  623. Arguments:
  624. Filename - supplies full NT path of file to check.
  625. IsNtImage - Receives flag indicating whether the file is an
  626. NT image file.
  627. Checksum - receives 32-bit checksum value.
  628. Valid - receives flag indicating whether the file is a valid
  629. image (for nt images) and that we can read the image.
  630. Return Value:
  631. BOOL - Returns TRUE if the flie was validated, and in this case,
  632. IsNtImage, Checksum, and Valid will contain the result of
  633. the validation.
  634. This function will return FALSE, if the file could not be
  635. validated, and in this case, the caller should call GetLastError()
  636. to find out why this function failed.
  637. --*/
  638. {
  639. DWORD Error;
  640. PVOID BaseAddress;
  641. ULONG FileSize;
  642. HANDLE hFile,hSection;
  643. PIMAGE_NT_HEADERS NtHeaders;
  644. ULONG HeaderSum;
  645. //
  646. // Assume not an image and failure.
  647. //
  648. *IsNtImage = FALSE;
  649. *Checksum = 0;
  650. *Valid = FALSE;
  651. //
  652. // Open and map the file for read access.
  653. //
  654. Error = pSetupOpenAndMapFileForRead( Filename,
  655. &FileSize,
  656. &hFile,
  657. &hSection,
  658. &BaseAddress );
  659. if( Error != ERROR_SUCCESS ) {
  660. SetLastError( Error );
  661. return(FALSE);
  662. }
  663. if( FileSize == 0 ) {
  664. *IsNtImage = FALSE;
  665. *Checksum = 0;
  666. *Valid = TRUE;
  667. CloseHandle( hFile );
  668. return(TRUE);
  669. }
  670. try {
  671. NtHeaders = CheckSumMappedFile(BaseAddress,FileSize,&HeaderSum,Checksum);
  672. } except(EXCEPTION_EXECUTE_HANDLER) {
  673. *Checksum = 0;
  674. NtHeaders = NULL;
  675. }
  676. //
  677. // If the file is not an image and we got this far (as opposed to encountering
  678. // an i/o error) then the checksum is declared valid. If the file is an image,
  679. // then its checksum may or may not be valid.
  680. //
  681. if(NtHeaders) {
  682. *IsNtImage = TRUE;
  683. *Valid = HeaderSum ? (*Checksum == HeaderSum) : TRUE;
  684. } else {
  685. *Valid = TRUE;
  686. }
  687. pSetupUnmapAndCloseFile( hFile, hSection, BaseAddress );
  688. return( TRUE );
  689. }
  690. DWORD
  691. QueryHardDiskNumber(
  692. IN UCHAR DriveLetter
  693. )
  694. {
  695. WCHAR driveName[10];
  696. HANDLE h;
  697. BOOL b;
  698. STORAGE_DEVICE_NUMBER number;
  699. DWORD bytes;
  700. driveName[0] = '\\';
  701. driveName[1] = '\\';
  702. driveName[2] = '.';
  703. driveName[3] = '\\';
  704. driveName[4] = DriveLetter;
  705. driveName[5] = ':';
  706. driveName[6] = 0;
  707. h = CreateFile(driveName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  708. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  709. INVALID_HANDLE_VALUE);
  710. if (h == INVALID_HANDLE_VALUE) {
  711. return (DWORD) -1;
  712. }
  713. b = DeviceIoControl(h, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
  714. &number, sizeof(number), &bytes, NULL);
  715. CloseHandle(h);
  716. if (!b) {
  717. return (DWORD) -1;
  718. }
  719. return number.DeviceNumber;
  720. }
  721. BOOL
  722. ExtendPartition(
  723. IN WCHAR DriveLetter,
  724. IN ULONG SizeMB OPTIONAL
  725. )
  726. /*++
  727. Routine Description:
  728. This function will extend a partition.
  729. We'll do this in the following way:
  730. 1. Figure out if the partition is NTFS.
  731. 2. Figure out if there's any unpartitioned space behind
  732. the partition the user is asking us to extend.
  733. 3. How much space is available?
  734. 4. Extend the partition
  735. 5. Extend the filesystem (inform him the partition is bigger).
  736. Arguments:
  737. DriveLetter - Supplies the driveletter for the partition
  738. that we'll be extending.
  739. SizeMB - if specified, indicates the size in MB by which
  740. the partition will grow. If not specified, the
  741. partition grows to encompass all the free space
  742. in the adjacent free space.
  743. Return Value:
  744. Boolean value indicating whether anything actually changed.
  745. --*/
  746. {
  747. #define LEAVE_FREE_BUFFER (5 * (1024*1024))
  748. HANDLE h;
  749. PARTITION_INFORMATION_EX PartitionInfo;
  750. BOOL b;
  751. DWORD Bytes;
  752. DISK_GEOMETRY Geometry;
  753. DISK_GROW_PARTITION GrowInfo;
  754. TCHAR PhysicalName[MAX_PATH];
  755. TCHAR DosName[10];
  756. LARGE_INTEGER BytesAvailable;
  757. LARGE_INTEGER OurPartitionEndingLocation;
  758. DWORD i;
  759. PDRIVE_LAYOUT_INFORMATION_EX DriveLayout;
  760. //
  761. // =====================================
  762. // 1. Figure out if the partition is NTFS.
  763. // =====================================
  764. //
  765. DosName[0] = DriveLetter;
  766. DosName[1] = TEXT(':');
  767. DosName[2] = TEXT('\\');
  768. DosName[3] = TEXT('\0');
  769. b = GetVolumeInformation(
  770. DosName,
  771. NULL,0, // don't care about volume name
  772. NULL, // ...or serial #
  773. &i, // ...or max component length
  774. &i, // ... or flags
  775. PhysicalName,
  776. sizeof(PhysicalName)/sizeof(TCHAR)
  777. );
  778. if( !b ) {
  779. return FALSE;
  780. }
  781. if(lstrcmpi(PhysicalName,TEXT("NTFS"))) {
  782. //
  783. // Our partition isn't NTFS. Bail.
  784. //
  785. DbgPrintEx( DPFLTR_SETUP_ID,
  786. DPFLTR_INFO_LEVEL,
  787. "ExtendPartition: %ws is not NTFS volume\n",
  788. DosName);
  789. return FALSE;
  790. }
  791. //
  792. // Now initialize the name for this partition and
  793. // the name for this drive.
  794. //
  795. wsprintf( DosName, TEXT("\\\\.\\%c:"), DriveLetter );
  796. wsprintf( PhysicalName, TEXT("\\\\.\\PhysicalDrive%u"), QueryHardDiskNumber( (UCHAR)DriveLetter) );
  797. //
  798. // =====================================
  799. // 2. Figure out if there's any unpartitioned space behind
  800. // the partition the user is asking us to extend.
  801. // =====================================
  802. //
  803. //
  804. // Get a handle to the disk so we can start examination.
  805. //
  806. h = CreateFile( PhysicalName,
  807. GENERIC_READ | GENERIC_WRITE,
  808. FILE_SHARE_READ | FILE_SHARE_WRITE,
  809. NULL,
  810. OPEN_EXISTING,
  811. FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING,
  812. NULL );
  813. if( h == INVALID_HANDLE_VALUE ) {
  814. DbgPrintEx( DPFLTR_SETUP_ID,
  815. DPFLTR_INFO_LEVEL,
  816. "ExtendPartition: %X Error while opening %ws\n",
  817. GetLastError(),
  818. PhysicalName);
  819. return FALSE;
  820. }
  821. //
  822. // Get the disk's layout information. We aren't
  823. // sure how big of a buffer we need, so brute-force it.
  824. //
  825. {
  826. DWORD DriveLayoutSize = 1024;
  827. PVOID p;
  828. DriveLayout = MyMalloc(DriveLayoutSize);
  829. if( !DriveLayout ) {
  830. CloseHandle( h );
  831. return FALSE;
  832. }
  833. retry:
  834. b = DeviceIoControl( h,
  835. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  836. NULL,
  837. 0,
  838. (PVOID)DriveLayout,
  839. DriveLayoutSize,
  840. &Bytes,
  841. NULL );
  842. if( !b ) {
  843. DWORD LastError = GetLastError();
  844. if (LastError == ERROR_INSUFFICIENT_BUFFER) {
  845. DriveLayoutSize += 1024;
  846. if(p = MyRealloc((PVOID)DriveLayout,DriveLayoutSize)) {
  847. (PVOID)DriveLayout = p;
  848. } else {
  849. goto cleanexit0;
  850. }
  851. goto retry;
  852. } else {
  853. DbgPrintEx( DPFLTR_SETUP_ID,
  854. DPFLTR_INFO_LEVEL,
  855. "ExtendPartition: %X Error while getting drive layout for %ws\n",
  856. LastError,
  857. PhysicalName);
  858. goto cleanexit0;
  859. }
  860. }
  861. }
  862. CloseHandle( h );
  863. h = INVALID_HANDLE_VALUE;
  864. //
  865. // DriveLayout now is full of most of the information we
  866. // need, including an array of partition information. But
  867. // we aren't sure which partition is ours. We need to
  868. // get info on our specific partition, then match it
  869. // against the entry inside DriveLayout.
  870. //
  871. //
  872. // Open a handle to the partition.
  873. //
  874. h = CreateFile( DosName,
  875. GENERIC_READ,
  876. FILE_SHARE_READ | FILE_SHARE_WRITE,
  877. NULL,
  878. OPEN_EXISTING,
  879. FILE_ATTRIBUTE_NORMAL,
  880. INVALID_HANDLE_VALUE );
  881. if( h == INVALID_HANDLE_VALUE ) {
  882. DbgPrintEx( DPFLTR_SETUP_ID,
  883. DPFLTR_INFO_LEVEL,
  884. "ExtendPartition: %X Error while opening %ws\n",
  885. GetLastError(),
  886. DosName);
  887. return FALSE;
  888. }
  889. //
  890. // Load info about our partition.
  891. //
  892. b = DeviceIoControl( h,
  893. IOCTL_DISK_GET_PARTITION_INFO_EX,
  894. NULL,
  895. 0,
  896. &PartitionInfo,
  897. sizeof(PartitionInfo),
  898. &Bytes,
  899. NULL );
  900. if( !b ) {
  901. DbgPrintEx( DPFLTR_SETUP_ID,
  902. DPFLTR_INFO_LEVEL,
  903. "ExtendPartition: %X Error while getting %ws's partition information\n",
  904. GetLastError(),
  905. DosName);
  906. goto cleanexit0;
  907. }
  908. //
  909. // Might as well get the geometry info on the disk too.
  910. //
  911. b = DeviceIoControl( h,
  912. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  913. NULL,
  914. 0,
  915. &Geometry,
  916. sizeof(Geometry),
  917. &Bytes,
  918. NULL );
  919. if( !b ) {
  920. DbgPrintEx( DPFLTR_SETUP_ID,
  921. DPFLTR_INFO_LEVEL,
  922. "ExtendPartition: %X Error while getting %ws's drive geometry\n",
  923. GetLastError(),
  924. DosName);
  925. goto cleanexit0;
  926. }
  927. CloseHandle( h );
  928. h = INVALID_HANDLE_VALUE;
  929. //
  930. // =====================================
  931. // 3. How much space is available?
  932. // =====================================
  933. //
  934. //
  935. // We're ready to actually verify that there's rooom for us to grow.
  936. // If we're the last partition on the disk, we need to see if there's
  937. // any room behind us (i.e. any unpartitioned space). If we're not
  938. // the last partition, we need to see if there's any space between where
  939. // our partition ends and the next partition begins.
  940. //
  941. // This is really gross, but DriveLayout->PartitionCount will likely be 4
  942. // even if there's really only 1 formatted partition on the disk. We also
  943. // don't want to take the chance that the partitions aren't ordered by their
  944. // location on the disk. So we need to go cycle through the partitions
  945. // again and manually find the one that starts right after ours.
  946. //
  947. OurPartitionEndingLocation.QuadPart = PartitionInfo.StartingOffset.QuadPart + PartitionInfo.PartitionLength.QuadPart;
  948. //
  949. // Initialize BytesAvailable based on the space from where our partition ends to where
  950. // the disk ends. This is the best case and we can only get smaller sizes, so this
  951. // is safe.
  952. //
  953. BytesAvailable.QuadPart = UInt32x32To64( Geometry.BytesPerSector, Geometry.SectorsPerTrack );
  954. BytesAvailable.QuadPart = BytesAvailable.QuadPart * (ULONGLONG)(Geometry.TracksPerCylinder);
  955. BytesAvailable.QuadPart = BytesAvailable.QuadPart * Geometry.Cylinders.QuadPart;
  956. BytesAvailable.QuadPart = BytesAvailable.QuadPart - OurPartitionEndingLocation.QuadPart;
  957. for( i = 0; i < DriveLayout->PartitionCount; i++ ) {
  958. if( (DriveLayout->PartitionEntry[i].StartingOffset.QuadPart > OurPartitionEndingLocation.QuadPart) &&
  959. ((DriveLayout->PartitionEntry[i].StartingOffset.QuadPart - OurPartitionEndingLocation.QuadPart) < BytesAvailable.QuadPart) ) {
  960. //
  961. // This partition is starting after ours and it's also the closest one we've found
  962. // to our ending location.
  963. //
  964. BytesAvailable.QuadPart = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart - OurPartitionEndingLocation.QuadPart;
  965. }
  966. }
  967. //
  968. // Reserve the space at the disk end only for MBR disks
  969. //
  970. if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR) {
  971. //
  972. // If we don't have at least 5MB available, don't even bother. If we do, leave the last
  973. // 5MB free for later use as a dynamic volume.
  974. //
  975. if( BytesAvailable.QuadPart < (ULONGLONG)(LEAVE_FREE_BUFFER) ) {
  976. goto cleanexit0;
  977. } else {
  978. BytesAvailable.QuadPart = BytesAvailable.QuadPart - (ULONGLONG)(LEAVE_FREE_BUFFER);
  979. }
  980. }
  981. //
  982. // See if the user has asked us to extend by some known value...
  983. //
  984. if( SizeMB ) {
  985. //
  986. // Yes. Make sure we have atleast this much space to extend.
  987. //
  988. if( (LONGLONG)(SizeMB * (1024*1024)) < BytesAvailable.QuadPart ) {
  989. BytesAvailable.QuadPart = UInt32x32To64( SizeMB, (1024*1024) );
  990. }
  991. }
  992. //
  993. // =====================================
  994. // 4. Extend the partition
  995. // =====================================
  996. //
  997. //
  998. // Get a handle to the disk.
  999. //
  1000. h = CreateFile( PhysicalName,
  1001. GENERIC_READ | GENERIC_WRITE,
  1002. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1003. NULL,
  1004. OPEN_EXISTING,
  1005. FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING,
  1006. NULL );
  1007. if( h == INVALID_HANDLE_VALUE ) {
  1008. DbgPrintEx( DPFLTR_SETUP_ID,
  1009. DPFLTR_INFO_LEVEL,
  1010. "ExtendPartition: %X Error while opening %ws\n",
  1011. GetLastError(),
  1012. PhysicalName);
  1013. return FALSE;
  1014. }
  1015. //
  1016. // Fill in the datastructure we'll be sending to the IOCTL.
  1017. //
  1018. GrowInfo.PartitionNumber = PartitionInfo.PartitionNumber;
  1019. GrowInfo.BytesToGrow = BytesAvailable;
  1020. //
  1021. // Do it.
  1022. //
  1023. b = DeviceIoControl( h,
  1024. IOCTL_DISK_GROW_PARTITION,
  1025. &GrowInfo,
  1026. sizeof(GrowInfo),
  1027. NULL,
  1028. 0,
  1029. &Bytes,
  1030. NULL );
  1031. if( !b ) {
  1032. DbgPrintEx( DPFLTR_SETUP_ID,
  1033. DPFLTR_INFO_LEVEL,
  1034. "ExtendPartition: %X Error while growing %ws partition\n",
  1035. GetLastError(),
  1036. PhysicalName);
  1037. goto cleanexit0;
  1038. }
  1039. CloseHandle( h );
  1040. h = INVALID_HANDLE_VALUE;
  1041. //
  1042. // =====================================
  1043. // 5. Extend the filesystem (inform him the partition is bigger).
  1044. // =====================================
  1045. //
  1046. //
  1047. // Get a handle to the partition.
  1048. //
  1049. h = CreateFile( DosName,
  1050. GENERIC_READ,
  1051. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1052. NULL,
  1053. OPEN_EXISTING,
  1054. FILE_ATTRIBUTE_NORMAL,
  1055. INVALID_HANDLE_VALUE );
  1056. if( h == INVALID_HANDLE_VALUE ) {
  1057. DbgPrintEx( DPFLTR_SETUP_ID,
  1058. DPFLTR_INFO_LEVEL,
  1059. "ExtendPartition: %X Error while opening %ws\n",
  1060. GetLastError(),
  1061. DosName);
  1062. goto cleanexit0;
  1063. }
  1064. //
  1065. // Gather some info on the partition.
  1066. //
  1067. b = DeviceIoControl( h,
  1068. IOCTL_DISK_GET_PARTITION_INFO_EX,
  1069. NULL,
  1070. 0,
  1071. &PartitionInfo,
  1072. sizeof(PartitionInfo),
  1073. &Bytes,
  1074. NULL );
  1075. if( !b ) {
  1076. DbgPrintEx( DPFLTR_SETUP_ID,
  1077. DPFLTR_INFO_LEVEL,
  1078. "ExtendPartition: %X Error while getting %ws's partition information\n",
  1079. GetLastError(),
  1080. DosName);
  1081. goto cleanexit0;
  1082. }
  1083. //
  1084. // Grow the volume.
  1085. //
  1086. BytesAvailable.QuadPart = PartitionInfo.PartitionLength.QuadPart / Geometry.BytesPerSector;
  1087. b = DeviceIoControl( h,
  1088. FSCTL_EXTEND_VOLUME,
  1089. &BytesAvailable,
  1090. sizeof(BytesAvailable),
  1091. NULL,
  1092. 0,
  1093. &Bytes,
  1094. NULL );
  1095. if( !b ) {
  1096. DbgPrintEx( DPFLTR_SETUP_ID,
  1097. DPFLTR_INFO_LEVEL,
  1098. "ExtendPartition: %X Error while extending volume %ws\n",
  1099. GetLastError(),
  1100. DosName);
  1101. goto cleanexit0;
  1102. }
  1103. cleanexit0:
  1104. if( h != INVALID_HANDLE_VALUE ) {
  1105. CloseHandle( h );
  1106. }
  1107. //
  1108. // If we successfully extended the partition
  1109. // then mark the global flag to remove any
  1110. // stale volume information, at the end of setup.
  1111. //
  1112. if (b) {
  1113. PartitionExtended = TRUE;
  1114. }
  1115. return b;
  1116. }
  1117. BOOL
  1118. SetupExtendPartition(
  1119. IN WCHAR DriveLetter,
  1120. IN ULONG SizeMB OPTIONAL
  1121. )
  1122. {
  1123. BOOL b;
  1124. if ( b = ExtendPartition(DriveLetter, SizeMB) )
  1125. {
  1126. RemoveStaleVolumes();
  1127. PartitionExtended = FALSE;
  1128. }
  1129. return b;
  1130. }
  1131. BOOL
  1132. DoFilesMatch(
  1133. IN PCWSTR File1,
  1134. IN PCWSTR File2
  1135. )
  1136. /*++
  1137. Routine Description:
  1138. Compares two files to each other to see if they are identical.
  1139. Arguments:
  1140. File1 - First file to compare
  1141. File2 - Second file to compare
  1142. Return Value:
  1143. BOOL - Returns TRUE if the files match. If the both of the files are zero
  1144. length, then we still return TRUE.
  1145. --*/
  1146. {
  1147. DWORD FirstFileSize, SecondFileSize;
  1148. HANDLE FirstFileHandle, FirstMappingHandle;
  1149. HANDLE SecondFileHandle, SecondMappingHandle;
  1150. PVOID FirstBaseAddress, SecondBaseAddress;
  1151. BOOL RetVal = FALSE;
  1152. if( (pSetupOpenAndMapFileForRead(
  1153. File1,
  1154. &FirstFileSize,
  1155. &FirstFileHandle,
  1156. &FirstMappingHandle,
  1157. &FirstBaseAddress) == NO_ERROR)
  1158. && (pSetupOpenAndMapFileForRead(
  1159. File1,
  1160. &SecondFileSize,
  1161. &SecondFileHandle,
  1162. &SecondMappingHandle,
  1163. &SecondBaseAddress) == NO_ERROR) ) {
  1164. if (FirstFileSize == SecondFileSize ) {
  1165. if (FirstFileSize != 0) {
  1166. //
  1167. // protect against inpage IO error
  1168. //
  1169. try {
  1170. RetVal = !memcmp(
  1171. FirstBaseAddress,
  1172. SecondBaseAddress,
  1173. FirstFileSize
  1174. );
  1175. } except(EXCEPTION_EXECUTE_HANDLER) {
  1176. RetVal = FALSE;
  1177. }
  1178. }
  1179. }
  1180. pSetupUnmapAndCloseFile(
  1181. FirstFileHandle,
  1182. FirstMappingHandle,
  1183. FirstBaseAddress
  1184. );
  1185. pSetupUnmapAndCloseFile(
  1186. SecondFileHandle,
  1187. SecondMappingHandle,
  1188. SecondBaseAddress
  1189. );
  1190. }
  1191. return (RetVal);
  1192. }
  1193. DWORD
  1194. RemoveStaleVolumes(
  1195. VOID
  1196. )
  1197. /*++
  1198. Routine Description:
  1199. This routine walks through all the volumes and deletes the one
  1200. which are marked for reinstall.
  1201. NOTE : Use the function carefully because it will nuke all
  1202. the entries related to the volume from the registry, iff the volume
  1203. says it needs to be reinstalled.
  1204. Arguments:
  1205. None.
  1206. Return Value:
  1207. Appropriate Win32 error code.
  1208. --*/
  1209. {
  1210. const TCHAR *VolumeKeyName = TEXT("System\\CurrentControlSet\\Enum\\Storage\\Volume");
  1211. const TCHAR *ClassKeyName = TEXT("System\\CurrentControlSet\\Control\\Class");
  1212. DWORD ErrorCode;
  1213. HKEY VolumeKey = NULL;
  1214. HKEY ClassKey = NULL;
  1215. ULONG Index = 0;
  1216. ULONG VolumesFixedCount = 0;
  1217. TCHAR SubKeyName[MAX_PATH*2];
  1218. DWORD SubKeyLength;
  1219. FILETIME SubKeyTime;
  1220. //
  1221. // Open the Volume key
  1222. //
  1223. ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1224. VolumeKeyName,
  1225. 0,
  1226. KEY_ALL_ACCESS,
  1227. &VolumeKey);
  1228. if (VolumeKey == NULL) {
  1229. ErrorCode = ERROR_INVALID_HANDLE;
  1230. }
  1231. if (ErrorCode != ERROR_SUCCESS) {
  1232. return ErrorCode;
  1233. }
  1234. //
  1235. // Open the Class key
  1236. //
  1237. ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1238. ClassKeyName,
  1239. 0,
  1240. KEY_ALL_ACCESS,
  1241. &ClassKey);
  1242. if (ClassKey == NULL) {
  1243. ErrorCode = ERROR_INVALID_HANDLE;
  1244. }
  1245. if (ErrorCode != ERROR_SUCCESS) {
  1246. RegCloseKey(VolumeKey);
  1247. return ErrorCode;
  1248. }
  1249. //
  1250. // Enumerate each subkey of the opened key
  1251. //
  1252. while (TRUE) {
  1253. SubKeyName[0] = 0;
  1254. SubKeyLength = sizeof(SubKeyName) / sizeof(SubKeyName[0]);
  1255. ErrorCode = RegEnumKeyEx(VolumeKey,
  1256. Index,
  1257. SubKeyName,
  1258. &SubKeyLength,
  1259. NULL,
  1260. NULL,
  1261. NULL,
  1262. &SubKeyTime);
  1263. if (ErrorCode == ERROR_SUCCESS) {
  1264. TCHAR FullSubKeyName[MAX_PATH*4];
  1265. DWORD SubErrorCode;
  1266. HKEY CurrentSubKey = NULL;
  1267. GUID VolumeGuid = {0};
  1268. TCHAR VolumeGuidStr[MAX_PATH] = {0};
  1269. DWORD DrvInstance = -1;
  1270. BOOL DeleteKey = FALSE;
  1271. BOOL DeleteClassInstance = FALSE;
  1272. BOOL IncrementKeyIndex = TRUE;
  1273. _tcscpy(FullSubKeyName, VolumeKeyName);
  1274. _tcscat(FullSubKeyName, TEXT("\\"));
  1275. _tcscat(FullSubKeyName, SubKeyName);
  1276. SubErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1277. FullSubKeyName,
  1278. 0,
  1279. KEY_ALL_ACCESS,
  1280. &CurrentSubKey);
  1281. if (SubErrorCode == ERROR_SUCCESS) {
  1282. //
  1283. // Read the ConfigFlags value
  1284. //
  1285. DWORD ConfigFlags = 0;
  1286. DWORD Type = REG_DWORD;
  1287. DWORD BufferSize = sizeof(DWORD);
  1288. SubErrorCode = RegQueryValueEx(CurrentSubKey,
  1289. TEXT("ConfigFlags"),
  1290. NULL,
  1291. &Type,
  1292. (PBYTE)&ConfigFlags,
  1293. &BufferSize);
  1294. if (SubErrorCode == ERROR_SUCCESS) {
  1295. DeleteKey = (ConfigFlags & (CONFIGFLAG_REINSTALL | CONFIGFLAG_FINISH_INSTALL));
  1296. if (DeleteKey) {
  1297. Type = REG_BINARY;
  1298. BufferSize = sizeof(VolumeGuid);
  1299. //
  1300. // Read the GUID & DrvInst values
  1301. //
  1302. SubErrorCode = RegQueryValueEx(CurrentSubKey,
  1303. TEXT("GUID"),
  1304. NULL,
  1305. &Type,
  1306. (PBYTE)&VolumeGuid,
  1307. &BufferSize);
  1308. if (SubErrorCode == ERROR_SUCCESS) {
  1309. Type = REG_DWORD;
  1310. BufferSize = sizeof(DWORD);
  1311. SubErrorCode = RegQueryValueEx(CurrentSubKey,
  1312. TEXT("DrvInst"),
  1313. NULL,
  1314. &Type,
  1315. (PBYTE)&DrvInstance,
  1316. &BufferSize);
  1317. DeleteClassInstance =
  1318. (SubErrorCode == ERROR_SUCCESS) &&
  1319. (DrvInstance != -1);
  1320. }
  1321. }
  1322. }
  1323. //
  1324. // Close the current subkey since we don't need it anymore
  1325. //
  1326. RegCloseKey(CurrentSubKey);
  1327. //
  1328. // Delete after we close the current key
  1329. //
  1330. if (DeleteKey) {
  1331. SubErrorCode = SHDeleteKey(HKEY_LOCAL_MACHINE,
  1332. FullSubKeyName);
  1333. if (SubErrorCode == ERROR_SUCCESS) {
  1334. VolumesFixedCount++;
  1335. IncrementKeyIndex = FALSE;
  1336. }
  1337. }
  1338. //
  1339. // Delete the instance key under class also if needed
  1340. //
  1341. if (DeleteClassInstance &&
  1342. (pSetupStringFromGuid(&VolumeGuid,
  1343. VolumeGuidStr,
  1344. sizeof(VolumeGuidStr)/sizeof(VolumeGuidStr[0])) == ERROR_SUCCESS)) {
  1345. _stprintf(FullSubKeyName,
  1346. TEXT("System\\CurrentControlSet\\Control\\Class\\%ws\\%04d"),
  1347. VolumeGuidStr,
  1348. DrvInstance);
  1349. SubErrorCode = SHDeleteKey(HKEY_LOCAL_MACHINE,
  1350. FullSubKeyName);
  1351. }
  1352. }
  1353. if (IncrementKeyIndex) {
  1354. Index++;
  1355. }
  1356. } else {
  1357. break; // we couldn't enumerate further sub keys
  1358. }
  1359. }
  1360. RegCloseKey(ClassKey);
  1361. RegCloseKey(VolumeKey);
  1362. //
  1363. // If we fixed at least a single volume then assume things
  1364. // went fine
  1365. //
  1366. if (VolumesFixedCount > 0) {
  1367. ErrorCode = ERROR_SUCCESS;
  1368. }
  1369. return ErrorCode;
  1370. }
  1371. #define MAX_NT_PATH (MAX_PATH + 4)//"\\??\\"
  1372. #define UNDO_FILE_NAME L"UNDO_GUIMODE.TXT"
  1373. VOID
  1374. RemoveAllPendingOperationsOnRestartOfGUIMode(
  1375. VOID
  1376. )
  1377. {
  1378. WCHAR undoFilePath[MAX_PATH];
  1379. if(!GetWindowsDirectoryW(undoFilePath, ARRAYSIZE(undoFilePath))){
  1380. ASSERT(FALSE);
  1381. return;
  1382. }
  1383. wcscat(undoFilePath, L"\\system32\\");
  1384. wcscat(undoFilePath, UNDO_FILE_NAME);
  1385. SetFileAttributes(undoFilePath, FILE_ATTRIBUTE_NORMAL);
  1386. DeleteFile(undoFilePath);
  1387. }
  1388. BOOL
  1389. RenameOnRestartOfGUIMode(
  1390. IN PCWSTR pPathName,
  1391. IN PCWSTR pPathNameNew
  1392. )
  1393. {
  1394. DWORD Size;
  1395. BOOL result;
  1396. WCHAR undoFilePath[MAX_PATH];
  1397. WCHAR RenameOperationBuffer[2 * (MAX_NT_PATH + 2/*'\r\n'*/)];
  1398. HANDLE fileUndo;
  1399. BYTE signUnicode[] = {0xff, 0xfe};
  1400. if(!pPathName){
  1401. return FALSE;
  1402. }
  1403. if(!GetWindowsDirectoryW(undoFilePath, ARRAYSIZE(undoFilePath))){
  1404. return FALSE;
  1405. }
  1406. wcscat(undoFilePath, L"\\system32\\" UNDO_FILE_NAME);
  1407. wsprintfW(RenameOperationBuffer, L"\\??\\%s\r\n", pPathName);
  1408. if(pPathNameNew){
  1409. wsprintfW(RenameOperationBuffer + wcslen(RenameOperationBuffer),
  1410. L"\\??\\%s",
  1411. pPathNameNew);
  1412. }
  1413. wcscat(RenameOperationBuffer, L"\r\n");
  1414. fileUndo = CreateFileW(undoFilePath,
  1415. GENERIC_WRITE,
  1416. FILE_SHARE_READ,
  1417. NULL,
  1418. OPEN_ALWAYS,
  1419. FILE_ATTRIBUTE_NORMAL,
  1420. NULL);
  1421. if(INVALID_HANDLE_VALUE == fileUndo){
  1422. return FALSE;
  1423. }
  1424. if(!SetFilePointer(fileUndo, 0, NULL, FILE_END)){
  1425. result = WriteFile(fileUndo, signUnicode, sizeof(signUnicode), &Size, NULL);
  1426. }
  1427. else {
  1428. result = TRUE;
  1429. }
  1430. if(result){
  1431. result = WriteFile(fileUndo,
  1432. RenameOperationBuffer,
  1433. wcslen(RenameOperationBuffer) * sizeof(WCHAR),
  1434. &Size,
  1435. NULL);
  1436. }
  1437. CloseHandle(fileUndo);
  1438. return result;
  1439. }
  1440. BOOL
  1441. DeleteOnRestartOfGUIMode(
  1442. IN PCWSTR pPathName
  1443. )
  1444. {
  1445. return RenameOnRestartOfGUIMode(pPathName, NULL);
  1446. }