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.

592 lines
16 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. asr_app.c
  5. Abstract:
  6. Sample third party ASR recovery application.
  7. Authors:
  8. Guhan Suriyanarayanan (guhans) 07-Oct-1999
  9. Revision History:
  10. 07-Oct-2000 guhans
  11. Initial creation
  12. --*/
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <windows.h>
  16. #include <winasr.h>
  17. #include <setupapi.h>
  18. //
  19. // Macro Description:
  20. // If ErrorCondition occurs, it sets the LocalStatus to the ErrorCode
  21. // passed in, calls SetLastError() to set the Last Error to ErrorCode,
  22. // and jumps to the EXIT label in the calling function
  23. //
  24. // Arguments:
  25. // ErrorCondition // Expression to be tested
  26. // LocalStatus // Status variable in the calling function
  27. // LONG ErrorCode // ErrorCode
  28. //
  29. #define pErrExitCode( ErrorCondition, LocalStatus, ErrorCode ) { \
  30. \
  31. if ((BOOL) ErrorCondition) { \
  32. \
  33. wprintf(L"Error %lu (0x%x), line %lu", ErrorCode, ErrorCode, __LINE__); \
  34. \
  35. LocalStatus = (DWORD) ErrorCode; \
  36. \
  37. SetLastError((DWORD) ErrorCode); \
  38. \
  39. goto EXIT; \
  40. } \
  41. }
  42. //
  43. // Constants local to this module
  44. //
  45. const WCHAR BACKUP_OPTION[] = L"/backup";
  46. const WCHAR RESTORE_OPTION[] = L"/restore";
  47. const WCHAR REGISTER_OPTION[] = L"/register";
  48. const WCHAR SIF_PATH_FORMAT[] = L"/sifpath=%ws";
  49. const WCHAR ERROR_FILE_PATH[] = L"%systemroot%\\repair\\asr.err";
  50. const WCHAR MY_SIF_SECTION[] = L"[ASR_APP.APPDATA]";
  51. const WCHAR MY_SIF_SECTION_NAME[] = L"ASR_APP.APPDATA";
  52. const WCHAR GENERIC_ERROR_MESSAGE[] = L"asr_app could not complete successfully (error %lu 0x%x)\n\nusage: asr_app {/backup | /restore /sifpath=<path to asr.sif> | /register <path to asr_app>}";
  53. const WCHAR GENERIC_ERROR_TITLE[] = L"asr_app error";
  54. #ifdef _IA64_
  55. const WCHAR CONTEXT_FORMAT[] = L"/context=%I64u";
  56. #else
  57. const WCHAR CONTEXT_FORMAT[] = L"/context=%lu";
  58. #endif
  59. #define ASR_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Asr\\Commands"
  60. #define MY_REG_KEY_VALUE_NAME L"ASR Sample Application"
  61. typedef enum _AsrAppOption {
  62. AsrAppNone = 0,
  63. AsrAppRegister,
  64. AsrAppBackup,
  65. AsrAppRestore
  66. } AsrAppOption;
  67. HANDLE Gbl_hErrorFile = NULL;
  68. PWSTR // must be freed by caller
  69. ExpandEnvStrings(
  70. IN CONST PCWSTR OriginalString
  71. )
  72. {
  73. PWSTR expandedString = NULL;
  74. UINT cchSize = MAX_PATH + 1, // start with a reasonable default
  75. cchRequiredSize = 0;
  76. BOOL result = FALSE;
  77. DWORD status = ERROR_SUCCESS;
  78. HANDLE heapHandle = GetProcessHeap();
  79. expandedString = (PWSTR) HeapAlloc(heapHandle, HEAP_ZERO_MEMORY, (cchSize * sizeof(WCHAR)));
  80. if (!expandedString) {
  81. return NULL;
  82. }
  83. cchRequiredSize = ExpandEnvironmentStringsW(OriginalString,
  84. expandedString,
  85. cchSize
  86. );
  87. if (cchRequiredSize > cchSize) {
  88. //
  89. // Buffer wasn't big enough; free and re-allocate as needed
  90. //
  91. HeapFree(heapHandle, 0L, expandedString);
  92. cchSize = cchRequiredSize + 1;
  93. expandedString = (PWSTR) HeapAlloc(heapHandle, HEAP_ZERO_MEMORY, (cchSize * sizeof(WCHAR)));
  94. if (!expandedString) {
  95. return NULL;
  96. }
  97. cchRequiredSize = ExpandEnvironmentStringsW(OriginalString,
  98. expandedString,
  99. cchSize
  100. );
  101. }
  102. if ((0 == cchRequiredSize) || (cchRequiredSize > cchSize)) {
  103. //
  104. // Either the function failed, or the buffer wasn't big enough
  105. // even on the second try
  106. //
  107. HeapFree(heapHandle, 0L, expandedString);
  108. expandedString = NULL;
  109. }
  110. return expandedString;
  111. }
  112. VOID
  113. OpenErrorFile()
  114. {
  115. PWSTR szErrorFilePath = NULL;
  116. //
  117. // Get full path to the error file (%systemroot%\repair\asr.err)
  118. //
  119. szErrorFilePath = ExpandEnvStrings(ERROR_FILE_PATH);
  120. if (!szErrorFilePath) {
  121. return;
  122. }
  123. //
  124. // Open the error file
  125. //
  126. Gbl_hErrorFile = CreateFileW(
  127. szErrorFilePath, // lpFileName
  128. GENERIC_WRITE | GENERIC_READ, // dwDesiredAccess
  129. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  130. NULL, // lpSecurityAttributes
  131. OPEN_ALWAYS, // dwCreationFlags
  132. FILE_FLAG_WRITE_THROUGH, // dwFlagsAndAttributes
  133. NULL // hTemplateFile
  134. );
  135. HeapFree(GetProcessHeap(), 0L, szErrorFilePath);
  136. szErrorFilePath = NULL;
  137. if ((!Gbl_hErrorFile) || (INVALID_HANDLE_VALUE == Gbl_hErrorFile)) {
  138. return;
  139. }
  140. //
  141. // Move to the end of file
  142. //
  143. SetFilePointer(Gbl_hErrorFile, 0L, NULL, FILE_END);
  144. }
  145. VOID
  146. CloseErrorFile(
  147. VOID
  148. )
  149. {
  150. if ((Gbl_hErrorFile) && (INVALID_HANDLE_VALUE != Gbl_hErrorFile)) {
  151. CloseHandle(Gbl_hErrorFile);
  152. Gbl_hErrorFile = NULL;
  153. }
  154. }
  155. VOID
  156. LogErrorMessage(
  157. IN CONST PCWSTR Message
  158. )
  159. {
  160. SYSTEMTIME currentTime;
  161. DWORD bytesWritten = 0;
  162. WCHAR buffer[4196];
  163. if ((!Gbl_hErrorFile) || (INVALID_HANDLE_VALUE == Gbl_hErrorFile)) {
  164. //
  165. // We haven't been initialised, or the error file couldn't be
  166. // created for some reason.
  167. //
  168. return;
  169. }
  170. //
  171. // In case someone else wrote to this file since our last write
  172. //
  173. SetFilePointer(Gbl_hErrorFile, 0L, NULL, FILE_END);
  174. //
  175. // Create our string, and write it out
  176. //
  177. GetLocalTime(&currentTime);
  178. swprintf(buffer,
  179. L"\r\n[%04hu/%02hu/%02hu %02hu:%02hu:%02hu ASR_APP] (ERROR) %s\r\n",
  180. currentTime.wYear,
  181. currentTime.wMonth,
  182. currentTime.wDay,
  183. currentTime.wHour,
  184. currentTime.wMinute,
  185. currentTime.wSecond,
  186. Message
  187. );
  188. WriteFile(Gbl_hErrorFile,
  189. buffer,
  190. (wcslen(buffer) * sizeof(WCHAR)),
  191. &bytesWritten,
  192. NULL
  193. );
  194. }
  195. BOOL
  196. BackupState(
  197. IN CONST DWORD_PTR AsrContext
  198. )
  199. {
  200. //
  201. // Gather our state to backup
  202. //
  203. HMODULE hSyssetup = NULL;
  204. DWORD dwStatus = ERROR_SUCCESS;
  205. BOOL bResult = FALSE;
  206. //
  207. // BOOL
  208. // AsrAddSifEntryW(
  209. // IN DWORD_PTR AsrContext,
  210. // IN PCWSTR lpSectionName,
  211. // IN PCWSTR lpSifEntry
  212. // );
  213. //
  214. BOOL (*pfnAddSifEntry)(DWORD_PTR, PCWSTR, PCWSTR);
  215. //
  216. // Load syssetup.dll
  217. //
  218. hSyssetup = LoadLibraryW(L"syssetup.dll");
  219. pErrExitCode(
  220. (!hSyssetup || INVALID_HANDLE_VALUE == hSyssetup),
  221. dwStatus,
  222. GetLastError()
  223. );
  224. //
  225. // Get the RestoreNonCriticalDisksW API exported by syssetup.dll
  226. //
  227. pfnAddSifEntry = (BOOL (*)(DWORD_PTR, PCWSTR, PCWSTR))
  228. GetProcAddress(hSyssetup, "AsrAddSifEntryW");
  229. pErrExitCode((!pfnAddSifEntry), dwStatus, GetLastError());
  230. //
  231. // Add the state to asr.sif
  232. //
  233. bResult = pfnAddSifEntry(
  234. AsrContext,
  235. MY_SIF_SECTION,
  236. L"1=\"asr_app sample application data\",100,200,300"
  237. );
  238. pErrExitCode(!bResult, dwStatus, GetLastError());
  239. //
  240. // Also add to the commands and installfiles section, so that we get
  241. // called during the ASR recovery.
  242. //
  243. //
  244. // INSTALLFILES section entry format:
  245. // system-key,source-media-label,source-device,
  246. // source-file-path,destination-file-path,vendor-name
  247. // system-key must be 1
  248. //
  249. bResult = pfnAddSifEntry(
  250. AsrContext,
  251. ASR_SIF_SECTION_INSTALLFILES,
  252. L"1,\"ASR Sample App Disk 1\",\"%FLOPPY%\",\"i386\\asr_app.exe\",\"%temp%\\asr_app.exe\",\"ASR Sample App Company\""
  253. //L"1,\"Application Disk 1\",\"\\device\\cdrom0\",\"application.exe\",\"%TEMP%\\application.exe\",\"Company Name\""
  254. );
  255. pErrExitCode(!bResult, dwStatus, GetLastError());
  256. // CString cmd =L"1,\"ASRDisk1\",\"\\Device\\Floppy0\\edmbackup.exe\",\"%TEMP%\\edmbackup.exe\",\"EMC\"";
  257. /* bResult = pfnAddSifEntry(AsrContext,
  258. ASR_SIF_SECTION_INSTALLFILES,
  259. (LPCTSTR) L"1,\"ASRDisk1\",\"\\Device\\Floppy0\\edmbackup.exe\",\"%TEMP%\\edmbackup.exe\",\"EMC\"" );
  260. pErrExitCode(!bResult, dwStatus, GetLastError());
  261. */
  262. //
  263. // COMMANDS section entry format:
  264. // system-key,sequence-number,action-on-completion,"command","parameters"
  265. // system-key must be 1
  266. // 1000 <= sequence-number <= 4999
  267. // 0 <= action-on-completion <= 1
  268. //
  269. bResult = pfnAddSifEntry(
  270. AsrContext,
  271. ASR_SIF_SECTION_COMMANDS,
  272. L"1,3500,1,\"%temp%\\asr_app.exe\",\"/restore\""
  273. );
  274. pErrExitCode(!bResult, dwStatus, GetLastError());
  275. EXIT:
  276. //
  277. // Cleanup
  278. //
  279. if (hSyssetup) {
  280. FreeLibrary(hSyssetup);
  281. hSyssetup = NULL;
  282. }
  283. return (ERROR_SUCCESS == dwStatus);
  284. }
  285. BOOL
  286. RestoreState(
  287. IN CONST PCWSTR szAsrSifPath
  288. )
  289. {
  290. HINF hSif = NULL;
  291. INFCONTEXT infContext;
  292. BOOL bResult = FALSE;
  293. WCHAR szErrorString[1024];
  294. int iValue1 = 0,
  295. iValue2 = 0,
  296. iValue3 = 0;
  297. WCHAR szBuffer[1024];
  298. //
  299. // Open the asr.sif
  300. //
  301. hSif = SetupOpenInfFile(szAsrSifPath, NULL, INF_STYLE_WIN4, NULL);
  302. if ((!hSif) || (INVALID_HANDLE_VALUE == hSif)) {
  303. wsprintf(szErrorString, L"Unable to open the ASR state file at %ws (0x%x)",
  304. szAsrSifPath,
  305. GetLastError()
  306. );
  307. LogErrorMessage(szErrorString);
  308. return FALSE;
  309. }
  310. //
  311. // Find the section
  312. //
  313. bResult = SetupFindFirstLineW(hSif, MY_SIF_SECTION_NAME, NULL, &infContext);
  314. if (bResult) {
  315. //
  316. // Read in the information. We had one string followed by three numbers.
  317. //
  318. bResult = SetupGetStringField(&infContext, 1, szBuffer, 1024, NULL)
  319. && SetupGetIntField(&infContext, 2, &iValue1)
  320. && SetupGetIntField(&infContext, 3, &iValue2)
  321. && SetupGetIntField(&infContext, 4, &iValue3);
  322. if (bResult) {
  323. //
  324. // Now restore our state. Let's just pretend we're doing something.
  325. //
  326. wprintf(L"Values read: %ws %lu %lu %lu\n\n", szBuffer, iValue1, iValue2, iValue3);
  327. wprintf(L"Restoring sample system state, please wait ... ");
  328. Sleep(5000);
  329. wprintf(L"done\n");
  330. }
  331. else {
  332. wsprintf(szErrorString,
  333. L"Some values in the asr_app section of the ASR state file %ws could not be read (0x%x). "
  334. L"This may indicate a corrupt or an incompatible version of the ASR state file",
  335. szAsrSifPath,
  336. GetLastError()
  337. );
  338. LogErrorMessage(szErrorString);
  339. }
  340. }
  341. else {
  342. wsprintf(szErrorString,
  343. L"Unable to locate asr_app section in ASR state file %ws (0x%x). "
  344. L"This may indicate a corrupt or an incompatible version of the ASR state file",
  345. szAsrSifPath,
  346. GetLastError()
  347. );
  348. LogErrorMessage(szErrorString);
  349. }
  350. SetupCloseInfFile(hSif);
  351. return bResult;
  352. }
  353. DWORD
  354. RegisterForAsrBackup(
  355. IN CONST PCWSTR szApplicationName
  356. )
  357. {
  358. DWORD dwResult = ERROR_SUCCESS;
  359. HKEY hKeyAsr = NULL;
  360. WCHAR szData[1024];
  361. if (wcslen(szApplicationName) > 1000) {
  362. return ERROR_INSUFFICIENT_BUFFER;
  363. }
  364. wsprintf(szData, L"%ws %ws", szApplicationName, BACKUP_OPTION);
  365. //
  366. // Open the registry key
  367. //
  368. dwResult = RegOpenKeyExW(
  369. HKEY_LOCAL_MACHINE, // hKey
  370. ASR_REG_KEY, // lpSubKey
  371. 0, // ulOptions--Reserved, must be 0
  372. MAXIMUM_ALLOWED, // samDesired
  373. &hKeyAsr // phkbResult
  374. );
  375. if (ERROR_SUCCESS != dwResult) {
  376. return dwResult;
  377. }
  378. dwResult = RegSetValueExW(
  379. hKeyAsr, // hKey
  380. MY_REG_KEY_VALUE_NAME, // lpValueName
  381. 0, // dwReserved, must be 0
  382. REG_SZ, // dwType
  383. (LPBYTE)szData, // lpData
  384. ((wcslen(szData) + 1)* (sizeof(WCHAR))) // cbData
  385. );
  386. return dwResult;
  387. }
  388. int
  389. __cdecl // var arg
  390. wmain (
  391. int argc,
  392. wchar_t *argv[],
  393. wchar_t *envp[]
  394. )
  395. {
  396. AsrAppOption option = AsrAppNone;
  397. DWORD dwStatus = ERROR_SUCCESS;
  398. if (argc >= 3) {
  399. if (!_wcsicmp(argv[1], BACKUP_OPTION)) {
  400. //
  401. // asr_app /backup /context=nnn
  402. //
  403. option = AsrAppBackup;
  404. }
  405. else if (!_wcsicmp(argv[1], RESTORE_OPTION)) {
  406. //
  407. // asr_app /restore /sifpath="c:\winnt\repair\asr.sif"
  408. //
  409. option = AsrAppRestore;
  410. }
  411. else if (!_wcsicmp(argv[1], REGISTER_OPTION)) {
  412. //
  413. // asr_app /register "c:\apps\asr_app\asr_app.exe"
  414. //
  415. option = AsrAppRegister;
  416. }
  417. }
  418. switch (option) {
  419. case AsrAppRegister: { // This App is being installed
  420. dwStatus = RegisterForAsrBackup(argv[2]);
  421. break;
  422. }
  423. case AsrAppBackup: { // An ASR Backup is in progress
  424. DWORD_PTR AsrContext = 0;
  425. //
  426. // Extract the asr context from the commandline
  427. //
  428. swscanf(argv[2], CONTEXT_FORMAT, &AsrContext);
  429. //
  430. // Create our spooge and write to the asr.sif
  431. //
  432. if (!BackupState(AsrContext)) {
  433. dwStatus = GetLastError();
  434. }
  435. // AsrFreeContext(&AsrContext);
  436. //
  437. // And we're done
  438. //
  439. break;
  440. }
  441. case AsrAppRestore: { // An ASR Restore is in progress
  442. WCHAR szAsrFilePath[MAX_PATH +1];
  443. //
  444. // Get the path to the asr.sif
  445. //
  446. swscanf(argv[2], SIF_PATH_FORMAT, szAsrFilePath);
  447. OpenErrorFile();
  448. //
  449. // Read our spooge from asr.sif, and recreate the state. Be sure to
  450. // write out the error to %systemroot%\repair\asr.err in case of
  451. // error.
  452. //
  453. if (!RestoreState(szAsrFilePath)) {
  454. dwStatus = GetLastError();
  455. }
  456. CloseErrorFile();
  457. //
  458. // And we're done
  459. //
  460. break;
  461. }
  462. case AsrAppNone:
  463. default: {
  464. //
  465. // Command-line parameters were incorrect, display usage message
  466. //
  467. dwStatus = ERROR_INVALID_PARAMETER;
  468. break;
  469. }
  470. }
  471. if (ERROR_SUCCESS != dwStatus) {
  472. //
  473. // We hit an error
  474. //
  475. WCHAR szErrorMessage[1024];
  476. swprintf(szErrorMessage, GENERIC_ERROR_MESSAGE, dwStatus, dwStatus);
  477. MessageBoxW(NULL, szErrorMessage, GENERIC_ERROR_TITLE, MB_OK | MB_ICONSTOP);
  478. }
  479. SetLastError(dwStatus);
  480. return (int) dwStatus;
  481. }