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.

1022 lines
25 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. confdisk.cpp
  5. Abstract:
  6. Utility program to create an ASR state-file (asr.sif), or restore
  7. non-critical disk layout based on a previously created asr.sif.
  8. Author:
  9. Guhan Suriyanarayanan (guhans) 15-April-2001
  10. Environment:
  11. User-mode only.
  12. Revision History:
  13. 15-Apr-2001 guhans
  14. Initial creation
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <stdio.h>
  20. #include <windows.h>
  21. #include <setupapi.h>
  22. #include <winasr.h>
  23. #include "resource.h"
  24. #include "critdrv.h"
  25. #include "confdisk.h"
  26. //
  27. // --------
  28. // global variables used in this module
  29. // --------
  30. //
  31. WCHAR g_szTempBuffer[BUFFER_LENGTH];
  32. HMODULE g_hModule = NULL;
  33. HANDLE g_hHeap = NULL;
  34. BOOL g_fErrorMessageDone = FALSE;
  35. //
  36. // --------
  37. // function implementations
  38. // --------
  39. //
  40. VOID
  41. AsrpPrintError(
  42. IN CONST DWORD dwLineNumber,
  43. IN CONST DWORD dwErrorCode
  44. )
  45. /*++
  46. Routine Description:
  47. Loads an error message based on dwErrorCode from the resources, and
  48. prints it out to screen. There are some error codes that are of
  49. particular interest (that have specific error messages), others
  50. get a generic error message.
  51. Arguments:
  52. dwLineNumber - The line at which the error occured, pass in __LINE__
  53. dwErrorCode - The win-32 error that occured.
  54. Return Value:
  55. None.
  56. --*/
  57. {
  58. //
  59. // Handle the error codes we know and care about
  60. //
  61. switch (dwErrorCode) {
  62. case 0:
  63. break;
  64. default:
  65. //
  66. // Unexpected error, print out generic error message
  67. //
  68. LoadString(g_hModule, IDS_GENERIC_ERROR, g_szTempBuffer, BUFFER_LENGTH);
  69. wprintf(g_szTempBuffer, dwErrorCode, dwLineNumber);
  70. if ((ERROR_SUCCESS != dwErrorCode) &&
  71. (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  72. NULL,
  73. dwErrorCode,
  74. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
  75. g_szTempBuffer,
  76. BUFFER_LENGTH,
  77. NULL
  78. ))) {
  79. wprintf(L" %ws", g_szTempBuffer);
  80. }
  81. wprintf(L"\n");
  82. }
  83. }
  84. PWSTR // must be freed by caller
  85. AsrpExpandEnvStrings(
  86. IN CONST PCWSTR lpOriginalString
  87. )
  88. /*++
  89. Routine Description:
  90. Allocates and returns a pointer to a new string containing a copy of the
  91. original string in which environment-variables replaced by their defined
  92. values.
  93. Uses the Win-32 API ExpandEnvironmentStrings.
  94. The caller must free the returned string using HeapFree(LocalProcessHeap).
  95. Arguments:
  96. lpOriginalString - Pointer to a null-terminated string that contains
  97. environment-variable strings of the form: %variableName%. For
  98. each such reference, the %variableName% portion is replaced
  99. with the current value of that environment variable.
  100. The replacement rules are the same as those used by the command
  101. interpreter. Case is ignored when looking up the environment-
  102. variable name. If the name is not found, the %variableName%
  103. portion is left undisturbed.
  104. Return Value:
  105. If the function succeeds, the return value is a pointer to the destination
  106. string containing the result of the expansion. The caller must free
  107. this memory using HeapFree for the current process heap.
  108. If the function fails, the return value is NULL. To get extended error
  109. information, call GetLastError().
  110. --*/
  111. {
  112. PWSTR lpszResult = NULL;
  113. UINT cchSize = MAX_PATH + 1, // start with a reasonable default
  114. cchRequiredSize = 0;
  115. BOOL bResult = FALSE;
  116. Alloc(lpszResult, PWSTR, cchSize * sizeof(WCHAR));
  117. if (!lpszResult) {
  118. return NULL;
  119. }
  120. cchRequiredSize = ExpandEnvironmentStringsW(lpOriginalString,
  121. lpszResult, cchSize);
  122. if (cchRequiredSize > cchSize) {
  123. //
  124. // Buffer wasn't big enough; free and re-allocate as needed
  125. //
  126. Free(lpszResult);
  127. cchSize = cchRequiredSize + 1;
  128. Alloc(lpszResult, PWSTR, cchSize * sizeof(WCHAR));
  129. if (!lpszResult) {
  130. return NULL;
  131. }
  132. cchRequiredSize = ExpandEnvironmentStringsW(lpOriginalString,
  133. lpszResult, cchSize);
  134. }
  135. if ((0 == cchRequiredSize) || (cchRequiredSize > cchSize)) {
  136. //
  137. // Either the function failed, or the buffer wasn't big enough
  138. // even on the second try
  139. //
  140. Free(lpszResult); // sets it to NULL
  141. }
  142. return lpszResult;
  143. }
  144. DWORD
  145. AsrpPrintUsage()
  146. /*++
  147. Routine Description:
  148. Loads and prints the incorrect-usage error string.
  149. Arguments:
  150. None
  151. Return Values:
  152. None
  153. --*/
  154. {
  155. wcscpy(g_szTempBuffer, L"");
  156. LoadString(g_hModule, IDS_ERROR_USAGE, g_szTempBuffer, BUFFER_LENGTH);
  157. wprintf(g_szTempBuffer, L"confdisk /save ", L"confdisk /restore", L"confdisk /save c:\\asr.sif");
  158. return ERROR_INVALID_PARAMETER;
  159. }
  160. //
  161. // --------
  162. // functions used by /save
  163. // --------
  164. //
  165. BOOL
  166. AsrpAcquirePrivilege(
  167. IN CONST PCWSTR lpPrivilegeName
  168. )
  169. /*++
  170. Routine Description:
  171. Acquires the requested privilege (such as the backup privilege).
  172. Arguments:
  173. lpPrivilegeName - The required privilege (such as SE_BACKUP_NAME)
  174. Return Value:
  175. If the function succeeds, the return value is a nonzero value.
  176. If the function fails, the return value is zero. To get extended error
  177. information, call GetLastError().
  178. --*/
  179. {
  180. HANDLE hToken = NULL;
  181. BOOL bResult = FALSE;
  182. LUID luid;
  183. DWORD dwStatus = ERROR_SUCCESS;
  184. TOKEN_PRIVILEGES tNewState;
  185. bResult = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &hToken);
  186. ErrExitCode(!bResult, dwStatus, GetLastError());
  187. bResult = LookupPrivilegeValue(NULL, lpPrivilegeName, &luid);
  188. ErrExitCode(!bResult, dwStatus, GetLastError());
  189. tNewState.PrivilegeCount = 1;
  190. tNewState.Privileges[0].Luid = luid;
  191. tNewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  192. //
  193. // We will always call GetLastError below, so clear
  194. // any prior error values on this thread.
  195. //
  196. SetLastError(ERROR_SUCCESS);
  197. bResult = AdjustTokenPrivileges(
  198. hToken, // Token Handle
  199. FALSE, // DisableAllPrivileges
  200. &tNewState, // NewState
  201. (DWORD) 0, // BufferLength
  202. NULL, // PreviousState
  203. NULL // ReturnLength
  204. );
  205. //
  206. // Supposedly, AdjustTokenPriveleges always returns TRUE
  207. // (even when it fails). So, call GetLastError to be
  208. // extra sure everything's cool.
  209. //
  210. if (ERROR_SUCCESS != GetLastError()) {
  211. bResult = FALSE;
  212. }
  213. ErrExitCode(!bResult, dwStatus, GetLastError());
  214. EXIT:
  215. _AsrpCloseHandle(hToken);
  216. SetLastError(dwStatus);
  217. return bResult;
  218. }
  219. DWORD
  220. AsrpCreateSif(
  221. IN CONST PCWSTR lpSifPath OPTIONAL
  222. )
  223. /*++
  224. Routine Description:
  225. Creates an ASR state file (asr.sif) at the requested location, using the
  226. ASR API from syssetup.dll.
  227. Arguments:
  228. lpSifPath - A null terminated UNICODE string containing the full path and
  229. file-name of the ASR state file to be created.
  230. This parameter may contain unexpanded environment variables
  231. between "%" signs (such as %systemroot%\repair\asr.sif),
  232. This parameter can be NULL. If it is NULL, the ASR state-file is
  233. created at the default location (%systemroot%\repair\asr.sif).
  234. Return Value:
  235. If the function succeeds, the return value is zero.
  236. If the function fails, the return value is a Win-32 error code.
  237. --*/
  238. {
  239. HMODULE hDll = NULL;
  240. BOOL bResult = FALSE;
  241. DWORD_PTR asrContext = NULL;
  242. DWORD dwStatus = ERROR_SUCCESS;
  243. PWSTR lpProvider = NULL,
  244. lpCriticalVolumes = NULL;
  245. BOOL (*pfnCreateSif)(PCWSTR, PCWSTR, CONST BOOL, PCWSTR, DWORD_PTR*);
  246. BOOL (*pfnFreeContext)(DWORD_PTR* );
  247. pfnCreateSif = NULL;
  248. pfnFreeContext = NULL;
  249. //
  250. // We need to acquire the backup privileges to create asr.sif
  251. //
  252. bResult = AsrpAcquirePrivilege(SE_BACKUP_NAME);
  253. ErrExitCode(!bResult, dwStatus, ERROR_PRIVILEGE_NOT_HELD);
  254. //
  255. // Get the critical volume list
  256. //
  257. lpCriticalVolumes = pFindCriticalVolumes();
  258. ErrExitCode(!lpCriticalVolumes, dwStatus, ERROR_PRIVILEGE_NOT_HELD);
  259. //
  260. // Load syssetup, and find the routines to call
  261. //
  262. hDll = LoadLibraryW(L"syssetup.dll");
  263. ErrExitCode(!hDll, dwStatus, GetLastError());
  264. pfnCreateSif = (BOOL (*)(PCWSTR, PCWSTR, CONST BOOL, PCWSTR, DWORD_PTR*))
  265. GetProcAddress(hDll, "AsrCreateStateFileW");
  266. ErrExitCode(!pfnCreateSif, dwStatus, GetLastError());
  267. pfnFreeContext = (BOOL (*)(DWORD_PTR *))
  268. GetProcAddress(hDll, "AsrFreeContext");
  269. ErrExitCode(!pfnFreeContext, dwStatus, GetLastError());
  270. //
  271. // Finally, call the routine to create the state file:
  272. //
  273. bResult = pfnCreateSif(lpSifPath, // lpFilePath,
  274. lpProvider, // lpProviderName
  275. TRUE, // bEnableAutoExtend
  276. lpCriticalVolumes, // mszCriticalVolumes
  277. &asrContext // lpAsrContext
  278. );
  279. ErrExitCode(!bResult, dwStatus, GetLastError());
  280. EXIT:
  281. //
  282. // Cleanup
  283. //
  284. if (lpCriticalVolumes) {
  285. delete lpCriticalVolumes;
  286. lpCriticalVolumes = NULL;
  287. }
  288. if (pfnFreeContext && asrContext) {
  289. pfnFreeContext(&asrContext);
  290. }
  291. if (hDll) {
  292. FreeLibrary(hDll);
  293. hDll = NULL;
  294. }
  295. return dwStatus;
  296. }
  297. //
  298. // --------
  299. // functions used by /restore
  300. // --------
  301. //
  302. PWSTR
  303. AsrpReadField(
  304. PINFCONTEXT pInfContext,
  305. DWORD dwFieldIndex
  306. )
  307. /*++
  308. Routine Description:
  309. Reads and returns a pointer to string at the specified index from a sif.
  310. The caller must free the returned string using HeapFree(LocalProcessHeap).
  311. Arguments:
  312. pInfContext - The Inf Context to use to read the value, obtained from
  313. SetupGetLineByIndexW.
  314. dwFieldIndex - The 1 based field index of the string value to read.
  315. Return Value:
  316. If the function succeeds, the return value is a pointer to the destination
  317. string. The caller must free this memory using HeapFree for the
  318. current process heap.
  319. If the function fails, the return value is NULL. To get extended error
  320. information, call GetLastError().
  321. --*/
  322. {
  323. DWORD cchReqdSize = 0;
  324. BOOL bResult = FALSE;
  325. PWSTR lpszData = NULL;
  326. DWORD dwStatus = ERROR_SUCCESS;
  327. //
  328. // Allocate memory and read the data
  329. //
  330. Alloc(lpszData, PWSTR, MAX_PATH * sizeof(WCHAR));
  331. ErrExitCode(!lpszData, dwStatus, GetLastError());
  332. bResult = SetupGetStringFieldW(pInfContext, dwFieldIndex, lpszData,
  333. MAX_PATH, &cchReqdSize);
  334. if (!bResult) {
  335. dwStatus = GetLastError();
  336. //
  337. // If our buffer was too small, allocate a larger buffer
  338. // and try again
  339. //
  340. if (ERROR_INSUFFICIENT_BUFFER == dwStatus) {
  341. dwStatus = ERROR_SUCCESS;
  342. Free(lpszData);
  343. Alloc(lpszData, PWSTR, (cchReqdSize * sizeof(WCHAR)));
  344. bResult = SetupGetStringFieldW(pInfContext, dwFieldIndex,
  345. lpszData, cchReqdSize, NULL);
  346. }
  347. }
  348. if (!bResult) {
  349. Free(lpszData);
  350. }
  351. EXIT:
  352. return lpszData;
  353. }
  354. VOID
  355. AsrpInsertNodeToList(
  356. IN OUT PASR_RECOVERY_APP_LIST pList,
  357. IN OUT PASR_RECOVERY_APP_NODE pNode
  358. )
  359. /*++
  360. Routine Description:
  361. Does an insertion sort using the SequenceNumber as the key, to insert a
  362. Node to a List.
  363. Arguments:
  364. pList - The List in which to insert the node.
  365. pNode - The Node to insert.
  366. Return Value:
  367. None
  368. --*/
  369. {
  370. PASR_RECOVERY_APP_NODE pPrev = NULL,
  371. pCurr = NULL;
  372. if (pList->AppCount == 0) {
  373. //
  374. // First node being added
  375. //
  376. pNode->Next = NULL;
  377. pList->First = pNode;
  378. }
  379. else {
  380. //
  381. // Find the slot to insert this in, based on the SequenceNumber
  382. //
  383. pCurr = pList->First;
  384. pPrev = NULL;
  385. while ((pCurr) && (pCurr->SequenceNumber < pNode->SequenceNumber)) {
  386. pPrev = pCurr;
  387. pCurr = pCurr->Next;
  388. }
  389. if (pPrev) {
  390. pPrev->Next = pNode;
  391. }
  392. else {
  393. pList->First = pNode; // Head of the list
  394. }
  395. pNode->Next = pCurr;
  396. }
  397. pList->AppCount += 1;
  398. }
  399. PASR_RECOVERY_APP_NODE
  400. AsrpGetNextRecoveryApp(
  401. IN OUT PASR_RECOVERY_APP_LIST pList
  402. )
  403. /*++
  404. Routine Description:
  405. Removes and returns the first Node in a List.
  406. Arguments:
  407. pList - The List from which to remove
  408. Return Value:
  409. A pointer to the first Node in the List. Note that this Node is removed
  410. from the list.
  411. NULL if the List is empty.
  412. --*/
  413. {
  414. PASR_RECOVERY_APP_NODE pNode = NULL;
  415. if (pList->AppCount > 0) {
  416. pNode = pList->First;
  417. pList->First = pNode->Next;
  418. pList->AppCount -= 1;
  419. }
  420. return pNode;
  421. }
  422. DWORD
  423. AsrpBuildRecoveryAppList(
  424. IN CONST PCWSTR lpSifPath,
  425. OUT PASR_RECOVERY_APP_LIST pList
  426. )
  427. /*++
  428. Routine Description:
  429. Parses the COMMANDS section of asr.sif, and builds a list of recovery
  430. apps (that have SequenceNumber < 4000) to be launched. It skips apps
  431. with SequenceNumbers >= 4000 so that we don't launch the actual
  432. backup-and-restore (supposed to use sequence numbers >= 4000) listed.
  433. Arguments:
  434. lpSifPath - A null terminated UNICODE string containing the full path and
  435. file-name of the ASR state file to be used for the recovery.
  436. pList - Pointer to a struct that will receive the list recovery apps to
  437. be launched.
  438. Return Value:
  439. If the function succeeds, the return value is zero.
  440. If the function fails, the return value is a Win-32 error code.
  441. --*/
  442. {
  443. INFCONTEXT inf;
  444. HINF hSif = NULL;
  445. LONG line = 0,
  446. lLineCount = 0;
  447. BOOL bResult = FALSE;
  448. INT iSequenceNumber = 0;
  449. DWORD dwStatus = ERROR_SUCCESS;
  450. PASR_RECOVERY_APP_NODE pNode = NULL;
  451. //
  452. // Open asr.sif and build the list of commands to be launched.
  453. //
  454. hSif = SetupOpenInfFileW(lpSifPath, NULL, INF_STYLE_WIN4, NULL);
  455. ErrExitCode((!hSif || (INVALID_HANDLE_VALUE == hSif)),
  456. dwStatus, GetLastError());
  457. //
  458. // Read the COMMANDS section, and add each command to our list
  459. //
  460. lLineCount = SetupGetLineCountW(hSif, L"COMMANDS");
  461. for (line = 0; line < lLineCount; line++) {
  462. //
  463. // Get the inf context for the line in asr.sif. This will be used
  464. // to read the fields on that line
  465. //
  466. bResult = SetupGetLineByIndexW(hSif, L"COMMANDS", line, &inf);
  467. ErrExitCode(!bResult, dwStatus, ERROR_INVALID_DATA);
  468. //
  469. // Read in the int fields. First, check the SequenceNumber, and skip
  470. // this record if the SequenceNumber is >= 4000
  471. //
  472. bResult = SetupGetIntField(&inf, SequenceNumber, &iSequenceNumber);
  473. ErrExitCode(!bResult, dwStatus, ERROR_INVALID_DATA);
  474. if (iSequenceNumber >= 4000) {
  475. continue;
  476. }
  477. //
  478. // Create a new node
  479. //
  480. Alloc(pNode, PASR_RECOVERY_APP_NODE, sizeof(ASR_RECOVERY_APP_NODE));
  481. ErrExitCode(!pNode, dwStatus, GetLastError());
  482. pNode->SequenceNumber = iSequenceNumber;
  483. bResult = SetupGetIntField(&inf, SystemKey, &(pNode->SystemKey));
  484. ErrExitCode(!bResult, dwStatus, ERROR_INVALID_DATA);
  485. bResult = SetupGetIntField(&inf, CriticalApp, &(pNode->CriticalApp));
  486. ErrExitCode(!bResult, dwStatus, ERROR_INVALID_DATA);
  487. //
  488. // Read in the string fields
  489. //
  490. pNode->RecoveryAppCommand = AsrpReadField(&inf, CmdString);
  491. ErrExitCode((!pNode->RecoveryAppCommand), dwStatus, ERROR_INVALID_DATA);
  492. pNode->RecoveryAppParams = AsrpReadField(&inf, CmdParams);
  493. // null okay
  494. //
  495. // Add this node to our list, and move on to next
  496. //
  497. AsrpInsertNodeToList(pList, pNode);
  498. }
  499. EXIT:
  500. if (hSif && (INVALID_HANDLE_VALUE != hSif)) {
  501. SetupCloseInfFile(hSif);
  502. }
  503. return dwStatus;
  504. }
  505. PWSTR
  506. AsrpBuildInvocationString(
  507. IN PASR_RECOVERY_APP_NODE pNode,
  508. IN CONST PCWSTR lpSifPath
  509. )
  510. /*
  511. Routine Description:
  512. Builds the invocation string, as the name suggests. It expands out the
  513. environment variables in the recovery app path, and adds in
  514. /sifpath=<path to the sif file> at the end of the command. So for an
  515. entry in the COMMANDS section of the form:
  516. 4=1,3500,0,"%TEMP%\app.exe","/param1 /param2"
  517. the invocation string would be of the form:
  518. c:\temp\app.exe /param1 /param2 /sifpath=c:\windows\repair\asr.sif
  519. Arguments:
  520. pNode - The node from which to build the invocation string.
  521. lpSifPath - A null terminated UNICODE string containing the full path and
  522. file-name of the ASR state file to be used for the recovery.
  523. This parameter may contain unexpanded environment variables
  524. between "%" signs (such as %systemroot%\repair\asr.sif),
  525. Return Value:
  526. If the function succeeds, the return value is a pointer to the destination
  527. string containing the result of the expansion. The caller must free
  528. this memory using HeapFree for the current process heap.
  529. If the function fails, the return value is NULL. To get extended error
  530. information, call GetLastError().
  531. */
  532. {
  533. PWSTR lpszApp = pNode->RecoveryAppCommand,
  534. lpszArgs = pNode->RecoveryAppParams,
  535. lpszCmd = NULL,
  536. lpszFullcmd = NULL;
  537. DWORD dwSize = 0;
  538. //
  539. // Build an command line that looks like...
  540. //
  541. // "%TEMP%\ntbackup recover /1 /sifpath=%systemroot%\repair\asr.sif"
  542. //
  543. // The /sifpath parameter is added to all apps being launched
  544. //
  545. //
  546. // Allocate memory for the cmd line
  547. //
  548. dwSize = sizeof(WCHAR) * (
  549. wcslen(lpszApp) + // app name %TEMP%\ntbackup
  550. (lpszArgs ? wcslen(lpszArgs) : 0) + // arguments recover /1
  551. wcslen(lpSifPath) + // path to sif c:\windows\repair\asr.sif
  552. 25 // spaces, null, "/sifpath=", etc
  553. );
  554. Alloc(lpszCmd, PWSTR, dwSize); // won't return if alloc fails
  555. //
  556. // Build the string
  557. //
  558. swprintf(lpszCmd, L"%ws %ws /sifpath=%ws", lpszApp,
  559. (lpszArgs? lpszArgs: L""), lpSifPath);
  560. //
  561. // Expand the %% stuff, to build the full path
  562. //
  563. lpszFullcmd = AsrpExpandEnvStrings(lpszCmd);
  564. Free(lpszCmd);
  565. return lpszFullcmd;
  566. }
  567. VOID
  568. AsrpSetEnvironmentVariables()
  569. /*++
  570. Routine Description:
  571. Set some environment variables of interest.
  572. Arguments:
  573. None
  574. Return Value:
  575. None
  576. --*/
  577. {
  578. PWSTR TempPath = AsrpExpandEnvStrings(L"%systemdrive%\\TEMP");
  579. //
  580. // Set the TEMP and TMP variables to the same as GUI-mode recovery
  581. //
  582. SetEnvironmentVariableW(L"TEMP", TempPath);
  583. SetEnvironmentVariableW(L"TMP", TempPath);
  584. Free(TempPath);
  585. //
  586. // Clear this variable (it shouldn't exist anyway), since this is
  587. // meant to be set only if this is a full GUI-mode ASR
  588. //
  589. SetEnvironmentVariableW(L"ASR_C_CONTEXT", NULL);
  590. }
  591. DWORD
  592. AsrpRestoreSif(
  593. IN CONST PCWSTR lpSifPath
  594. )
  595. /*++
  596. Routine Description:
  597. Restores the disk layout specified in the ASR state file (asr.sif), using
  598. the ASR API in syssetup.dll. Then launches the recovery apps specified
  599. in the COMMANDS section of asr.sif, with sequence numbers less than 4000.
  600. Arguments:
  601. lpSifPath - A null terminated UNICODE string containing the full path and
  602. file-name of the ASR state file to be used for the recovery.
  603. This parameter may contain unexpanded environment variables
  604. between "%" signs (such as %systemroot%\repair\asr.sif),
  605. Return Value:
  606. If the function succeeds, the return value is zero.
  607. If the function fails, the return value is a Win-32 error code.
  608. --*/
  609. {
  610. BOOL bResult = TRUE;
  611. HMODULE hDll = NULL;
  612. STARTUPINFOW startUpInfo;
  613. PWSTR lpFullSifPath = NULL,
  614. lpszAppCmdLine = NULL;
  615. ASR_RECOVERY_APP_LIST AppList;
  616. DWORD dwStatus = ERROR_SUCCESS;
  617. PROCESS_INFORMATION processInfo;
  618. PASR_RECOVERY_APP_NODE pNode = NULL;
  619. BOOL (*pfnRestoreDisks)(PCWSTR, BOOL);
  620. pfnRestoreDisks = NULL;
  621. ZeroMemory(&AppList, sizeof(ASR_RECOVERY_APP_LIST));
  622. ZeroMemory(&startUpInfo, sizeof(STARTUPINFOW));
  623. ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
  624. lpFullSifPath = AsrpExpandEnvStrings(lpSifPath);
  625. ErrExitCode(!lpFullSifPath, dwStatus, GetLastError());
  626. //
  627. // To restore the disks, load syssetup and get the routine of interest
  628. //
  629. hDll = LoadLibraryW(L"syssetup.dll");
  630. ErrExitCode(!hDll, dwStatus, GetLastError());
  631. pfnRestoreDisks = (BOOL (*)(PCWSTR, BOOL))
  632. GetProcAddress(hDll, "AsrpRestoreNonCriticalDisksW");
  633. ErrExitCode(!pfnRestoreDisks, dwStatus, GetLastError());
  634. AsrpSetEnvironmentVariables();
  635. //
  636. // Recreate the disks. We don't need the AllOrNothing granularity--it's
  637. // okay if some disks come back but others don't,
  638. //
  639. bResult = pfnRestoreDisks(lpFullSifPath, FALSE);
  640. ErrExitCode(!bResult, dwStatus, GetLastError());
  641. //
  642. // Now, we need to launch the recovery apps in the COMMANDS section.
  643. // Note that we'll only launch apps with a sequence number below 4000,
  644. // so that we don't launch the actual backup-and-restore app listed.
  645. // Backup-and-restore apps are supposed to use sequence numbers >= 4000.
  646. //
  647. //
  648. // Parse the sif to obtain list of apps to run
  649. //
  650. dwStatus = AsrpBuildRecoveryAppList(lpFullSifPath, &AppList);
  651. ErrExitCode((ERROR_SUCCESS != dwStatus), dwStatus, dwStatus);
  652. //
  653. // And launch them synchronously.
  654. //
  655. pNode = AsrpGetNextRecoveryApp(&AppList);
  656. while (pNode) {
  657. lpszAppCmdLine = AsrpBuildInvocationString(pNode, lpFullSifPath);
  658. //
  659. // We don't need pNode any more
  660. //
  661. Free(pNode->RecoveryAppParams);
  662. Free(pNode->RecoveryAppCommand);
  663. Free(pNode);
  664. if (!lpszAppCmdLine) {
  665. //
  666. // Silently fail !TODO: May need error message
  667. //
  668. continue;
  669. }
  670. // !TODO: May need status message
  671. wprintf(L"[%ws]\n", lpszAppCmdLine);
  672. bResult = CreateProcessW(
  673. NULL, // lpApplicationName
  674. lpszAppCmdLine, // lpCommandLine
  675. NULL, // lpProcessAttributes
  676. NULL, // lpThreadAttributes
  677. FALSE, // bInheritHandles
  678. 0, // dwCreationFlags
  679. NULL, // pEnvironment
  680. NULL, // lpCurrentDirectory (null=current dir)
  681. &startUpInfo, // statup information
  682. &processInfo // process information
  683. );
  684. if (bResult) {
  685. WaitForSingleObject(processInfo.hProcess, INFINITE);
  686. }
  687. // else silently fail !TODO: May need error message
  688. Free(lpszAppCmdLine);
  689. pNode = AsrpGetNextRecoveryApp(&AppList);
  690. }
  691. EXIT:
  692. if (hDll && (INVALID_HANDLE_VALUE != hDll)) {
  693. FreeLibrary(hDll);
  694. hDll = NULL;
  695. }
  696. return dwStatus;
  697. }
  698. int __cdecl
  699. wmain(
  700. int argc,
  701. WCHAR *argv[],
  702. WCHAR *envp[]
  703. )
  704. /*++
  705. Routine Description:
  706. Entry point to the application.
  707. Arguments:
  708. argc - Number of command-line parameters used to invoke the app
  709. argv - The command-line parameters as an array of strings. See the top
  710. of this module for the list of valid parameters.
  711. envp - The process environment block, not currently used
  712. Return Values:
  713. If the function succeeds, the exit code is zero.
  714. If the function fails, the exit code is a win-32 error code.
  715. --*/
  716. {
  717. DWORD dwStatus = ERROR_SUCCESS;
  718. //
  719. // Initialise globals
  720. //
  721. g_hModule = GetModuleHandle(NULL);
  722. g_hHeap = GetProcessHeap();
  723. g_fErrorMessageDone = FALSE;
  724. //
  725. // Check and switch on the basis of the command line arguments
  726. //
  727. if ((argc >= 2) && (
  728. !_wcsicmp(argv[1], L"/save") ||
  729. !_wcsicmp(argv[1], L"-save") ||
  730. !_wcsicmp(argv[1], L"save")
  731. )) {
  732. //
  733. // confdisk /save [c:\windows\asr.sif]
  734. //
  735. dwStatus = AsrpCreateSif(argv[2]);
  736. }
  737. else if ((argc >= 3) && (
  738. !_wcsicmp(argv[1], L"/restore") ||
  739. !_wcsicmp(argv[1], L"-restore") ||
  740. !_wcsicmp(argv[1], L"restore")
  741. )) {
  742. //
  743. // confdisk /restore c:\windows\repair\asr.sif
  744. //
  745. dwStatus = AsrpRestoreSif(argv[2]);
  746. }
  747. else {
  748. //
  749. // Unknown parameter
  750. //
  751. dwStatus = AsrpPrintUsage();
  752. }
  753. //
  754. // We're all done. Return the error-code, for interested parties.
  755. //
  756. return (int) dwStatus;
  757. UNREFERENCED_PARAMETER(envp);
  758. }