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.

6111 lines
180 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. asrbkup.c
  5. Abstract:
  6. This module contains the following ASR routines:
  7. AsrCreateStateFile{A|W}
  8. AsrAddSifEntry{A|W}
  9. AsrFreeContext
  10. Author:
  11. Guhan Suriyanarayanan (guhans) 27-May-2000
  12. Environment:
  13. User-mode only.
  14. Notes:
  15. Naming conventions:
  16. _AsrpXXX private ASR Macros
  17. AsrpXXX private ASR routines
  18. AsrXXX Publically defined and documented routines
  19. Revision History:
  20. 27-May-2000 guhans
  21. Moved ASR-backup related routines from asr.c to
  22. asrbkup.c
  23. 01-Jan-2000 guhans
  24. Initial implementation for Asr routines in asr.c
  25. --*/
  26. #include "setupp.h"
  27. #pragma hdrstop
  28. #include <initguid.h> // DiskClassGuid
  29. #include <diskguid.h> // GPT partition type guids
  30. #include <ntddvol.h> // ioctl_volume_query_failover_set
  31. #include <setupapi.h> // SetupDi routines
  32. #include <mountmgr.h> // mountmgr ioctls
  33. #include <rpcdce.h> // UuidToStringW, RpcStringFreeW
  34. #include <winasr.h> // ASR public routines
  35. #define THIS_MODULE 'B'
  36. #include <accctrl.h> // EXPLICIT_ACCESS, ACL related stuff
  37. #include <aclapi.h> // SetEntriesInAcl
  38. #include "asrpriv.h" // Private ASR definitions and routines
  39. //
  40. // --------
  41. // constants local to this module. These are not accessed outside this file.
  42. // --------
  43. //
  44. //
  45. // The Setup Key to find the system partition from
  46. //
  47. const WCHAR ASR_REGKEY_SETUP[] = L"SYSTEM\\SETUP";
  48. const WCHAR ASR_REGVALUE_SYSTEM_PARTITION[] = L"SystemPartition";
  49. //
  50. // The ASR registry entries. Currently, this is used to look
  51. // up the commands to run during an Asr backup, but we could
  52. // have other settings here later.
  53. //
  54. const WCHAR ASR_REGKEY_ASR_COMMANDS[]
  55. = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Asr\\Commands";
  56. const WCHAR ASR_REGKEY_ASR[]
  57. = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Asr\\";
  58. const WCHAR ASR_REGVALUE_TIMEOUT[] = L"ProcessTimeOut";
  59. //
  60. // File to save the PnP information in.
  61. //
  62. const WCHAR ASR_DEFAULT_SIF_PATH[] = L"\\\\?\\%systemroot%\\repair\\asr.sif";
  63. const WCHAR ASRPNP_DEFAULT_SIF_NAME[] = L"asrpnp.sif";
  64. //
  65. // We only support x86, AMD64, and IA64 architectures.
  66. //
  67. const WCHAR ASR_PLATFORM_X86[] = L"x86";
  68. const WCHAR ASR_PLATFORM_AMD64[] = L"AMD64";
  69. const WCHAR ASR_PLATFORM_IA64[] = L"IA64";
  70. //
  71. // This is the suffix that we add when launching the apps registered for ASR.
  72. // Remember to change the length if you're changing this. The length should
  73. // include space for 20 digits (max 64-bit int) + null + space at the beginning.
  74. //
  75. #define ASR_COMMANDLINE_SUFFIX_LEN 35
  76. const WCHAR ASR_COMMANDLINE_SUFFIX[] = L" /context=%I64u";
  77. //
  78. // Miscellaneous constants
  79. //
  80. const WCHAR ASR_DOS_DEVICES_PREFIX[] = L"\\DosDevices\\";
  81. const WCHAR ASR_DEVICE_PATH_PREFIX[] = L"\\Device\\Harddisk";
  82. const WCHAR ASR_PARTITION_1[] = L"\\\\\?\\GLOBALROOT\\Device\\Harddisk%u\\Partition1";
  83. const WCHAR ASR_WSZ_VOLUME_PREFIX[] = L"\\??\\Volume";
  84. const WCHAR ASR_WSZ_DEVICE_PATH_FORMAT[] = L"\\Device\\Harddisk%d\\Partition%d";
  85. //
  86. // Sections in asr.sif
  87. //
  88. const WCHAR ASR_SIF_VERSION_SECTION_NAME[] = L"[VERSION]";
  89. const WCHAR ASR_SIF_SYSTEM_SECTION_NAME[] = L"[SYSTEMS]";
  90. const WCHAR ASR_SIF_BUSES_SECTION_NAME[] = L"[BUSES]";
  91. const WCHAR ASR_SIF_MBR_DISKS_SECTION_NAME[] = L"[DISKS.MBR]";
  92. const WCHAR ASR_SIF_GPT_DISKS_SECTION_NAME[] = L"[DISKS.GPT]";
  93. const WCHAR ASR_SIF_MBR_PARTITIONS_SECTION_NAME[] = L"[PARTITIONS.MBR]";
  94. const WCHAR ASR_SIF_GPT_PARTITIONS_SECTION_NAME[] = L"[PARTITIONS.GPT]";
  95. const WCHAR ASR_SIF_PROVIDER_PREFIX[] = L"Provider=";
  96. // wcslen("Provider=""\r\n\0")
  97. #define ASR_SIF_CCH_PROVIDER_STRING 14
  98. //
  99. // While launching registered applications during an ASR backup, we
  100. // add two environment variables to the environment block for the
  101. // process being launched: the AsrContext and the critical volume
  102. // list.
  103. //
  104. #define ASR_CCH_ENVBLOCK_ASR_ENTRIES (32 + 1 + 28 + 2)
  105. const WCHAR ASR_ENVBLOCK_CONTEXT_ENTRY[] = L"_AsrContext=%I64u";
  106. const WCHAR ASR_ENVBLOCK_CRITICAL_VOLUME_ENTRY[]
  107. = L"_AsrCriticalVolumeList=";
  108. //
  109. // Pre-defined flags designating the boot and system partitions
  110. // in the partitions section of asr.sif. Remember to change the
  111. // counter-parts in setupdd.sys if you change these!
  112. //
  113. const BYTE ASR_FLAGS_BOOT_PTN = 1;
  114. const BYTE ASR_FLAGS_SYSTEM_PTN = 2;
  115. //
  116. // For now, we only allow one system per sif file. If a sif
  117. // already exists at the location AsrCreateStateFile is called,
  118. // the existing sif is deleted. The asr.sif architecture does
  119. // allow for multiple systems per sif file, but
  120. // - I don't see any compelling reason to support this, and
  121. // - It would be a test nightmare
  122. //
  123. const BYTE ASR_SYSTEM_KEY = 1;
  124. //
  125. // _AsrpCheckTrue: primarily used with WriteFile calls.
  126. //
  127. #define _AsrpCheckTrue( Expression ) \
  128. if (!Expression) { \
  129. return FALSE; \
  130. }
  131. //
  132. // --------
  133. // constants used across asr modules.
  134. // --------
  135. //
  136. const WCHAR ASR_SIF_SYSTEM_SECTION[] = L"SYSTEMS";
  137. const WCHAR ASR_SIF_BUSES_SECTION[] = L"BUSES";
  138. const WCHAR ASR_SIF_MBR_DISKS_SECTION[] = L"DISKS.MBR";
  139. const WCHAR ASR_SIF_GPT_DISKS_SECTION[] = L"DISKS.GPT";
  140. const WCHAR ASR_SIF_MBR_PARTITIONS_SECTION[] = L"PARTITIONS.MBR";
  141. const WCHAR ASR_SIF_GPT_PARTITIONS_SECTION[] = L"PARTITIONS.GPT";
  142. //
  143. // --------
  144. // function prototypes
  145. // --------
  146. //
  147. //
  148. // Function prototype for AsrCreatePnpStateFileW.
  149. // (linked into syssetup.dll from pnpsif.lib)
  150. //
  151. BOOL
  152. AsrCreatePnpStateFileW(
  153. IN PCWSTR lpFilePath
  154. );
  155. //
  156. // --------
  157. // private functions
  158. // --------
  159. //
  160. BOOL
  161. AsrpConstructSecurityAttributes(
  162. PSECURITY_ATTRIBUTES psaSecurityAttributes,
  163. SecurityAttributeType eSaType,
  164. BOOL bIncludeBackupOperator
  165. )
  166. {
  167. DWORD dwStatus;
  168. DWORD dwAccessMask = 0;
  169. BOOL bResult = TRUE;
  170. PSID psidBackupOperators = NULL;
  171. PSID psidAdministrators = NULL;
  172. PSID psidLocalSystem = NULL;
  173. PACL paclDiscretionaryAcl = NULL;
  174. SID_IDENTIFIER_AUTHORITY sidNtAuthority = SECURITY_NT_AUTHORITY;
  175. EXPLICIT_ACCESS eaExplicitAccess [3];
  176. switch (eSaType) {
  177. case esatMutex:
  178. dwAccessMask = MUTEX_ALL_ACCESS;
  179. break;
  180. case esatSemaphore:
  181. dwAccessMask = SEMAPHORE_ALL_ACCESS;
  182. break;
  183. case esatEvent:
  184. dwAccessMask = EVENT_ALL_ACCESS;
  185. break;
  186. case esatFile:
  187. dwAccessMask = FILE_ALL_ACCESS;
  188. break;
  189. default:
  190. bResult = FALSE;
  191. break;
  192. }
  193. /*
  194. ** Initialise the security descriptor.
  195. */
  196. if (bResult) {
  197. bResult = InitializeSecurityDescriptor(psaSecurityAttributes->lpSecurityDescriptor,
  198. SECURITY_DESCRIPTOR_REVISION
  199. );
  200. }
  201. if (bResult && bIncludeBackupOperator) {
  202. /*
  203. ** Create a SID for the Backup Operators group.
  204. */
  205. bResult = AllocateAndInitializeSid(&sidNtAuthority,
  206. 2,
  207. SECURITY_BUILTIN_DOMAIN_RID,
  208. DOMAIN_ALIAS_RID_BACKUP_OPS,
  209. 0, 0, 0, 0, 0, 0,
  210. &psidBackupOperators
  211. );
  212. }
  213. if (bResult) {
  214. /*
  215. ** Create a SID for the Administrators group.
  216. */
  217. bResult = AllocateAndInitializeSid(&sidNtAuthority,
  218. 2,
  219. SECURITY_BUILTIN_DOMAIN_RID,
  220. DOMAIN_ALIAS_RID_ADMINS,
  221. 0, 0, 0, 0, 0, 0,
  222. &psidAdministrators
  223. );
  224. }
  225. if (bResult) {
  226. /*
  227. ** Create a SID for the Local System.
  228. */
  229. bResult = AllocateAndInitializeSid(&sidNtAuthority,
  230. 1,
  231. SECURITY_LOCAL_SYSTEM_RID,
  232. 0, 0, 0, 0, 0, 0, 0,
  233. &psidLocalSystem
  234. );
  235. }
  236. if (bResult) {
  237. /*
  238. ** Initialize the array of EXPLICIT_ACCESS structures for an
  239. ** ACEs we are setting.
  240. **
  241. ** The first ACE allows the Backup Operators group full access
  242. ** and the second, allowa the Administrators group full
  243. ** access.
  244. */
  245. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  246. // The ACE allows the Administrators group full access to the directory
  247. eaExplicitAccess[0].grfAccessPermissions = FILE_ALL_ACCESS;
  248. eaExplicitAccess[0].grfAccessMode = SET_ACCESS;
  249. eaExplicitAccess[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  250. eaExplicitAccess[0].Trustee.pMultipleTrustee = NULL;
  251. eaExplicitAccess[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  252. eaExplicitAccess[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  253. eaExplicitAccess[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
  254. eaExplicitAccess[0].Trustee.ptstrName = (LPTSTR) psidLocalSystem;
  255. eaExplicitAccess[1].grfAccessPermissions = dwAccessMask;
  256. eaExplicitAccess[1].grfAccessMode = SET_ACCESS;
  257. eaExplicitAccess[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  258. eaExplicitAccess[1].Trustee.pMultipleTrustee = NULL;
  259. eaExplicitAccess[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  260. eaExplicitAccess[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  261. eaExplicitAccess[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  262. eaExplicitAccess[1].Trustee.ptstrName = (LPTSTR) psidAdministrators;
  263. if (bIncludeBackupOperator) {
  264. eaExplicitAccess[2].grfAccessPermissions = dwAccessMask;
  265. eaExplicitAccess[2].grfAccessMode = SET_ACCESS;
  266. eaExplicitAccess[2].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  267. eaExplicitAccess[2].Trustee.pMultipleTrustee = NULL;
  268. eaExplicitAccess[2].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  269. eaExplicitAccess[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  270. eaExplicitAccess[2].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  271. eaExplicitAccess[2].Trustee.ptstrName = (LPTSTR) psidBackupOperators;
  272. }
  273. /*
  274. ** Create a new ACL that contains the new ACEs.
  275. */
  276. dwStatus = SetEntriesInAcl(bIncludeBackupOperator ? 3 : 2,
  277. eaExplicitAccess,
  278. NULL,
  279. &paclDiscretionaryAcl);
  280. if (ERROR_SUCCESS != dwStatus) {
  281. bResult = FALSE;
  282. }
  283. }
  284. if (bResult) {
  285. /*
  286. ** Add the ACL to the security descriptor.
  287. */
  288. bResult = SetSecurityDescriptorDacl(psaSecurityAttributes->lpSecurityDescriptor,
  289. TRUE,
  290. paclDiscretionaryAcl,
  291. FALSE
  292. );
  293. }
  294. if (bResult) {
  295. paclDiscretionaryAcl = NULL;
  296. }
  297. /*
  298. ** Clean up any left over junk.
  299. */
  300. if (NULL != psidLocalSystem) {
  301. FreeSid (psidLocalSystem);
  302. psidLocalSystem = NULL;
  303. }
  304. if (NULL != psidAdministrators) {
  305. FreeSid (psidAdministrators);
  306. psidAdministrators = NULL;
  307. }
  308. if (NULL != psidBackupOperators) {
  309. FreeSid (psidBackupOperators);
  310. psidBackupOperators = NULL;
  311. }
  312. if (NULL != paclDiscretionaryAcl) {
  313. LocalFree (paclDiscretionaryAcl);
  314. paclDiscretionaryAcl = NULL;
  315. }
  316. return bResult;
  317. } /* ConstructSecurityAttributes () */
  318. VOID
  319. AsrpCleanupSecurityAttributes(
  320. PSECURITY_ATTRIBUTES psaSecurityAttributes
  321. )
  322. {
  323. BOOL bSucceeded;
  324. BOOL bDaclPresent = FALSE;
  325. BOOL bDaclDefaulted = TRUE;
  326. PACL paclDiscretionaryAcl = NULL;
  327. bSucceeded = GetSecurityDescriptorDacl (psaSecurityAttributes->lpSecurityDescriptor,
  328. &bDaclPresent,
  329. &paclDiscretionaryAcl,
  330. &bDaclDefaulted);
  331. if (bSucceeded && bDaclPresent && !bDaclDefaulted && (NULL != paclDiscretionaryAcl)) {
  332. LocalFree (paclDiscretionaryAcl);
  333. }
  334. } /* CleanupSecurityAttributes () */
  335. BOOL
  336. AsrpIsInaccessibleSanDisk(
  337. IN CONST ULONG DeviceNumber
  338. )
  339. /*++
  340. Routine Description:
  341. Utility to check if the current disk is a shared SAN disk that's "owned"
  342. by a different machine (and is hence inaccessible).
  343. Arguments:
  344. DeviceNumber - NT Device number to the disk of interest.
  345. Return Value:
  346. If the function succeeds and the disk is a shared SAN disk that is
  347. owned by some other machine, the return value is a nonzero value.
  348. If the function fails, or if the disk is not a shared SAN disk that
  349. is owned by a different machine (ie, is a local unshared disk, or
  350. a shared disk owned by this machine) the return value
  351. is zero.
  352. --*/
  353. {
  354. DWORD dwStatus = ERROR_SUCCESS,
  355. dwDummy = 0;
  356. HANDLE hPartition = INVALID_HANDLE_VALUE;
  357. HANDLE heapHandle = GetProcessHeap();
  358. BOOL bIsInaccessibleDevice = FALSE;
  359. PWSTR lpPartitionPath = NULL;
  360. DWORD cchPartitionPath = 0;
  361. cchPartitionPath = MAX_PATH+1; //wcslen(lpDevicePath);
  362. lpPartitionPath = (LPWSTR) HeapAlloc(
  363. heapHandle,
  364. HEAP_ZERO_MEMORY,
  365. (cchPartitionPath + wcslen(ASR_PARTITION_1) + 1) * sizeof(WCHAR)
  366. );
  367. _AsrpErrExitCode(!lpPartitionPath, dwStatus, GetLastError())
  368. wsprintf(lpPartitionPath, ASR_PARTITION_1, DeviceNumber);
  369. //
  370. // Get a handle to the first partition on disk
  371. //
  372. hPartition = CreateFileW(
  373. lpPartitionPath, // lpFileName
  374. 0, // dwDesiredAccess
  375. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  376. NULL, // lpSecurityAttributes
  377. OPEN_EXISTING, // dwCreationFlags
  378. FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
  379. NULL // hTemplateFile
  380. );
  381. if ((!hPartition) || (INVALID_HANDLE_VALUE == hPartition)) {
  382. //
  383. // We couldn't open the partition. Now check for the specific error
  384. // code we're interested in (STATUS_OFF_LINE, which gets mapped to
  385. // ERROR_NOT_READY).
  386. //
  387. dwStatus = GetLastError();
  388. if (ERROR_NOT_READY == dwStatus) {
  389. bIsInaccessibleDevice = TRUE;
  390. }
  391. }
  392. else {
  393. //
  394. // Dynamic disks don't support this IOCTL, and will return a failure.
  395. // Basic disks that are online will return FALSE as well.
  396. //
  397. bIsInaccessibleDevice = DeviceIoControl(
  398. hPartition,
  399. IOCTL_VOLUME_IS_OFFLINE,
  400. NULL,
  401. 0,
  402. NULL,
  403. 0,
  404. &dwDummy,
  405. NULL
  406. );
  407. }
  408. EXIT:
  409. _AsrpCloseHandle(hPartition);
  410. _AsrpHeapFree(lpPartitionPath);
  411. return bIsInaccessibleDevice;
  412. }
  413. BOOL
  414. AsrpGetMountPoints(
  415. IN PCWSTR DeviceName,
  416. IN CONST DWORD SizeDeviceName,
  417. OUT PMOUNTMGR_MOUNT_POINTS *pMountPointsOut
  418. )
  419. /*++
  420. Routine Description:
  421. Returns the current list of mount-points for DeviceName, by querying the
  422. mount manager.
  423. Arguments:
  424. DeviceName - The device name that the mount-point list is requested for.
  425. Typically, this is something of the form
  426. \Device\HarddiskX\PartitionY or \DosDevices\X:
  427. SizeDeviceName - The size, in bytes, of DeviceName. This includes the
  428. terminating null character.
  429. pMountPointsOut - Receives the output list of mount-points. The caller
  430. must free this memory by calling HeapFree for the current process
  431. heap.
  432. Return Values:
  433. TRUE, if everything went well. MountPointsOut contains the promised data.
  434. FALSE, if the mount manager returned an error. MountPoints is NULL. Call
  435. GetLastError() for more information.
  436. --*/
  437. {
  438. PMOUNTMGR_MOUNT_POINT mountPointIn = NULL;
  439. PMOUNTMGR_MOUNT_POINTS mountPointsOut = NULL;
  440. MOUNTMGR_MOUNT_POINTS mountPointsTemp;
  441. DWORD mountPointsSize = 0;
  442. HANDLE mpHandle = NULL;
  443. HANDLE heapHandle = NULL;
  444. ULONG index = 0;
  445. LONG status = ERROR_SUCCESS;
  446. BOOL result = FALSE;
  447. memset(&mountPointsTemp, 0L, sizeof(MOUNTMGR_MOUNT_POINTS));
  448. MYASSERT(pMountPointsOut);
  449. *pMountPointsOut = NULL;
  450. heapHandle = GetProcessHeap();
  451. MYASSERT(heapHandle);
  452. mountPointIn = (PMOUNTMGR_MOUNT_POINT) HeapAlloc(
  453. heapHandle,
  454. HEAP_ZERO_MEMORY,
  455. sizeof (MOUNTMGR_MOUNT_POINT) + (SizeDeviceName - sizeof(WCHAR))
  456. );
  457. _AsrpErrExitCode((!mountPointIn), status, ERROR_NOT_ENOUGH_MEMORY);
  458. //
  459. // Try with a decently sized mountPoints out: if it isn't big
  460. // enough, we'll realloc as needed
  461. //
  462. mountPointsOut = (PMOUNTMGR_MOUNT_POINTS) HeapAlloc(
  463. heapHandle,
  464. HEAP_ZERO_MEMORY,
  465. (MAX_PATH + 1) * (sizeof(WCHAR))
  466. );
  467. _AsrpErrExitCode(!mountPointsOut, status, ERROR_NOT_ENOUGH_MEMORY);
  468. //
  469. // Get a handle to the mount manager
  470. //
  471. mpHandle = CreateFileW(
  472. MOUNTMGR_DOS_DEVICE_NAME, // lpFileName
  473. 0, // dwDesiredAccess
  474. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  475. NULL, // lpSecurityAttributes
  476. OPEN_EXISTING, // dwCreationFlags
  477. FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
  478. NULL // hTemplateFile
  479. );
  480. _AsrpErrExitCode((!mpHandle || INVALID_HANDLE_VALUE == mpHandle),
  481. status,
  482. GetLastError()
  483. );
  484. //
  485. // put the DeviceName right after struct mountPointIn
  486. //
  487. wcsncpy((PWSTR) (mountPointIn + 1),
  488. DeviceName,
  489. (SizeDeviceName / sizeof(WCHAR)) - 1
  490. );
  491. mountPointIn->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  492. mountPointIn->DeviceNameLength = (USHORT)(SizeDeviceName - sizeof(WCHAR));
  493. result = DeviceIoControl(
  494. mpHandle,
  495. IOCTL_MOUNTMGR_QUERY_POINTS,
  496. mountPointIn,
  497. sizeof(MOUNTMGR_MOUNT_POINT) + mountPointIn->DeviceNameLength,
  498. &mountPointsTemp,
  499. sizeof(MOUNTMGR_MOUNT_POINTS),
  500. &mountPointsSize,
  501. NULL
  502. );
  503. while (!result) {
  504. status = GetLastError();
  505. if (ERROR_MORE_DATA == status) {
  506. //
  507. // The buffer is not big enough, re-size and try again
  508. //
  509. status = ERROR_SUCCESS;
  510. _AsrpHeapFree(mountPointsOut);
  511. mountPointsOut = (PMOUNTMGR_MOUNT_POINTS) HeapAlloc(
  512. heapHandle,
  513. HEAP_ZERO_MEMORY,
  514. mountPointsTemp.Size
  515. );
  516. _AsrpErrExitCode((!mountPointsOut),
  517. status,
  518. ERROR_NOT_ENOUGH_MEMORY);
  519. result = DeviceIoControl(
  520. mpHandle,
  521. IOCTL_MOUNTMGR_QUERY_POINTS,
  522. mountPointIn,
  523. sizeof(MOUNTMGR_MOUNT_POINT) + mountPointIn->DeviceNameLength,
  524. mountPointsOut,
  525. mountPointsTemp.Size,
  526. &mountPointsSize,
  527. NULL
  528. );
  529. _AsrpErrExitCode((!mountPointsSize), status, GetLastError());
  530. }
  531. else {
  532. //
  533. // If some other error occurred, EXIT.
  534. //
  535. result = TRUE;
  536. status = GetLastError();
  537. // _AsrpErrExitCode(status, status, GetLastError());
  538. }
  539. }
  540. EXIT:
  541. //
  542. // Free up locally allocated memory
  543. //
  544. _AsrpHeapFree(mountPointIn);
  545. if (ERROR_SUCCESS != status) {
  546. //
  547. // On failure, free up mountPointsOut as well
  548. //
  549. _AsrpHeapFree(mountPointsOut);
  550. }
  551. _AsrpCloseHandle(mpHandle);
  552. *pMountPointsOut = mountPointsOut;
  553. return (BOOL) (ERROR_SUCCESS == status);
  554. }
  555. BOOL
  556. AsrpGetMorePartitionInfo(
  557. IN PCWSTR DeviceName,
  558. IN CONST DWORD SizeDeviceName,
  559. IN CONST PASR_SYSTEM_INFO pSystemInfo OPTIONAL,
  560. OUT PWSTR pVolumeGuid,
  561. OUT USHORT* pPartitionFlags OPTIONAL,
  562. OUT UCHAR* pFileSystemType OPTIONAL,
  563. OUT LPDWORD pClusterSize OPTIONAL
  564. )
  565. /*++
  566. Routine Description:
  567. Gets additional information about the partition specified by DeviceName,
  568. including the volume guid (if any) for the volume that maps to the
  569. partition specified by DeviceName.
  570. If the partition is the current system or boot drive, pPartitionFlags and
  571. pFileSystemType are set appropriately.
  572. Arguments:
  573. DeviceName - A null terminated string containing the device path to the
  574. partition, typically of the form \Device\HarddiskX\PartitionY
  575. SizeDeviceName - Size, in bytes, of DeviceName, including \0 at the end
  576. pSystemInfo - The SYSTEM_INFO structure for the current system; used for
  577. finding out the current system partition.
  578. This is an optional parameter. If absent, pPartitionFlags will
  579. not have the SYSTEM_FLAG set, even if DeviceName is in fact the
  580. system partition.
  581. pVolumeGuid - Receives a null-terminated string containing the GUID for
  582. the volume on this partition. This is only relevant for basic
  583. disks, where volumes and partitions have a one-on-one
  584. relationship.
  585. This will be set to a blank null-terminated string if there is no
  586. volume (or multiple volumes) on this partition.
  587. *** Note that if ANY of three of the OPTIONAL parameters are not present,
  588. NONE of them will be filled with valid data.
  589. pPartitionFlags - If the current partition is a partition of interest,
  590. this receives the appropriate flags, IN ADDITION TO THE FLAGS
  591. ALREADY SET when the routine is called (i.e., caller should
  592. usually zero this out). Currently, the two flags of interest are:
  593. ASR_FLAGS_BOOT_PTN for the boot partition
  594. ASR_FLAGS_SYSTEM_PTN for (you guessed it) the system partition
  595. pFileSystemType - If (and ONLY if) the current partition is a partition of
  596. interest, this will contain a UCHAR to the file-system type of the
  597. partition. Currently, the three file-systems this recognises are:
  598. PARTITION_HUGE (FAT)
  599. PARTITION_FAT32 (FAT32)
  600. PARTITION_IFS (NTFS)
  601. pClusterSize - The file-system cluster size. Set to 0 if the information
  602. could not be obtained.
  603. Return Value:
  604. If the function succeeds, the return value is a nonzero value.
  605. If the function fails, the return value is zero. To get extended error
  606. information, call GetLastError().
  607. --*/
  608. {
  609. PMOUNTMGR_MOUNT_POINTS mountPointsOut = NULL;
  610. HANDLE heapHandle = NULL;
  611. ULONG index = 0;
  612. LONG status = ERROR_SUCCESS;
  613. BOOL result = FALSE;
  614. BOOL volumeGuidSet = FALSE;
  615. //
  616. // set OUT variables to known values.
  617. //
  618. MYASSERT(pVolumeGuid);
  619. wcscpy(pVolumeGuid, L"");
  620. /* if (ARGUMENT_PRESENT(pPartitionFlags)) {
  621. *pPartitionFlags = 0;
  622. }
  623. */
  624. if (ARGUMENT_PRESENT(pClusterSize)) {
  625. *pClusterSize = 0;
  626. }
  627. heapHandle = GetProcessHeap();
  628. MYASSERT(heapHandle);
  629. //
  630. // Open the mount manager, and get a list of all the symbolic links
  631. // this partition
  632. //
  633. result = AsrpGetMountPoints(DeviceName, SizeDeviceName, &mountPointsOut);
  634. _AsrpErrExitCode((!result), status, GetLastError());
  635. _AsrpErrExitCode((!mountPointsOut), status, ERROR_SUCCESS);
  636. //
  637. // Check if this is the system partition, by comparing the
  638. // device path with the one stored in the Setup key.
  639. //
  640. if (ARGUMENT_PRESENT(pSystemInfo) && ARGUMENT_PRESENT(pPartitionFlags)) {
  641. PWSTR deviceName = (PWSTR) (
  642. ((LPBYTE) mountPointsOut) +
  643. mountPointsOut->MountPoints[index].DeviceNameOffset
  644. );
  645. UINT sizeDeviceName =
  646. (UINT)(mountPointsOut->MountPoints[index].DeviceNameLength);
  647. if ((pSystemInfo->SystemPath) &&
  648. (wcslen(pSystemInfo->SystemPath)==sizeDeviceName/sizeof(WCHAR)) &&
  649. (!wcsncmp(pSystemInfo->SystemPath, deviceName,
  650. sizeDeviceName/sizeof(WCHAR)))
  651. ) {
  652. *pPartitionFlags |= ASR_FLAGS_SYSTEM_PTN;
  653. }
  654. }
  655. for (index = 0; index < mountPointsOut->NumberOfMountPoints; index++) {
  656. //
  657. // Go through the list of mount points returned, and find the one
  658. // that looks like an nt volume guid
  659. //
  660. PWSTR linkName = (PWSTR) (((LPBYTE) mountPointsOut) +
  661. mountPointsOut->MountPoints[index].SymbolicLinkNameOffset
  662. );
  663. UINT sizeLinkName =
  664. (UINT)(mountPointsOut->MountPoints[index].SymbolicLinkNameLength);
  665. if ((!volumeGuidSet) &&
  666. !wcsncmp(ASR_WSZ_VOLUME_PREFIX,
  667. linkName,
  668. wcslen(ASR_WSZ_VOLUME_PREFIX))
  669. ) {
  670. wcsncpy(pVolumeGuid, linkName, sizeLinkName / sizeof(WCHAR));
  671. volumeGuidSet = TRUE; // we got a GUID, no need to check again
  672. }
  673. else if (
  674. ARGUMENT_PRESENT(pSystemInfo) &&
  675. ARGUMENT_PRESENT(pPartitionFlags)
  676. ) {
  677. //
  678. // Also, if this link isn't a GUID, it might be a drive letter.
  679. // use the boot directory's drive letter to check if this
  680. // is the boot volume, and mark it if so.
  681. //
  682. if (!wcsncmp(ASR_DOS_DEVICES_PREFIX,
  683. linkName,
  684. wcslen(ASR_DOS_DEVICES_PREFIX))
  685. ) {
  686. if ((pSystemInfo->BootDirectory) &&
  687. (pSystemInfo->BootDirectory[0]
  688. == linkName[wcslen(ASR_DOS_DEVICES_PREFIX)])
  689. ) {
  690. *pPartitionFlags |= ASR_FLAGS_BOOT_PTN;
  691. }
  692. }
  693. }
  694. }
  695. EXIT:
  696. //
  697. // If this is a partition of interest, we need to get the file-system
  698. // type as well
  699. //
  700. if (ARGUMENT_PRESENT(pFileSystemType) &&
  701. ARGUMENT_PRESENT(pPartitionFlags) &&
  702. ARGUMENT_PRESENT(pClusterSize)
  703. ) {
  704. if (*pPartitionFlags) {
  705. WCHAR fsName[20];
  706. DWORD dwSectorsPerCluster = 0,
  707. dwBytesPerSector = 0,
  708. dwNumFreeClusters = 0,
  709. dwTotalNumClusters = 0;
  710. //
  711. // Convert the NT Volume-GUID (starts with \??\) to a DOS
  712. // Volume (begins with a \\?\, and ends with a back-slash),
  713. // since GetVolumeInformation needs it in this format.
  714. //
  715. pVolumeGuid[1] = L'\\';
  716. wcscat(pVolumeGuid, L"\\");
  717. memset(fsName, 0L, 20*sizeof(WCHAR));
  718. result = GetVolumeInformationW(pVolumeGuid, NULL, 0L,
  719. NULL, NULL, NULL, fsName, 20);
  720. if (result) {
  721. if (!wcscmp(fsName, L"NTFS")) {
  722. *pFileSystemType = PARTITION_IFS;
  723. }
  724. else if (!wcscmp(fsName, L"FAT32")) {
  725. *pFileSystemType = PARTITION_FAT32;
  726. }
  727. else if (!wcscmp(fsName, L"FAT")) {
  728. *pFileSystemType = PARTITION_HUGE;
  729. }
  730. else {
  731. *pFileSystemType = 0;
  732. }
  733. }
  734. else {
  735. GetLastError(); // debug
  736. }
  737. result = GetDiskFreeSpace(pVolumeGuid,
  738. &dwSectorsPerCluster,
  739. &dwBytesPerSector,
  740. &dwNumFreeClusters,
  741. &dwTotalNumClusters
  742. );
  743. if (result) {
  744. *pClusterSize = dwSectorsPerCluster * dwBytesPerSector;
  745. }
  746. else {
  747. GetLastError(); // debug
  748. }
  749. //
  750. // Convert the guid back to NT namespace, by changing \\?\
  751. // to \??\ and removing the trailing slash.
  752. //
  753. pVolumeGuid[1] = L'?';
  754. pVolumeGuid[wcslen(pVolumeGuid)-1] = L'\0';
  755. }
  756. }
  757. //
  758. // Free up locally allocated data
  759. //
  760. _AsrpHeapFree(mountPointsOut);
  761. //
  762. // If we hit errors, make sure the VolumeGuid is a blank string.
  763. //
  764. if (status != ERROR_SUCCESS) {
  765. wcscpy(pVolumeGuid, L"");
  766. }
  767. return (BOOL) (status == ERROR_SUCCESS);
  768. }
  769. BOOL
  770. AsrpDetermineBuses(
  771. IN PASR_DISK_INFO pDiskList
  772. )
  773. /*++
  774. Routine Description:
  775. This attempts to group the disks based on which bus they are on. For
  776. SCSI disks, this is relatively easy, since it can be based on the
  777. location info (port).
  778. For other disks, we attempt to get the PnP parent node of the disks, and
  779. group all disks having the same parent.
  780. The groups are identified by the SifBusKey field of each disk structure--
  781. i.e., all disks that have SifBusKey == 1 are on one bus, SifBusKey == 2
  782. are on another bus, and so on. The SifBusKey values are guaranteed to be
  783. sequential, and not have any holes (i.e., For a system with "n" buses,
  784. the SifBusKey values will be 1,2,3,...,n).
  785. At the end SifBusKey is zero for disks which couldn't be grouped.
  786. Arguments:
  787. pDiskList - The ASR_DISK_INFO list of disks present on the current system.
  788. Return Value:
  789. If the function succeeds, the return value is a nonzero value.
  790. If the function fails, the return value is zero. To get extended error
  791. information, call GetLastError().
  792. --*/
  793. {
  794. BOOL done = FALSE,
  795. newPass = TRUE;
  796. ULONG port = 0,
  797. sifBusKey = 0;
  798. DEVINST parent;
  799. STORAGE_BUS_TYPE busType = BusTypeUnknown;
  800. PASR_DISK_INFO pCurrentDisk = pDiskList;
  801. //
  802. // The first pass goes through and groups all the scsi disks together.
  803. // Note that this works for IDE too, since IDE disks respond to the
  804. // IOCTL_SCSI_GET_ADDRESS and appear to us to have valid location info.
  805. //
  806. do {
  807. sifBusKey++;
  808. pCurrentDisk = pDiskList;
  809. done = TRUE;
  810. newPass = TRUE;
  811. while (pCurrentDisk) {
  812. if ((BusTypeUnknown == pCurrentDisk->BusType) ||
  813. (!pCurrentDisk->pScsiAddress)) {
  814. pCurrentDisk = pCurrentDisk->pNext;
  815. continue;
  816. }
  817. if (0 == pCurrentDisk->SifBusKey) {
  818. done = FALSE;
  819. if (newPass) {
  820. pCurrentDisk->SifBusKey = sifBusKey;
  821. port = pCurrentDisk->pScsiAddress->PortNumber;
  822. busType = pCurrentDisk->BusType;
  823. newPass = FALSE;
  824. }
  825. else {
  826. if ((pCurrentDisk->pScsiAddress->PortNumber == port) &&
  827. (pCurrentDisk->BusType == busType)) {
  828. pCurrentDisk->SifBusKey = sifBusKey;
  829. }
  830. }
  831. }
  832. pCurrentDisk = pCurrentDisk->pNext;
  833. }
  834. } while (!done);
  835. //
  836. // By now, the only disks with SifBusKey is 0 are disks for which
  837. // pScsiAddress is NULL, ie (most-likely) non SCSI/IDE disks. Attempt
  838. // to group them on the basis of their parent dev node (which is usually
  839. // the bus). We may have to loop through multiple times again.
  840. //
  841. --sifBusKey; // compensate for the last pass above
  842. do {
  843. sifBusKey++;
  844. pCurrentDisk = pDiskList;
  845. done = TRUE;
  846. newPass = TRUE;
  847. while (pCurrentDisk) {
  848. if ((BusTypeUnknown == pCurrentDisk->BusType) ||
  849. (!pCurrentDisk->pScsiAddress)) {
  850. if ((0 == pCurrentDisk->SifBusKey)
  851. && (pCurrentDisk->ParentDevInst)) {
  852. done = FALSE;
  853. if (newPass) {
  854. pCurrentDisk->SifBusKey = sifBusKey;
  855. parent = pCurrentDisk->ParentDevInst;
  856. newPass = FALSE;
  857. }
  858. else {
  859. if (pCurrentDisk->ParentDevInst == parent) {
  860. pCurrentDisk->SifBusKey = sifBusKey;
  861. }
  862. }
  863. }
  864. }
  865. pCurrentDisk = pCurrentDisk->pNext;
  866. }
  867. } while (!done);
  868. //
  869. // Disks that still have SifBusKey = 0 couldn't be grouped. Either the
  870. // BusType is unknown, or the parent node couldn't be found.
  871. //
  872. return TRUE;
  873. }
  874. BOOL
  875. AsrpGetDiskLayout(
  876. IN CONST HANDLE hDisk,
  877. IN CONST PASR_SYSTEM_INFO pSystemInfo,
  878. OUT PASR_DISK_INFO pCurrentDisk,
  879. IN BOOL AllDetails
  880. )
  881. /*++
  882. Routine Description:
  883. Fills in the fields of the pCurrentDisk structure with the relevant
  884. information about the disk represented by hDisk, by querying the system
  885. with the appropriate IOCTL's.
  886. Arguments:
  887. hDisk - handle to the disk of interest.
  888. pSystemInfo - The SYSTEM_INFO structure for the current system.
  889. pCurrentDisk - Receives the information about the disk represented by
  890. hDisk
  891. AllDetails - If FALSE, only the pDriveLayout information of pCurrentDisk
  892. is filled in. This is an optimisation that comes in handy when
  893. we're dealing with disks on a shared cluster bus.
  894. If TRUE, all the fields of pCurrentDisk are filled in.
  895. Return Value:
  896. If the function succeeds, the return value is a nonzero value.
  897. If the function fails, the return value is zero. To get extended error
  898. information, call GetLastError().
  899. --*/
  900. {
  901. DWORD index = 0,
  902. status = ERROR_SUCCESS;
  903. DWORD dwBytesReturned = 0L,
  904. bufferLength = 0L;
  905. BOOL result = FALSE;
  906. PDISK_GEOMETRY diskGeometry = NULL;
  907. DWORD sizeDiskGeometry = 0L;
  908. PDRIVE_LAYOUT_INFORMATION_EX driveLayoutEx = NULL;
  909. DWORD sizeDriveLayoutEx = 0L;
  910. STORAGE_DEVICE_NUMBER deviceNumber;
  911. DWORD sizeDeviceNumber = 0L;
  912. PPARTITION_INFORMATION_EX partition0Ex = NULL;
  913. DWORD sizePartition0Ex = 0L;
  914. PASR_PTN_INFO pPartitionTable = NULL;
  915. DWORD sizePartitionTable = 0L;
  916. STORAGE_PROPERTY_QUERY propertyQuery;
  917. STORAGE_DEVICE_DESCRIPTOR *deviceDesc = NULL;
  918. STORAGE_BUS_TYPE busType = BusTypeUnknown;
  919. PSCSI_ADDRESS scsiAddress = NULL;
  920. HANDLE heapHandle = GetProcessHeap(); // For memory allocations
  921. MYASSERT(heapHandle); // It better not be NULL
  922. MYASSERT(pCurrentDisk);
  923. MYASSERT((hDisk) && (INVALID_HANDLE_VALUE != hDisk));
  924. //
  925. // Initialize OUT variables to known values
  926. //
  927. pCurrentDisk->Style = PARTITION_STYLE_RAW;
  928. pCurrentDisk->pDriveLayoutEx = NULL;
  929. pCurrentDisk->sizeDriveLayoutEx = 0L;
  930. pCurrentDisk->pDiskGeometry = NULL;
  931. pCurrentDisk->sizeDiskGeometry = 0L;
  932. pCurrentDisk->pPartition0Ex = NULL;
  933. pCurrentDisk->sizePartition0Ex = 0L;
  934. pCurrentDisk->pScsiAddress = NULL;
  935. pCurrentDisk->BusType = BusTypeUnknown;
  936. pCurrentDisk->SifBusKey = 0L;
  937. SetLastError(ERROR_SUCCESS);
  938. //
  939. // Get the device number for this device. This should succeed even if
  940. // this is a clustered disk that this node doesn't own.
  941. //
  942. result = DeviceIoControl(
  943. hDisk,
  944. IOCTL_STORAGE_GET_DEVICE_NUMBER,
  945. NULL,
  946. 0,
  947. &deviceNumber,
  948. sizeof(STORAGE_DEVICE_NUMBER),
  949. &sizeDeviceNumber,
  950. NULL
  951. );
  952. _AsrpErrExitCode(!result, status, GetLastError());
  953. pCurrentDisk->DeviceNumber = deviceNumber.DeviceNumber;
  954. //
  955. // The output buffer for IOCTL_DISK_GET_DRIVE_LAYOUT_EX consists of a
  956. // DRIVE_LAYOUT_INFORMATION_EX structure as a header, followed by an
  957. // array of PARTITION_INFORMATION_EX structures.
  958. //
  959. // We initially allocate enough space for the DRIVE_LAYOUT_INFORMATION_EX
  960. // struct, which contains a single PARTITION_INFORMATION_EX struct, and
  961. // 3 more PARTITION_INFORMATION_EX structs, since each (MBR) disk will
  962. // have a minimum of four partitions, even if they are not all in use.
  963. // If the disk contains more than four partitions, we'll increase the
  964. // buffer size as needed
  965. //
  966. bufferLength = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
  967. (sizeof(PARTITION_INFORMATION_EX) * 3);
  968. driveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  969. heapHandle,
  970. HEAP_ZERO_MEMORY,
  971. bufferLength
  972. );
  973. _AsrpErrExitCode(!driveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY);
  974. result = FALSE;
  975. while (!result) {
  976. result = DeviceIoControl(
  977. hDisk,
  978. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  979. NULL,
  980. 0L,
  981. driveLayoutEx,
  982. bufferLength,
  983. &sizeDriveLayoutEx,
  984. NULL
  985. );
  986. if (!result) {
  987. status = GetLastError();
  988. _AsrpHeapFree(driveLayoutEx);
  989. //
  990. // If the buffer is of insufficient size, resize the buffer.
  991. // Note that get-drive-layout-ex could return error-insufficient-
  992. // buffer (instead of? in addition to? error-more-data)
  993. //
  994. if ((ERROR_MORE_DATA == status) ||
  995. (ERROR_INSUFFICIENT_BUFFER == status)
  996. ) {
  997. status = ERROR_SUCCESS;
  998. bufferLength += sizeof(PARTITION_INFORMATION_EX) * 4;
  999. driveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  1000. heapHandle,
  1001. HEAP_ZERO_MEMORY,
  1002. bufferLength
  1003. );
  1004. _AsrpErrExitCode(!driveLayoutEx,
  1005. status,
  1006. ERROR_NOT_ENOUGH_MEMORY
  1007. );
  1008. }
  1009. else {
  1010. //
  1011. // some other error occurred, EXIT, and go to the next drive.
  1012. //
  1013. result = TRUE;
  1014. status = ERROR_SUCCESS;
  1015. }
  1016. }
  1017. else {
  1018. if (!AllDetails) {
  1019. //
  1020. // If we don't want all the details for this disk, just exit
  1021. // now. This is used in the case of clusters, where we don't
  1022. // want to get all the details twice even if the current node
  1023. // owns the disk
  1024. //
  1025. pCurrentDisk->pDriveLayoutEx = driveLayoutEx;
  1026. pCurrentDisk->sizeDriveLayoutEx = sizeDriveLayoutEx;
  1027. //
  1028. // Jump to EXIT
  1029. //
  1030. _AsrpErrExitCode(TRUE, status, ERROR_SUCCESS);
  1031. }
  1032. //
  1033. // The disk geometry: so that we can match the bytes-per-sector
  1034. // value during restore.
  1035. //
  1036. diskGeometry = (PDISK_GEOMETRY) HeapAlloc(
  1037. heapHandle,
  1038. HEAP_ZERO_MEMORY,
  1039. sizeof(DISK_GEOMETRY)
  1040. );
  1041. _AsrpErrExitCode(!diskGeometry, status, ERROR_NOT_ENOUGH_MEMORY);
  1042. result = DeviceIoControl(
  1043. hDisk,
  1044. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  1045. NULL,
  1046. 0,
  1047. diskGeometry,
  1048. sizeof(DISK_GEOMETRY),
  1049. &sizeDiskGeometry,
  1050. NULL
  1051. );
  1052. _AsrpErrExitCode(!result, status, ERROR_READ_FAULT);
  1053. partition0Ex = (PPARTITION_INFORMATION_EX) HeapAlloc(
  1054. heapHandle,
  1055. HEAP_ZERO_MEMORY,
  1056. sizeof(PARTITION_INFORMATION_EX)
  1057. );
  1058. _AsrpErrExitCode(!partition0Ex, status, ERROR_NOT_ENOUGH_MEMORY);
  1059. //
  1060. // Information about partition 0 (the whole disk), to get the true
  1061. // sector count of the disk
  1062. //
  1063. result = DeviceIoControl(
  1064. hDisk,
  1065. IOCTL_DISK_GET_PARTITION_INFO_EX,
  1066. NULL,
  1067. 0,
  1068. partition0Ex,
  1069. sizeof(PARTITION_INFORMATION_EX),
  1070. &sizePartition0Ex,
  1071. NULL
  1072. );
  1073. _AsrpErrExitCode(!result, status, ERROR_READ_FAULT);
  1074. //
  1075. // Figure out the bus that this disk is on. This will only be
  1076. // used to group the disks--all the disks on a bus will be
  1077. // restored to the same bus if possible
  1078. //
  1079. propertyQuery.QueryType = PropertyStandardQuery;
  1080. propertyQuery.PropertyId = StorageDeviceProperty;
  1081. deviceDesc = (STORAGE_DEVICE_DESCRIPTOR *) HeapAlloc(
  1082. heapHandle,
  1083. HEAP_ZERO_MEMORY,
  1084. ASR_BUFFER_SIZE
  1085. );
  1086. _AsrpErrExitCode(!deviceDesc, status, ERROR_NOT_ENOUGH_MEMORY);
  1087. result = DeviceIoControl(
  1088. hDisk,
  1089. IOCTL_STORAGE_QUERY_PROPERTY,
  1090. &propertyQuery,
  1091. sizeof(STORAGE_PROPERTY_QUERY),
  1092. deviceDesc,
  1093. ASR_BUFFER_SIZE,
  1094. &dwBytesReturned,
  1095. NULL
  1096. );
  1097. if (result) {
  1098. busType = deviceDesc->BusType;
  1099. }
  1100. _AsrpHeapFree(deviceDesc);
  1101. scsiAddress = (PSCSI_ADDRESS) HeapAlloc(
  1102. heapHandle,
  1103. HEAP_ZERO_MEMORY,
  1104. sizeof(SCSI_ADDRESS)
  1105. );
  1106. _AsrpErrExitCode(!scsiAddress, status, ERROR_NOT_ENOUGH_MEMORY);
  1107. result = DeviceIoControl(
  1108. hDisk,
  1109. IOCTL_SCSI_GET_ADDRESS,
  1110. NULL,
  1111. 0,
  1112. scsiAddress,
  1113. sizeof(SCSI_ADDRESS),
  1114. &dwBytesReturned,
  1115. NULL
  1116. );
  1117. if (!result) { // Not fatal--expected for non SCSI/IDE disks
  1118. _AsrpHeapFree(scsiAddress);
  1119. result = TRUE;
  1120. }
  1121. }
  1122. }
  1123. if (driveLayoutEx) {
  1124. PPARTITION_INFORMATION_EX currentPartitionEx = NULL;
  1125. WCHAR devicePath[MAX_PATH + 1];
  1126. pCurrentDisk->Style = driveLayoutEx->PartitionStyle;
  1127. sizePartitionTable = sizeof(ASR_PTN_INFO) *
  1128. (driveLayoutEx->PartitionCount);
  1129. pPartitionTable = (PASR_PTN_INFO) HeapAlloc(
  1130. heapHandle,
  1131. HEAP_ZERO_MEMORY,
  1132. sizePartitionTable
  1133. );
  1134. _AsrpErrExitCode(!pPartitionTable, status, ERROR_NOT_ENOUGH_MEMORY);
  1135. for (index = 0; index < driveLayoutEx->PartitionCount; index++) {
  1136. currentPartitionEx = &driveLayoutEx->PartitionEntry[index];
  1137. pPartitionTable[index].SlotIndex = index;
  1138. if (currentPartitionEx->PartitionNumber) {
  1139. swprintf(devicePath,
  1140. ASR_WSZ_DEVICE_PATH_FORMAT,
  1141. deviceNumber.DeviceNumber,
  1142. currentPartitionEx->PartitionNumber
  1143. );
  1144. pPartitionTable[index].PartitionFlags = 0;
  1145. //
  1146. // Check specially for the EFI system partition
  1147. //
  1148. if ((PARTITION_STYLE_GPT == driveLayoutEx->PartitionStyle) &&
  1149. IsEqualGUID(&(currentPartitionEx->Gpt.PartitionType), &(PARTITION_SYSTEM_GUID))
  1150. ) {
  1151. pPartitionTable[index].PartitionFlags |= ASR_FLAGS_SYSTEM_PTN;
  1152. }
  1153. AsrpGetMorePartitionInfo(
  1154. devicePath,
  1155. (wcslen(devicePath)+1) * sizeof(WCHAR), // cb including \0
  1156. pSystemInfo,
  1157. pPartitionTable[index].szVolumeGuid,
  1158. &(pPartitionTable[index].PartitionFlags),
  1159. &(pPartitionTable[index].FileSystemType),
  1160. &(pPartitionTable[index].ClusterSize)
  1161. );
  1162. //
  1163. // Make sure that the file-system type for the EFI system
  1164. // partition is set to FAT
  1165. //
  1166. if ((PARTITION_STYLE_GPT == driveLayoutEx->PartitionStyle) &&
  1167. IsEqualGUID(&(currentPartitionEx->Gpt.PartitionType), &(PARTITION_SYSTEM_GUID))
  1168. ) {
  1169. pPartitionTable[index].FileSystemType = PARTITION_HUGE;
  1170. }
  1171. if (pPartitionTable[index].PartitionFlags) {
  1172. pCurrentDisk->IsCritical = TRUE;
  1173. }
  1174. }
  1175. }
  1176. }
  1177. pCurrentDisk->pDriveLayoutEx = driveLayoutEx;
  1178. pCurrentDisk->sizeDriveLayoutEx = sizeDriveLayoutEx;
  1179. pCurrentDisk->pDiskGeometry = diskGeometry;
  1180. pCurrentDisk->sizeDiskGeometry = sizeDiskGeometry;
  1181. pCurrentDisk->DeviceNumber = deviceNumber.DeviceNumber;
  1182. pCurrentDisk->pPartition0Ex = partition0Ex;
  1183. pCurrentDisk->sizePartition0Ex = sizePartition0Ex;
  1184. pCurrentDisk->pScsiAddress = scsiAddress;
  1185. pCurrentDisk->BusType = busType;
  1186. pCurrentDisk->PartitionInfoTable = pPartitionTable;
  1187. pCurrentDisk->sizePartitionInfoTable = sizePartitionTable;
  1188. EXIT:
  1189. //
  1190. // Free up locally allocated memory on failure
  1191. //
  1192. if (status != ERROR_SUCCESS) {
  1193. _AsrpHeapFree(driveLayoutEx);
  1194. _AsrpHeapFree(diskGeometry);
  1195. _AsrpHeapFree(partition0Ex);
  1196. _AsrpHeapFree(scsiAddress);
  1197. _AsrpHeapFree(pPartitionTable);
  1198. }
  1199. //
  1200. // Make sure the last error is set if we are going to return FALSE
  1201. //
  1202. if ((ERROR_SUCCESS != status) && (ERROR_SUCCESS == GetLastError())) {
  1203. SetLastError(status);
  1204. }
  1205. return (BOOL) (status == ERROR_SUCCESS);
  1206. }
  1207. BOOL
  1208. AsrpGetSystemPath(
  1209. IN PASR_SYSTEM_INFO pSystemInfo
  1210. )
  1211. /*++
  1212. Routine Description:
  1213. Gets the system partition DevicePath, and fills in the SystemPath field
  1214. of the ASR_SYSTEM_INFO struct, by looking up the HKLM\Setup registry key.
  1215. This key is updated at every boot with the path to the current system
  1216. device. The path is of the form
  1217. \Device\Harddisk0\Partition1 (basic disks)
  1218. \Device\HarddiskDmVolumes\DgName\Volume1 (dynamic disks)
  1219. Arguments:
  1220. pSystemInfo - The SystemPath field of this struct will be filled with
  1221. a pointer to the path to the current system device
  1222. Return Value:
  1223. If the function succeeds, the return value is a nonzero value.
  1224. pSystemInfo->SystemPath is a pointer to a null-terminated string
  1225. containing the path to the current system device. The caller is
  1226. reponsible for freeing this memory with a call to
  1227. HeapFree(GetProcessHeap(),...).
  1228. If the function fails, the return value is zero. To get extended error
  1229. information, call GetLastError(). pSystemInfo->SystemPath is set
  1230. to NULL.
  1231. --*/
  1232. {
  1233. HKEY regKey = NULL;
  1234. DWORD type = 0L;
  1235. HANDLE heapHandle = NULL;
  1236. DWORD status = ERROR_SUCCESS;
  1237. PWSTR systemPartition = NULL;
  1238. DWORD cbSystemPartition = 0L;
  1239. heapHandle = GetProcessHeap();
  1240. MYASSERT(heapHandle);
  1241. MYASSERT(pSystemInfo);
  1242. if (!pSystemInfo) {
  1243. SetLastError(ERROR_BAD_ENVIRONMENT);
  1244. return FALSE;
  1245. }
  1246. pSystemInfo->SystemPath = NULL;
  1247. //
  1248. // Open the reg key to find the system partition
  1249. //
  1250. status = RegOpenKeyExW(
  1251. HKEY_LOCAL_MACHINE, // hKey
  1252. ASR_REGKEY_SETUP, // lpSubKey
  1253. 0, // ulOptions--Reserved, must be 0
  1254. MAXIMUM_ALLOWED, // samDesired
  1255. &regKey // phkResult
  1256. );
  1257. _AsrpErrExitCode(status, status, ERROR_REGISTRY_IO_FAILED);
  1258. //
  1259. // Allocate a reasonably sized buffer for the system partition, to
  1260. // start off with. If this isn't big enough, we'll re-allocate as
  1261. // needed.
  1262. //
  1263. cbSystemPartition = (MAX_PATH + 1) * sizeof(WCHAR);
  1264. systemPartition = HeapAlloc(heapHandle,
  1265. HEAP_ZERO_MEMORY,
  1266. cbSystemPartition
  1267. );
  1268. _AsrpErrExitCode((!systemPartition), status, ERROR_NOT_ENOUGH_MEMORY);
  1269. //
  1270. // Get the system partition device Name. This is of the form
  1271. // \Device\Harddisk0\Partition1 (basic disks)
  1272. // \Device\HarddiskDmVolumes\DgName\Volume1 (dynamic disks)
  1273. //
  1274. status = RegQueryValueExW(
  1275. regKey,
  1276. ASR_REGVALUE_SYSTEM_PARTITION,
  1277. NULL,
  1278. &type,
  1279. (LPBYTE)systemPartition,
  1280. &cbSystemPartition // \0 is included
  1281. );
  1282. _AsrpErrExitCode((type != REG_SZ), status, ERROR_REGISTRY_IO_FAILED);
  1283. while (ERROR_MORE_DATA == status) {
  1284. //
  1285. // Our buffer wasn't big enough, cbSystemPartition contains
  1286. // the required size.
  1287. //
  1288. _AsrpHeapFree(systemPartition);
  1289. systemPartition = HeapAlloc(heapHandle,
  1290. HEAP_ZERO_MEMORY,
  1291. cbSystemPartition
  1292. );
  1293. _AsrpErrExitCode((!systemPartition), status, ERROR_NOT_ENOUGH_MEMORY);
  1294. status = RegQueryValueExW(
  1295. regKey,
  1296. ASR_REGVALUE_SYSTEM_PARTITION,
  1297. NULL,
  1298. &type,
  1299. (LPBYTE)systemPartition,
  1300. &cbSystemPartition // \0 is included
  1301. );
  1302. }
  1303. EXIT:
  1304. if (regKey) {
  1305. RegCloseKey(regKey);
  1306. regKey = NULL;
  1307. }
  1308. if (ERROR_SUCCESS != status) {
  1309. _AsrpHeapFree(systemPartition);
  1310. return FALSE;
  1311. }
  1312. else {
  1313. pSystemInfo->SystemPath = systemPartition;
  1314. return TRUE;
  1315. }
  1316. }
  1317. BOOL
  1318. AsrpInitSystemInformation(
  1319. IN OUT PASR_SYSTEM_INFO pSystemInfo,
  1320. IN CONST BOOL bEnableAutoExtend
  1321. )
  1322. /*++
  1323. Routine Description:
  1324. Initialisation routine to allocate memory for various fields in the
  1325. ASR_SYSTEM_INFO structure, and fill them in with the relevant information.
  1326. Arguments:
  1327. pSystemInfo - The struct to be filled in with info about the current
  1328. system.
  1329. Return Value:
  1330. If the function succeeds, the return value is a nonzero value. The caller
  1331. is responsible for freeing memory pointed to by the various
  1332. pointers in the struct, using HeapFree(GetProcessHeap(),...).
  1333. If the function fails, the return value is zero. To get extended error
  1334. information, call GetLastError(). The caller is still responsible
  1335. for checking the fields and releasing any non-NULL pointers using
  1336. HeapFree(GetProcessHeap(),...).
  1337. --*/
  1338. {
  1339. DWORD cchBootDirectory = 0L,
  1340. reqdSize = 0L;
  1341. BOOL result = FALSE;
  1342. HANDLE heapHandle = GetProcessHeap();
  1343. //
  1344. // Initialise the structure to zeroes
  1345. //
  1346. memset(pSystemInfo, 0L, sizeof (ASR_SYSTEM_INFO));
  1347. //
  1348. // The auto-extension feature
  1349. //
  1350. pSystemInfo->AutoExtendEnabled = bEnableAutoExtend;
  1351. //
  1352. // Get the machine name
  1353. //
  1354. pSystemInfo->sizeComputerName = MAX_COMPUTERNAME_LENGTH + 1;
  1355. if (!GetComputerNameW(pSystemInfo->ComputerName,
  1356. &(pSystemInfo->sizeComputerName)
  1357. )) {
  1358. //
  1359. // GetComputerName sets LastError
  1360. //
  1361. return FALSE;
  1362. }
  1363. //
  1364. // Get the Processor Architecture. We expect the process architecture
  1365. // to be a either x86, amd64, or ia64, so if it doesn't fit in our buffer of
  1366. // six characters, we don't support it anyway.
  1367. //
  1368. pSystemInfo->Platform = HeapAlloc(heapHandle,
  1369. HEAP_ZERO_MEMORY,
  1370. 6*sizeof(WCHAR)
  1371. );
  1372. if (!pSystemInfo->Platform) {
  1373. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1374. return FALSE;
  1375. }
  1376. reqdSize = GetEnvironmentVariableW(L"PROCESSOR_ARCHITECTURE",
  1377. pSystemInfo->Platform,
  1378. 6
  1379. );
  1380. if (0 == reqdSize) {
  1381. //
  1382. // We couldn't find the PROCESSOR_ARCHITECTURE variable
  1383. //
  1384. SetLastError(ERROR_BAD_ENVIRONMENT);
  1385. return FALSE;
  1386. }
  1387. if (reqdSize > 6) {
  1388. //
  1389. // The architecture didn't fit in our buffer
  1390. //
  1391. SetLastError(ERROR_NOT_SUPPORTED);
  1392. return FALSE;
  1393. }
  1394. //
  1395. // Get the OS version
  1396. //
  1397. pSystemInfo->OsVersionEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1398. result = GetVersionEx((LPOSVERSIONINFO) (&(pSystemInfo->OsVersionEx)));
  1399. if (!result) {
  1400. //
  1401. // GetVersionEx sets the LastError
  1402. //
  1403. return FALSE;
  1404. }
  1405. //
  1406. // Get the boot directory
  1407. //
  1408. pSystemInfo->BootDirectory = HeapAlloc(heapHandle,
  1409. HEAP_ZERO_MEMORY,
  1410. (MAX_PATH+1)*sizeof(WCHAR)
  1411. );
  1412. if (!(pSystemInfo->BootDirectory)) {
  1413. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1414. return FALSE;
  1415. }
  1416. cchBootDirectory = GetSystemWindowsDirectoryW(pSystemInfo->BootDirectory,
  1417. MAX_PATH + 1
  1418. );
  1419. if (0 == cchBootDirectory) {
  1420. //
  1421. // GetSystemWindowsDirectoryW sets LastError
  1422. //
  1423. return FALSE;
  1424. }
  1425. if (cchBootDirectory >
  1426. ASR_SIF_ENTRY_MAX_CHARS - MAX_COMPUTERNAME_LENGTH - 26) {
  1427. //
  1428. // We can't write out sif lines that are more than
  1429. // ASR_SIF_ENTRY_MAX_CHARS chars long
  1430. //
  1431. SetLastError(ERROR_BAD_ENVIRONMENT);
  1432. return FALSE;
  1433. }
  1434. if (cchBootDirectory > MAX_PATH) {
  1435. UINT cchNewSize = cchBootDirectory + 1;
  1436. //
  1437. // Our buffer wasn't big enough, free and re-alloc as needed
  1438. //
  1439. _AsrpHeapFree(pSystemInfo->BootDirectory);
  1440. pSystemInfo->BootDirectory = HeapAlloc(heapHandle,
  1441. HEAP_ZERO_MEMORY,
  1442. (cchNewSize + 1) * sizeof(WCHAR)
  1443. );
  1444. if (!(pSystemInfo->BootDirectory)) {
  1445. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1446. return FALSE;
  1447. }
  1448. cchBootDirectory = GetSystemWindowsDirectoryW(pSystemInfo->BootDirectory,
  1449. MAX_PATH + 1
  1450. );
  1451. if (!cchBootDirectory) {
  1452. //
  1453. // GetSystemWindowsDirectoryW sets LastError
  1454. //
  1455. return FALSE;
  1456. }
  1457. if (cchBootDirectory > cchNewSize) {
  1458. SetLastError(ERROR_BAD_ENVIRONMENT);
  1459. return FALSE;
  1460. }
  1461. }
  1462. //
  1463. // Get the system directory
  1464. //
  1465. if (!AsrpGetSystemPath(pSystemInfo)) {
  1466. //
  1467. // AsrpGetSystemPath sets LastError
  1468. //
  1469. return FALSE;
  1470. }
  1471. //
  1472. // Get the time-zone information. We need to save and restore this since
  1473. // GUI-mode Setup (ASR) will otherwise default to GMT, and the file-time
  1474. // stamps on all the restored files will be off, since most back-up apps
  1475. // assume that they're restoring in the same time-zone that they backed
  1476. // up in and do nothing special to restore the time-zone first.
  1477. //
  1478. GetTimeZoneInformation(&(pSystemInfo->TimeZoneInformation));
  1479. return TRUE;
  1480. }
  1481. BOOL
  1482. AsrpInitLayoutInformation(
  1483. IN CONST PASR_SYSTEM_INFO pSystemInfo,
  1484. IN OUT PASR_DISK_INFO pDiskList,
  1485. OUT PULONG MaxDeviceNumber OPTIONAL,
  1486. IN BOOL AllDetailsForLocalDisks,
  1487. IN BOOL AllDetailsForOfflineClusteredDisks
  1488. )
  1489. /*++
  1490. Routine Description:
  1491. Initialisation routine to fill in layout and other interesting information
  1492. about the disks on the system.
  1493. Arguments:
  1494. pSystemInfo - the ASR_SYSTEM_INFO for the current system
  1495. pDiskList - ASR_DISK_INFO list of disks on the current system, with
  1496. the DevicePath field for each disk pointing to a null terminated
  1497. path to the disk, that can be used to open a handle to the disk.
  1498. The other fields of the structure are filled in by this routine,
  1499. if the disk could be accessed and the appropriate info could be
  1500. obtained.
  1501. MaxDeviceNumber - Receives the max device number of all the disks on the
  1502. system. This can be used as an optimisation to allocate memory
  1503. for a table of disks based on the device number.
  1504. This is an optional argument.
  1505. AllDetailsForLocalDisks - If FALSE, only the pDriveLayout information is
  1506. filled in for each disk. This is an optimisation that comes in
  1507. handy when we're dealing with disks on a shared cluster bus.
  1508. If TRUE, all the fields are filled in for each "local" disk,
  1509. which includes all unshared disks and shared clustered disks
  1510. owned by this node.
  1511. AllDetailsForOfflineClusteredDisks - If FALSE, only the pDriveLayout
  1512. information is filled in for each disk.
  1513. If TRUE, all the fields are filled in for each disk, and any
  1514. errors encountered are treated as failures (even if the
  1515. disk is a shared disk that is offline on this node).
  1516. Return Value:
  1517. If the function succeeds, the return value is a nonzero value.
  1518. If the function fails, the return value is zero. To get extended error
  1519. information, call GetLastError().
  1520. --*/
  1521. {
  1522. BOOL result = FALSE;
  1523. HANDLE hDisk = NULL;
  1524. PASR_DISK_INFO currentDisk = pDiskList;
  1525. BOOL getAllDetails = FALSE;
  1526. if (ARGUMENT_PRESENT(MaxDeviceNumber)) {
  1527. *MaxDeviceNumber = 0;
  1528. }
  1529. while (currentDisk) {
  1530. //
  1531. // Open the disk. If an error occurs, get the next
  1532. // disk from the disk list and continue.
  1533. //
  1534. hDisk = CreateFileW(
  1535. currentDisk->DevicePath, // lpFileName
  1536. 0, // dwDesiredAccess
  1537. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  1538. NULL, // lpSecurityAttributes
  1539. OPEN_EXISTING, // dwCreationFlags
  1540. FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
  1541. NULL // hTemplateFile
  1542. );
  1543. if ((!hDisk) || (INVALID_HANDLE_VALUE == hDisk)) {
  1544. //
  1545. // We couldn't open the disk. If this is a critical disk, we'll
  1546. // fail later in AsrpMarkCriticalDisks, so it's okay to ignore
  1547. // this error for now.
  1548. //
  1549. currentDisk = currentDisk->pNext;
  1550. continue;
  1551. }
  1552. //
  1553. // Set getAllDetails to the appropriate flag, based on whether this
  1554. // is a clustered disk that's offline, or a local disk. Note that
  1555. // this routine will open (and close) another handle to the disk,
  1556. // since the ioctl it uses to figure this out needs FILE_WRITE_ACCESS
  1557. // (and our handle above is opened with 0 access, which suffices for
  1558. // the rest of the IOCTL's).
  1559. //
  1560. if (AsrpIsOfflineClusteredDisk(hDisk)) {
  1561. getAllDetails = AllDetailsForOfflineClusteredDisks;
  1562. }
  1563. else {
  1564. getAllDetails = AllDetailsForLocalDisks;
  1565. }
  1566. //
  1567. // Get the layout and other interesting info for this disk.
  1568. // If this fails, we must abort.
  1569. //
  1570. result = AsrpGetDiskLayout(hDisk,
  1571. pSystemInfo,
  1572. currentDisk,
  1573. getAllDetails
  1574. );
  1575. if (!result) {
  1576. DWORD status = GetLastError();
  1577. _AsrpCloseHandle(hDisk); // this may change LastError.
  1578. SetLastError(status);
  1579. return FALSE;
  1580. }
  1581. _AsrpCloseHandle(hDisk);
  1582. //
  1583. // Set the max device number if needed
  1584. //
  1585. if (ARGUMENT_PRESENT(MaxDeviceNumber) &&
  1586. (currentDisk->DeviceNumber > *MaxDeviceNumber)
  1587. ) {
  1588. *MaxDeviceNumber = currentDisk->DeviceNumber;
  1589. }
  1590. //
  1591. // Get the next drive from the drive list.
  1592. //
  1593. currentDisk = currentDisk->pNext;
  1594. }
  1595. return TRUE;
  1596. }
  1597. BOOL
  1598. AsrpInitDiskInformation(
  1599. OUT PASR_DISK_INFO *ppDiskList
  1600. )
  1601. /*++
  1602. Routine Description:
  1603. Initialisation routine to get a list of disks present on the system. This
  1604. routine allocates a ASR_DISK_INFO struct for each disk on the machine, and
  1605. fills in the DevicePath and ParentDevInst fields of each with a path to
  1606. the disk. It is expected that the other fields will be filled in with a
  1607. subsequent call to AsrpInitLayoutInformation().
  1608. Arguments:
  1609. ppDiskList - Receives the location of the first ASR_DISK_INFO struct.
  1610. Return Value:
  1611. If the function succeeds, the return value is a nonzero value.
  1612. If the function fails, the return value is zero. To get extended error
  1613. information, call GetLastError(). ppDiskList may point to an
  1614. incomplete list of disks on the system, and it is the caller's
  1615. responsibility to free the memory allocated, if any, using
  1616. HeapFree(GetProcessHeap(),...).
  1617. --*/
  1618. {
  1619. DWORD count = 0,
  1620. status = ERROR_SUCCESS;
  1621. HDEVINFO hdevInfo = NULL;
  1622. BOOL result = FALSE;
  1623. PASR_DISK_INFO pNewDisk = NULL;
  1624. HANDLE heapHandle = NULL;
  1625. PSP_DEVICE_INTERFACE_DETAIL_DATA_W pDiDetail = NULL;
  1626. SP_DEVICE_INTERFACE_DATA devInterfaceData;
  1627. DWORD sizeDiDetail = 0;
  1628. SP_DEVINFO_DATA devInfoData;
  1629. //
  1630. // Initialise stuff to zeros
  1631. //
  1632. memset(&devInterfaceData, 0, sizeof(SP_DEVICE_INTERFACE_DATA));
  1633. *ppDiskList = NULL;
  1634. heapHandle = GetProcessHeap(); // used for HeapAlloc functions
  1635. MYASSERT(heapHandle);
  1636. //
  1637. // Get a device interface set which includes all Disk devices
  1638. // present on the machine. DiskClassGuid is a predefined GUID that
  1639. // will return all disk-type device interfaces
  1640. //
  1641. hdevInfo = SetupDiGetClassDevsW(
  1642. &DiskClassGuid,
  1643. NULL,
  1644. NULL,
  1645. DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
  1646. );
  1647. _AsrpErrExitCode(
  1648. ((NULL == hdevInfo) || (INVALID_HANDLE_VALUE == hdevInfo)),
  1649. status,
  1650. ERROR_IO_DEVICE
  1651. );
  1652. //
  1653. // Iterate over all devices interfaces in the set
  1654. //
  1655. for (count = 0; ; count++) {
  1656. // must set size first
  1657. devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  1658. //
  1659. // Retrieve the device interface data for each device interface
  1660. //
  1661. result = SetupDiEnumDeviceInterfaces(
  1662. hdevInfo,
  1663. NULL,
  1664. &DiskClassGuid,
  1665. count,
  1666. &devInterfaceData
  1667. );
  1668. if (!result) {
  1669. //
  1670. // If we retrieved the last item, break
  1671. //
  1672. status = GetLastError();
  1673. if (ERROR_NO_MORE_ITEMS == status) {
  1674. status = ERROR_SUCCESS;
  1675. break;
  1676. }
  1677. else {
  1678. //
  1679. // Some other error occured, goto EXIT. We overwrite the
  1680. // last error.
  1681. //
  1682. _AsrpErrExitCode(status, status, ERROR_IO_DEVICE);
  1683. }
  1684. }
  1685. //
  1686. // Get the required buffer-size for the device path
  1687. //
  1688. result = SetupDiGetDeviceInterfaceDetailW(
  1689. hdevInfo,
  1690. &devInterfaceData,
  1691. NULL,
  1692. 0,
  1693. &sizeDiDetail,
  1694. NULL
  1695. );
  1696. if (!result) {
  1697. status = GetLastError();
  1698. //
  1699. // If a value other than "insufficient buffer" is returned,
  1700. // an error occured
  1701. //
  1702. _AsrpErrExitCode((ERROR_INSUFFICIENT_BUFFER != status),
  1703. status,
  1704. ERROR_IO_DEVICE
  1705. );
  1706. }
  1707. else {
  1708. //
  1709. // The call should have failed since we're getting the
  1710. // required buffer size. If it doesn't, and error occurred.
  1711. //
  1712. _AsrpErrExitCode(status, status, ERROR_IO_DEVICE);
  1713. }
  1714. //
  1715. // Allocate memory for the buffer
  1716. //
  1717. pDiDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W) HeapAlloc(
  1718. heapHandle,
  1719. HEAP_ZERO_MEMORY,
  1720. sizeDiDetail
  1721. );
  1722. _AsrpErrExitCode(!pDiDetail, status, ERROR_NOT_ENOUGH_MEMORY);
  1723. // must set the struct's size member
  1724. pDiDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
  1725. devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1726. //
  1727. // Finally, retrieve the device interface detail info
  1728. //
  1729. result = SetupDiGetDeviceInterfaceDetailW(
  1730. hdevInfo,
  1731. &devInterfaceData,
  1732. pDiDetail,
  1733. sizeDiDetail,
  1734. NULL,
  1735. &devInfoData
  1736. );
  1737. _AsrpErrExitCode(!result, status, GetLastError());
  1738. //
  1739. // Okay, now alloc a struct for this disk, and fill in the DevicePath
  1740. // field with the Path from the interface detail.
  1741. //
  1742. pNewDisk = (PASR_DISK_INFO) HeapAlloc(
  1743. heapHandle,
  1744. HEAP_ZERO_MEMORY,
  1745. sizeof(ASR_DISK_INFO)
  1746. );
  1747. _AsrpErrExitCode(!pNewDisk, status, ERROR_NOT_ENOUGH_MEMORY);
  1748. //
  1749. // Insert at the head so this is O(1) and not O(n!)
  1750. //
  1751. pNewDisk->pNext = *ppDiskList;
  1752. *ppDiskList = pNewDisk;
  1753. pNewDisk->DevicePath = (PWSTR) HeapAlloc(
  1754. heapHandle,
  1755. HEAP_ZERO_MEMORY,
  1756. sizeof(WCHAR) * (wcslen(pDiDetail->DevicePath) + 1)
  1757. );
  1758. _AsrpErrExitCode(!(pNewDisk->DevicePath),
  1759. status,
  1760. ERROR_NOT_ENOUGH_MEMORY
  1761. );
  1762. wcscpy(pNewDisk->DevicePath, pDiDetail->DevicePath);
  1763. //
  1764. // Get the PnP parent of this disk, so we can use it for grouping
  1765. // disks later based on the bus they are on.
  1766. //
  1767. CM_Get_Parent(&(pNewDisk->ParentDevInst),
  1768. devInfoData.DevInst,
  1769. 0
  1770. );
  1771. _AsrpHeapFree(pDiDetail);
  1772. }
  1773. EXIT:
  1774. //
  1775. // Free local mem allocs
  1776. //
  1777. _AsrpHeapFree(pDiDetail);
  1778. if ((hdevInfo) && (INVALID_HANDLE_VALUE != hdevInfo)) {
  1779. SetupDiDestroyDeviceInfoList(hdevInfo);
  1780. hdevInfo = NULL;
  1781. }
  1782. return (BOOL) (status == ERROR_SUCCESS);
  1783. }
  1784. BOOL
  1785. AsrpMarkCriticalDisks(
  1786. IN PASR_DISK_INFO pDiskList,
  1787. IN PCWSTR CriticalVolumeList,
  1788. IN ULONG MaxDeviceNumber
  1789. )
  1790. /*++
  1791. Routine Description:
  1792. Sets the IsCritical flag of each of the critical disks on the system. A
  1793. disk is deemed "critical" if it is part of part of the failover set for
  1794. any of the critical volumes present on the system.
  1795. Arguments:
  1796. pDiskList - The list of disks on the current system.
  1797. CriticalVolumeList - A multi-string containing a list of the volume GUID's
  1798. of each of the critical volumes present on the system. The GUID's
  1799. must be in the NT name-space, i.e., must be of the form:
  1800. \??\Volume{GUID}
  1801. MaxDeviceNumber - The highest storage device number of the disks present
  1802. in the disk list, as determined by calling
  1803. IOCTL_STORAGE_GET_DEVICE_NUMBER for each of them.
  1804. Return Value:
  1805. If the function succeeds, the return value is a nonzero value.
  1806. If the function fails, the return value is zero. To get extended error
  1807. information, call GetLastError().
  1808. --*/
  1809. {
  1810. PCWSTR volGuid = NULL;
  1811. PASR_DISK_INFO currentDisk = NULL;
  1812. PVOLUME_FAILOVER_SET failoverSet = NULL;
  1813. DWORD index = 0,
  1814. reqdSize=0,
  1815. sizeFailoverSet = 0,
  1816. status = ERROR_SUCCESS;
  1817. BOOL result = TRUE,
  1818. *criticalDiskTable = NULL;
  1819. WCHAR devicePath[ASR_CCH_DEVICE_PATH_FORMAT + 1];
  1820. HANDLE heapHandle = NULL,
  1821. hDevice = NULL;
  1822. memset(devicePath, 0L, (ASR_CCH_DEVICE_PATH_FORMAT+1)*sizeof(WCHAR));
  1823. if (!CriticalVolumeList) {
  1824. //
  1825. // No critical volumes:
  1826. //
  1827. #ifdef PRERELEASE
  1828. return TRUE;
  1829. #else
  1830. return FALSE;
  1831. #endif
  1832. }
  1833. if (!pDiskList) {
  1834. //
  1835. // No disks on machine?!
  1836. //
  1837. MYASSERT(0 && L"DiskList is NULL");
  1838. return FALSE;
  1839. }
  1840. heapHandle = GetProcessHeap();
  1841. MYASSERT(heapHandle);
  1842. //
  1843. // criticalDiskTable is our table of BOOL values.
  1844. //
  1845. criticalDiskTable = (BOOL *) HeapAlloc(
  1846. heapHandle,
  1847. HEAP_ZERO_MEMORY,
  1848. sizeof (BOOL) * (MaxDeviceNumber + 1)
  1849. );
  1850. _AsrpErrExitCode(!criticalDiskTable, status, ERROR_NOT_ENOUGH_MEMORY);
  1851. //
  1852. // Try with a reasonable sized buffer first--say 10 disks. We'll
  1853. // realloc as needed if this isn't enough.
  1854. //
  1855. sizeFailoverSet = sizeof(VOLUME_FAILOVER_SET) + (10 * sizeof(ULONG));
  1856. failoverSet = (PVOLUME_FAILOVER_SET) HeapAlloc(
  1857. heapHandle,
  1858. HEAP_ZERO_MEMORY,
  1859. sizeFailoverSet
  1860. );
  1861. _AsrpErrExitCode(!failoverSet, status, ERROR_NOT_ENOUGH_MEMORY);
  1862. volGuid = CriticalVolumeList;
  1863. while (*volGuid) {
  1864. //
  1865. // Convert the \??\ to \\?\ so that CreateFile can use it
  1866. //
  1867. wcsncpy(devicePath, volGuid, ASR_CCH_DEVICE_PATH_FORMAT);
  1868. devicePath[1] = L'\\';
  1869. //
  1870. // Get a handle so we can send the ioctl
  1871. //
  1872. hDevice = CreateFileW(
  1873. devicePath, // lpFileName
  1874. 0, // dwDesiredAccess
  1875. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  1876. NULL, // lpSecurityAttributes
  1877. OPEN_EXISTING, // dwCreationFlags
  1878. 0, // dwFlagsAndAttributes
  1879. NULL // hTemplateFile
  1880. );
  1881. _AsrpErrExitCode(((!hDevice) || (INVALID_HANDLE_VALUE == hDevice)),
  1882. status,
  1883. GetLastError());
  1884. result = DeviceIoControl(
  1885. hDevice,
  1886. IOCTL_VOLUME_QUERY_FAILOVER_SET,
  1887. NULL,
  1888. 0,
  1889. failoverSet,
  1890. sizeFailoverSet,
  1891. &reqdSize,
  1892. NULL
  1893. );
  1894. //
  1895. // We're doing this in a while loop because if the disk configuration
  1896. // changes in the small interval between when we get the reqd buffer
  1897. // size and when we send the ioctl again with a buffer of the "reqd"
  1898. // size, we may still end up with a buffer that isn't big enough.
  1899. //
  1900. while (!result) {
  1901. status = GetLastError();
  1902. if (ERROR_MORE_DATA == status) {
  1903. //
  1904. // The buffer was too small, reallocate the reqd size.
  1905. //
  1906. status = ERROR_SUCCESS;
  1907. sizeFailoverSet = (sizeof(VOLUME_FAILOVER_SET) +
  1908. ((failoverSet->NumberOfDisks) * sizeof(ULONG)));
  1909. _AsrpHeapFree(failoverSet);
  1910. failoverSet = (PVOLUME_FAILOVER_SET) HeapAlloc(
  1911. heapHandle,
  1912. HEAP_ZERO_MEMORY,
  1913. sizeFailoverSet
  1914. );
  1915. _AsrpErrExitCode(!failoverSet,
  1916. status,
  1917. ERROR_NOT_ENOUGH_MEMORY
  1918. );
  1919. result = DeviceIoControl(
  1920. hDevice,
  1921. IOCTL_VOLUME_QUERY_FAILOVER_SET,
  1922. NULL,
  1923. 0,
  1924. failoverSet,
  1925. sizeFailoverSet,
  1926. &reqdSize,
  1927. NULL
  1928. );
  1929. }
  1930. else {
  1931. //
  1932. // The IOCTL failed because of something else, this is
  1933. // fatal since we can't find the critical disk list now.
  1934. //
  1935. _AsrpErrExitCode((TRUE), status, status);
  1936. }
  1937. }
  1938. //
  1939. // Mark the appropriate entries in our table
  1940. //
  1941. for (index = 0; index < failoverSet->NumberOfDisks; index++) {
  1942. criticalDiskTable[failoverSet->DiskNumbers[index]] = 1;
  1943. }
  1944. _AsrpCloseHandle(hDevice);
  1945. //
  1946. // Repeat for next volumeguid in list
  1947. //
  1948. volGuid += (wcslen(CriticalVolumeList) + 1);
  1949. }
  1950. //
  1951. // Now go through the list of disks, and mark the critical flags.
  1952. //
  1953. currentDisk = pDiskList;
  1954. while (currentDisk) {
  1955. if (currentDisk->IsClusterShared) {
  1956. //
  1957. // By definition, cluster shared disks cannot be critical.
  1958. //
  1959. currentDisk = currentDisk->pNext;
  1960. continue;
  1961. }
  1962. currentDisk->IsCritical =
  1963. (criticalDiskTable[currentDisk->DeviceNumber] ? TRUE : FALSE);
  1964. //
  1965. // Increment the entry, so that we can track how many critical volumes
  1966. // reside on this disk, and--more importantly--ensure that all the
  1967. // critical disks exist on the system (next loop below)
  1968. //
  1969. if (currentDisk->IsCritical) {
  1970. ++(criticalDiskTable[currentDisk->DeviceNumber]);
  1971. }
  1972. currentDisk = currentDisk->pNext;
  1973. }
  1974. //
  1975. // Finally, we want to make sure that we don't have any critical disks
  1976. // in our table that we didn't find physical disks for. (I.e., make
  1977. // sure that the system has no "missing" critical disks)
  1978. //
  1979. for (index = 0; index < MaxDeviceNumber; index++) {
  1980. if (1 == criticalDiskTable[index]) {
  1981. //
  1982. // If the table still has "1" for the value, it was never
  1983. // incremented in the while loop above, ie our diskList doesn't
  1984. // have a disk corresponding to this.
  1985. //
  1986. _AsrpErrExitCode(TRUE, status, ERROR_DEV_NOT_EXIST);
  1987. }
  1988. }
  1989. EXIT:
  1990. _AsrpHeapFree(failoverSet);
  1991. _AsrpHeapFree(criticalDiskTable);
  1992. _AsrpCloseHandle(hDevice);
  1993. return (BOOL)(ERROR_SUCCESS == status);
  1994. }
  1995. PASR_DISK_INFO
  1996. AsrpFreeDiskInfo(
  1997. PASR_DISK_INFO pCurrentDisk
  1998. )
  1999. /*++
  2000. Routine Description:
  2001. Helper function to free memory pointed to by various pointers in the
  2002. ASR_DISK_INFO struct, and then free the struct itself.
  2003. Arguments:
  2004. pCurrentDisk - the struct to be freed
  2005. Return Value:
  2006. pCurrentDisk->Next, which is a pointer to the next disk in the list
  2007. --*/
  2008. {
  2009. HANDLE heapHandle = NULL;
  2010. PASR_DISK_INFO pNext = NULL;
  2011. heapHandle = GetProcessHeap();
  2012. MYASSERT(heapHandle);
  2013. if (pCurrentDisk) {
  2014. pNext = pCurrentDisk->pNext;
  2015. //
  2016. // If it's a packed struct, then we only need to free the struct
  2017. // itself. If not, we need to free the memory the pointers point
  2018. // to as well.
  2019. //
  2020. if (!pCurrentDisk->IsPacked) {
  2021. _AsrpHeapFree(pCurrentDisk->DevicePath);
  2022. _AsrpHeapFree(pCurrentDisk->pDriveLayoutEx);
  2023. _AsrpHeapFree(pCurrentDisk->pDiskGeometry);
  2024. _AsrpHeapFree(pCurrentDisk->pPartition0Ex);
  2025. _AsrpHeapFree(pCurrentDisk->pScsiAddress);
  2026. _AsrpHeapFree(pCurrentDisk->PartitionInfoTable);
  2027. }
  2028. _AsrpHeapFree(pCurrentDisk);
  2029. }
  2030. return pNext;
  2031. }
  2032. BOOL
  2033. AsrpIsRemovableOrInaccesibleMedia(
  2034. IN PASR_DISK_INFO pDisk
  2035. )
  2036. /*++
  2037. Routine Description:
  2038. Checks if the disk represented by pDisk should be removed from our list
  2039. of disks that we'll store information on in the state file.
  2040. Disks that should be removed include disks that are removable, or disks
  2041. that we couldn't access.
  2042. Arguments:
  2043. pDisk - the disk structure to be checked
  2044. Return Value:
  2045. TRUE if the device is removable, or some key information about the disk is
  2046. missing. Since code depends on the driveLayout being non-NULL,
  2047. for instance, we shall just remove the disk from the list if we
  2048. couldn't get it's drive layout. We shall therefore not backup
  2049. information about any disk whose drive geo or layout we couldn't
  2050. get, and not restore to any such disk.
  2051. FALSE if the structure contains all the required information, and is not
  2052. a removable device.
  2053. --*/
  2054. {
  2055. if ((NULL == pDisk->pDiskGeometry) ||
  2056. (NULL == pDisk->pDriveLayoutEx) ||
  2057. (NULL == pDisk->pPartition0Ex) ||
  2058. (FixedMedia != pDisk->pDiskGeometry->MediaType)
  2059. ) {
  2060. return TRUE;
  2061. }
  2062. if (AsrpIsInaccessibleSanDisk(pDisk->DeviceNumber) && (!pDisk->IsClusterShared)) {
  2063. return TRUE;
  2064. }
  2065. return FALSE;
  2066. }
  2067. BOOL
  2068. AsrpFreeNonFixedMedia(
  2069. IN OUT PASR_DISK_INFO *ppDiskList
  2070. )
  2071. /*++
  2072. Routine Description:
  2073. Removes removable media, and disks that are inaccessible, from the list of
  2074. disks passed in.
  2075. Arguments:
  2076. ppDiskList - a pointer to the address of the first disk in the list of all
  2077. the disks present on the current system.
  2078. Return Value:
  2079. If the function succeeds, the return value is a nonzero value.
  2080. If the function fails, the return value is zero. To get extended error
  2081. information, call GetLastError().
  2082. Currently, this function always succeeds.
  2083. --*/
  2084. {
  2085. PASR_DISK_INFO prevDisk = NULL,
  2086. currentDisk = *ppDiskList;
  2087. while (currentDisk) {
  2088. if (AsrpIsRemovableOrInaccesibleMedia(currentDisk)) {
  2089. //
  2090. // Disk is not Fixed, we should remove it from out list
  2091. //
  2092. if (NULL == prevDisk) { // this is the first disk in the list
  2093. *ppDiskList = currentDisk->pNext;
  2094. }
  2095. else {
  2096. prevDisk->pNext = currentDisk->pNext;
  2097. }
  2098. //
  2099. // Free it and get a pointer to the next disk
  2100. //
  2101. currentDisk = AsrpFreeDiskInfo(currentDisk);
  2102. }
  2103. else {
  2104. //
  2105. // Disk is okay, move on to the next disk
  2106. //
  2107. prevDisk = currentDisk;
  2108. currentDisk = currentDisk->pNext;
  2109. }
  2110. }
  2111. return TRUE;
  2112. }
  2113. VOID
  2114. AsrpFreeStateInformation(
  2115. IN OUT PASR_DISK_INFO *ppDiskList OPTIONAL,
  2116. IN OUT PASR_SYSTEM_INFO pSystemInfo OPTIONAL
  2117. )
  2118. /*++
  2119. Routine Description:
  2120. Frees the memory addressed by pointers in the ASR_DISK_INFO and
  2121. ASR_SYSTEM_INFO structs.
  2122. Frees the list of disks pointed to by the ASR_DISK_INFO struct.
  2123. Arguments:
  2124. ppDiskList - Pointer to the address of the first Disk in the DiskList
  2125. being freed. The address is set to NULL after the list is freed,
  2126. to prevent further unintended accesses to the freed object.
  2127. pSystemInfo - A pointer to the ASR_SYSTEM_INFO struct, containing the
  2128. pointers to be freed.
  2129. Return Value:
  2130. If the function succeeds, the return value is a nonzero value.
  2131. *ppDiskList is set to NULL.
  2132. If the function fails, the return value is zero. To get extended error
  2133. information, call GetLastError().
  2134. Currently, this function always succeeds.
  2135. --*/
  2136. {
  2137. PASR_DISK_INFO pTempDisk = NULL;
  2138. HANDLE heapHandle = GetProcessHeap();
  2139. MYASSERT(heapHandle);
  2140. if (ARGUMENT_PRESENT(ppDiskList)) {
  2141. pTempDisk = *ppDiskList;
  2142. while (pTempDisk) {
  2143. pTempDisk = AsrpFreeDiskInfo(pTempDisk);
  2144. }
  2145. *ppDiskList = NULL;
  2146. }
  2147. if (ARGUMENT_PRESENT(pSystemInfo)) {
  2148. _AsrpHeapFree(pSystemInfo->SystemPath);
  2149. _AsrpHeapFree(pSystemInfo->BootDirectory);
  2150. }
  2151. }
  2152. VOID
  2153. AsrpFreePartitionList(
  2154. IN OUT PASR_PTN_INFO_LIST *ppPtnList OPTIONAL
  2155. )
  2156. /*++
  2157. Routine Description:
  2158. Frees the list of partitions, along with memory addressed by all the
  2159. pointers in the list.
  2160. Arguments:
  2161. ppPtnList - Pointer to the address of the first partition in the list
  2162. being freed. The address is set to NULL after the list is freed,
  2163. to prevent further unintended accesses to the freed object.
  2164. Return Value:
  2165. If the function succeeds, the return value is a nonzero value.
  2166. *ppPtnList is set to NULL.
  2167. If the function fails, the return value is zero. To get extended error
  2168. information, call GetLastError().
  2169. Currently, this function always succeeds.
  2170. --*/
  2171. {
  2172. DWORD index = 0,
  2173. numberOfPartitions = 0;
  2174. PASR_PTN_INFO_LIST pList = NULL;
  2175. PASR_PTN_INFO pCurrent = NULL,
  2176. pNext = NULL;
  2177. HANDLE heapHandle = GetProcessHeap();
  2178. if (!ARGUMENT_PRESENT(ppPtnList) || !(*ppPtnList)) {
  2179. return;
  2180. }
  2181. pList = *ppPtnList;
  2182. numberOfPartitions = pList[0].numTotalPtns;
  2183. for (index = 0; index < numberOfPartitions; index++) {
  2184. pCurrent = pList[index].pOffsetHead;
  2185. while (pCurrent) {
  2186. //
  2187. // Save a pointer to the next
  2188. //
  2189. pNext = pCurrent->pOffsetNext;
  2190. //
  2191. // No pointers in PASR_PTN_INFO, okay to free as-is.
  2192. //
  2193. _AsrpHeapFree(pCurrent);
  2194. pCurrent = pNext;
  2195. }
  2196. }
  2197. _AsrpHeapFree(pList);
  2198. *ppPtnList = NULL;
  2199. }
  2200. BOOL
  2201. AsrpWriteVersionSection(
  2202. IN CONST HANDLE SifHandle,
  2203. IN PCWSTR Provider OPTIONAL
  2204. )
  2205. /*++
  2206. Routine Description:
  2207. Creates the VERSION section of the ASR state file, and writes out the
  2208. entries in that section to file.
  2209. Arguments:
  2210. SifHandle - Handle to asr.sif, the ASR state file.
  2211. Provider - Pointer to a null-terminated string containing the name of the
  2212. application creating the asr.sif. The length of this string must
  2213. not exceed (ASR_SIF_ENTRY_MAX_CHARS - ASR_SIF_CCH_PROVIDER_STRING)
  2214. characters.
  2215. This is an optional argument.
  2216. Return Value:
  2217. If the function succeeds, the return value is a nonzero value.
  2218. If the function fails, the return value is zero. To get extended error
  2219. information, call GetLastError().
  2220. --*/
  2221. {
  2222. WCHAR infstring[ASR_SIF_ENTRY_MAX_CHARS + 1];
  2223. DWORD size;
  2224. //
  2225. // Write out the section name
  2226. //
  2227. swprintf(infstring, L"\r\n%ws\r\n", ASR_SIF_VERSION_SECTION_NAME);
  2228. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2229. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2230. //
  2231. // Section Entries
  2232. //
  2233. wcscpy(infstring, L"Signature=\"$Windows NT$\"\r\n");
  2234. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2235. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2236. wcscpy(infstring, L"ASR-Version=\"1.0\"\r\n");
  2237. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2238. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2239. if (ARGUMENT_PRESENT(Provider)) {
  2240. if (wcslen(Provider) >
  2241. (ASR_SIF_ENTRY_MAX_CHARS - ASR_SIF_CCH_PROVIDER_STRING)
  2242. ) {
  2243. //
  2244. // This string is too long to fit into one line in asr.sif
  2245. //
  2246. SetLastError(ERROR_INVALID_PARAMETER);
  2247. return FALSE;
  2248. }
  2249. swprintf(infstring, L"%ws\"%.*ws\"\r\n",
  2250. ASR_SIF_PROVIDER_PREFIX,
  2251. (ASR_SIF_ENTRY_MAX_CHARS - ASR_SIF_CCH_PROVIDER_STRING),
  2252. Provider
  2253. );
  2254. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2255. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2256. }
  2257. return TRUE;
  2258. }
  2259. BOOL
  2260. AsrpWriteSystemsSection(
  2261. IN CONST HANDLE SifHandle,
  2262. IN CONST PASR_SYSTEM_INFO pSystemInfo
  2263. )
  2264. /*++
  2265. Routine Description:
  2266. Creates the SYSTEMS section of the ASR state file, and writes out the
  2267. entries in that section to file.
  2268. Arguments:
  2269. SifHandle - Handle to asr.sif, the ASR state file.
  2270. pSystemInfo - Pointer to information about the current system.
  2271. Return Value:
  2272. If the function succeeds, the return value is a nonzero value.
  2273. If the function fails, the return value is zero. To get extended error
  2274. information, call GetLastError().
  2275. --*/
  2276. {
  2277. WCHAR infstring[ASR_SIF_ENTRY_MAX_CHARS + 1];
  2278. DWORD size = 0, SKU = 0;
  2279. if ((!pSystemInfo) || (!pSystemInfo->BootDirectory)) {
  2280. //
  2281. // We need a boot directory
  2282. //
  2283. SetLastError(ERROR_BAD_ENVIRONMENT);
  2284. return FALSE;
  2285. }
  2286. //
  2287. // Write out the section name
  2288. //
  2289. swprintf(infstring, L"\r\n%ws\r\n", ASR_SIF_SYSTEM_SECTION_NAME);
  2290. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2291. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2292. SKU = (DWORD) (pSystemInfo->OsVersionEx.wProductType);
  2293. SKU = SKU << 16; // shift the ProductType left 2 bytes
  2294. SKU = SKU | (DWORD) (pSystemInfo->OsVersionEx.wSuiteMask);
  2295. //
  2296. // Create the section entry, and write it out to file.
  2297. //
  2298. swprintf(infstring,
  2299. L"1=\"%ws\",\"%ws\",\"%d.%d\",\"%ws\",%d,0x%08x,\"%ld %ld %ld %hd-%hd-%hd-%hd %hd:%02hd:%02hd.%hd %hd-%hd-%hd-%hd %hd:%02hd:%02hd.%hd\",\"%ws\",\"%ws\"\r\n",
  2300. pSystemInfo->ComputerName,
  2301. pSystemInfo->Platform,
  2302. pSystemInfo->OsVersionEx.dwMajorVersion,
  2303. pSystemInfo->OsVersionEx.dwMinorVersion,
  2304. pSystemInfo->BootDirectory,
  2305. ((pSystemInfo->AutoExtendEnabled) ? 1 : 0),
  2306. // Product SKU
  2307. SKU,
  2308. // Time-zone stuff
  2309. pSystemInfo->TimeZoneInformation.Bias,
  2310. pSystemInfo->TimeZoneInformation.StandardBias,
  2311. pSystemInfo->TimeZoneInformation.DaylightBias,
  2312. pSystemInfo->TimeZoneInformation.StandardDate.wYear,
  2313. pSystemInfo->TimeZoneInformation.StandardDate.wMonth,
  2314. pSystemInfo->TimeZoneInformation.StandardDate.wDayOfWeek,
  2315. pSystemInfo->TimeZoneInformation.StandardDate.wDay,
  2316. pSystemInfo->TimeZoneInformation.StandardDate.wHour,
  2317. pSystemInfo->TimeZoneInformation.StandardDate.wMinute,
  2318. pSystemInfo->TimeZoneInformation.StandardDate.wSecond,
  2319. pSystemInfo->TimeZoneInformation.StandardDate.wMilliseconds,
  2320. pSystemInfo->TimeZoneInformation.DaylightDate.wYear,
  2321. pSystemInfo->TimeZoneInformation.DaylightDate.wMonth,
  2322. pSystemInfo->TimeZoneInformation.DaylightDate.wDayOfWeek,
  2323. pSystemInfo->TimeZoneInformation.DaylightDate.wDay,
  2324. pSystemInfo->TimeZoneInformation.DaylightDate.wHour,
  2325. pSystemInfo->TimeZoneInformation.DaylightDate.wMinute,
  2326. pSystemInfo->TimeZoneInformation.DaylightDate.wSecond,
  2327. pSystemInfo->TimeZoneInformation.DaylightDate.wMilliseconds,
  2328. pSystemInfo->TimeZoneInformation.StandardName,
  2329. pSystemInfo->TimeZoneInformation.DaylightName
  2330. );
  2331. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2332. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2333. return TRUE;
  2334. }
  2335. BOOL
  2336. AsrpWriteBusesSection(
  2337. IN CONST HANDLE SifHandle,
  2338. IN CONST PASR_DISK_INFO pDiskList
  2339. )
  2340. /*++
  2341. Routine Description:
  2342. Creates the BUSES section of the ASR state file, and writes out the
  2343. entries in that section to file.
  2344. Arguments:
  2345. SifHandle - Handle to asr.sif, the ASR state file.
  2346. pDiskList - List of disks present on the current system.
  2347. Return Value:
  2348. If the function succeeds, the return value is a nonzero value.
  2349. If the function fails, the return value is zero. To get extended error
  2350. information, call GetLastError().
  2351. --*/
  2352. {
  2353. DWORD size = 0,
  2354. busKey = 1;
  2355. BOOL done = FALSE;
  2356. WCHAR infstring[ASR_SIF_ENTRY_MAX_CHARS + 1];
  2357. PASR_DISK_INFO pCurrentDisk = NULL;
  2358. //
  2359. // Write out the section name
  2360. //
  2361. swprintf(infstring, L"\r\n%ws\r\n", ASR_SIF_BUSES_SECTION_NAME);
  2362. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2363. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2364. //
  2365. // Create the list of buses. This routine fills in the SifBusKey field
  2366. // for each disk.
  2367. //
  2368. AsrpDetermineBuses(pDiskList);
  2369. //
  2370. // Go through the list of disks now, and add one entry in asr.sif for each
  2371. // bus present on the system (i.e., each unique SifBusKey value). Note
  2372. // that we won't care about disks for which we couldn't get any bus info--
  2373. // SifBusKey is 0 for such disks, and we start here from SifBusKey == 1.
  2374. //
  2375. // Also, we assume that SifBusKey values have no holes.
  2376. //
  2377. while (!done) {
  2378. done = TRUE; // assume that we've been through all the buses.
  2379. //
  2380. // Start from the beginning of the list
  2381. //
  2382. pCurrentDisk = pDiskList;
  2383. while (pCurrentDisk) {
  2384. if (pCurrentDisk->SifBusKey > busKey) {
  2385. //
  2386. // There are SifBusKeys we haven't covered yet.
  2387. //
  2388. done = FALSE;
  2389. }
  2390. if (pCurrentDisk->SifBusKey == busKey) {
  2391. //
  2392. // This is the SifBusKey we're looking for, so lets write
  2393. // out the bus type to file.
  2394. //
  2395. swprintf(infstring, L"%lu=%d,%lu\r\n",
  2396. busKey,
  2397. ASR_SYSTEM_KEY,
  2398. pCurrentDisk->BusType
  2399. );
  2400. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2401. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2402. //
  2403. // We've already covered this SifBusKey, lets move on to the
  2404. // next.
  2405. //
  2406. ++busKey;
  2407. }
  2408. pCurrentDisk = pCurrentDisk->pNext;
  2409. }
  2410. }
  2411. return TRUE;
  2412. }
  2413. BOOL
  2414. AsrpWriteMbrDisksSection(
  2415. IN CONST HANDLE SifHandle, // handle to the state file
  2416. IN CONST PASR_DISK_INFO pDiskList
  2417. )
  2418. /*++
  2419. Routine Description:
  2420. Creates the DISKS.MBR section of the ASR state file, and writes out the
  2421. entries in that section to file.
  2422. Arguments:
  2423. SifHandle - Handle to asr.sif, the ASR state file.
  2424. pDiskList - List of disks present on the current system.
  2425. Return Value:
  2426. If the function succeeds, the return value is a nonzero value.
  2427. If the function fails, the return value is zero. To get extended error
  2428. information, call GetLastError().
  2429. --*/
  2430. {
  2431. DWORD size = 0,
  2432. diskKey = 1;
  2433. WCHAR infstring[ASR_SIF_ENTRY_MAX_CHARS + 1];
  2434. PASR_DISK_INFO pCurrentDisk = pDiskList;
  2435. //
  2436. // Write out the section name: [DISKS.MBR]
  2437. //
  2438. swprintf(infstring, L"\r\n%ws\r\n", ASR_SIF_MBR_DISKS_SECTION_NAME);
  2439. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2440. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2441. //
  2442. // Go through the list of disks, and write one entry for each MBR disk
  2443. // on the list.
  2444. //
  2445. while (pCurrentDisk) {
  2446. if (PARTITION_STYLE_MBR !=
  2447. pCurrentDisk->pDriveLayoutEx->PartitionStyle
  2448. ) {
  2449. //
  2450. // Skip non-MBR (i.e., GPT) disks.
  2451. //
  2452. pCurrentDisk = pCurrentDisk->pNext;
  2453. continue;
  2454. }
  2455. pCurrentDisk->SifDiskKey = diskKey;
  2456. swprintf(infstring, L"%lu=%d,%lu,%lu,0x%08x,%lu,%lu,%lu,%I64u\r\n",
  2457. diskKey,
  2458. ASR_SYSTEM_KEY,
  2459. pCurrentDisk->SifBusKey,
  2460. pCurrentDisk->IsCritical,
  2461. pCurrentDisk->pDriveLayoutEx->Mbr.Signature,
  2462. pCurrentDisk->pDiskGeometry->BytesPerSector,
  2463. pCurrentDisk->pDiskGeometry->SectorsPerTrack,
  2464. pCurrentDisk->pDiskGeometry->TracksPerCylinder,
  2465. (ULONG64)(pCurrentDisk->pPartition0Ex->PartitionLength.QuadPart /
  2466. pCurrentDisk->pDiskGeometry->BytesPerSector)
  2467. );
  2468. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2469. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2470. ++diskKey;
  2471. pCurrentDisk = pCurrentDisk->pNext;
  2472. }
  2473. return TRUE;
  2474. }
  2475. BOOL
  2476. AsrpWriteGptDisksSection(
  2477. IN CONST HANDLE SifHandle, // handle to the state file
  2478. IN CONST PASR_DISK_INFO pDiskList
  2479. )
  2480. /*++
  2481. Routine Description:
  2482. Creates the DISKS.GPT section of the ASR state file, and writes out the
  2483. entries in that section to file.
  2484. Arguments:
  2485. SifHandle - Handle to asr.sif, the ASR state file.
  2486. pDiskList - List of disks present on the current system.
  2487. Return Value:
  2488. If the function succeeds, the return value is a nonzero value.
  2489. If the function fails, the return value is zero. To get extended error
  2490. information, call GetLastError().
  2491. --*/
  2492. {
  2493. DWORD size = 0,
  2494. diskKey = 1;
  2495. PWSTR lpGuidString = NULL;
  2496. RPC_STATUS rpcStatus = RPC_S_OK;
  2497. PASR_DISK_INFO pCurrentDisk = pDiskList;
  2498. WCHAR infstring[ASR_SIF_ENTRY_MAX_CHARS + 1];
  2499. //
  2500. // Write out the section name: [DISKS.GPT]
  2501. //
  2502. swprintf(infstring, L"\r\n%ws\r\n", ASR_SIF_GPT_DISKS_SECTION_NAME);
  2503. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2504. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2505. //
  2506. // Go through the list of disks, and write one entry for each GPT disk
  2507. // on the list.
  2508. //
  2509. while (pCurrentDisk) {
  2510. if (PARTITION_STYLE_GPT !=
  2511. pCurrentDisk->pDriveLayoutEx->PartitionStyle
  2512. ) {
  2513. //
  2514. // Skip non-GPT (i.e., MBR) disks.
  2515. //
  2516. pCurrentDisk = pCurrentDisk->pNext;
  2517. continue;
  2518. }
  2519. //
  2520. // Convert the DiskId to a printable string
  2521. //
  2522. rpcStatus = UuidToStringW(
  2523. &pCurrentDisk->pDriveLayoutEx->Gpt.DiskId,
  2524. &lpGuidString
  2525. );
  2526. if (rpcStatus != RPC_S_OK) {
  2527. if (lpGuidString) {
  2528. RpcStringFreeW(&lpGuidString);
  2529. }
  2530. //
  2531. // The only error from UuidToStringW is RPC_S_OUT_OF_MEMORY
  2532. //
  2533. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2534. return FALSE;
  2535. }
  2536. pCurrentDisk->SifDiskKey = diskKey;
  2537. swprintf(infstring, L"%lu=%d,%lu,%lu,%ws%ws%ws,%lu,%lu,%lu,%lu,%I64u\r\n",
  2538. diskKey,
  2539. ASR_SYSTEM_KEY,
  2540. pCurrentDisk->SifBusKey,
  2541. pCurrentDisk->IsCritical,
  2542. (lpGuidString ? L"\"" : L""),
  2543. (lpGuidString ? lpGuidString : L""),
  2544. (lpGuidString ? L"\"" : L""),
  2545. pCurrentDisk->pDriveLayoutEx->Gpt.MaxPartitionCount,
  2546. pCurrentDisk->pDiskGeometry->BytesPerSector,
  2547. pCurrentDisk->pDiskGeometry->SectorsPerTrack,
  2548. pCurrentDisk->pDiskGeometry->TracksPerCylinder,
  2549. (ULONG64) (pCurrentDisk->pPartition0Ex->PartitionLength.QuadPart /
  2550. pCurrentDisk->pDiskGeometry->BytesPerSector)
  2551. );
  2552. _AsrpCheckTrue(WriteFile(SifHandle, infstring, wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2553. if (lpGuidString) {
  2554. RpcStringFreeW(&lpGuidString);
  2555. lpGuidString = NULL;
  2556. }
  2557. ++diskKey;
  2558. pCurrentDisk = pCurrentDisk->pNext;
  2559. }
  2560. return TRUE;
  2561. }
  2562. BOOL
  2563. AsrpWriteMbrPartitionsSection(
  2564. IN CONST HANDLE SifHandle, // handle to the state file
  2565. IN CONST PASR_DISK_INFO pDiskList,
  2566. IN CONST PASR_SYSTEM_INFO pSystemInfo
  2567. )
  2568. /*++
  2569. Routine Description:
  2570. Creates the PARTITIONS.MBR section of the ASR state file, and writes
  2571. out the entries in that section to file.
  2572. Arguments:
  2573. SifHandle - Handle to asr.sif, the ASR state file.
  2574. pDiskList - List of disks present on the current system.
  2575. pSystemInfo - Info about the current system, used to determine the current
  2576. boot and system partitions (and mark them appropriately in
  2577. asr.sif)
  2578. Return Value:
  2579. If the function succeeds, the return value is a nonzero value.
  2580. If the function fails, the return value is zero. To get extended error
  2581. information, call GetLastError().
  2582. --*/
  2583. {
  2584. DWORD size = 0,
  2585. index = 0,
  2586. partitionKey = 1;
  2587. UCHAR fsType = 0;
  2588. PWSTR volumeGuid = NULL;
  2589. BOOL writeVolumeGuid = FALSE;
  2590. PASR_DISK_INFO pCurrentDisk = pDiskList;
  2591. WCHAR infstring[ASR_SIF_ENTRY_MAX_CHARS + 1];
  2592. PPARTITION_INFORMATION_EX currentPartitionEx = NULL;
  2593. //
  2594. // Write out the section name: [PARTITIONS.MBR]
  2595. //
  2596. swprintf(infstring, L"\r\n%ws\r\n", ASR_SIF_MBR_PARTITIONS_SECTION_NAME);
  2597. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2598. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2599. //
  2600. // Go through the list of disks, and write one entry for each partition on
  2601. // each of the MBR disks on the list.
  2602. //
  2603. while (pCurrentDisk) {
  2604. if (pCurrentDisk->pDriveLayoutEx) {
  2605. if (PARTITION_STYLE_MBR !=
  2606. pCurrentDisk->pDriveLayoutEx->PartitionStyle
  2607. ) {
  2608. //
  2609. // Skip non-MBR (i.e., GPT) disks
  2610. //
  2611. pCurrentDisk = pCurrentDisk->pNext;
  2612. continue;
  2613. }
  2614. //
  2615. // Enumerate partitions on the disk. We expect to find only
  2616. // MBR partitions.
  2617. //
  2618. for (index =0;
  2619. index < pCurrentDisk->pDriveLayoutEx->PartitionCount;
  2620. index++
  2621. ) {
  2622. currentPartitionEx =
  2623. &pCurrentDisk->pDriveLayoutEx->PartitionEntry[index];
  2624. MYASSERT(currentPartitionEx->PartitionStyle ==
  2625. PARTITION_STYLE_MBR);
  2626. if (currentPartitionEx->Mbr.PartitionType == 0) {
  2627. //
  2628. // Empty partition table entry.
  2629. //
  2630. continue;
  2631. }
  2632. fsType =
  2633. pCurrentDisk->PartitionInfoTable[index].FileSystemType;
  2634. volumeGuid =
  2635. pCurrentDisk->PartitionInfoTable[index].szVolumeGuid;
  2636. //
  2637. // We only want to write out the Volume GUID for basic
  2638. // (recognized) partitions/volumes, since it does not make
  2639. // sense in the context of LDM or other unknown partition
  2640. // types which would need special handling from their
  2641. // respective recovery agents such as asr_ldm in GUI-mode
  2642. // Setup.
  2643. //
  2644. writeVolumeGuid = (wcslen(volumeGuid) > 0) &&
  2645. IsRecognizedPartition(currentPartitionEx->Mbr.PartitionType);
  2646. //
  2647. // Create the entry and write it to file.
  2648. //
  2649. swprintf(
  2650. infstring,
  2651. L"%d=%d,%d,%lu,%ws%ws%ws,0x%02x,0x%02x,0x%02x,%I64u,%I64u,0x%x\r\n",
  2652. partitionKey,
  2653. pCurrentDisk->SifDiskKey,
  2654. index,
  2655. pCurrentDisk->PartitionInfoTable[index].PartitionFlags,
  2656. (writeVolumeGuid ? L"\"" : L""),
  2657. (writeVolumeGuid ? volumeGuid : L""),
  2658. (writeVolumeGuid ? L"\"" : L""),
  2659. (currentPartitionEx->Mbr.BootIndicator)?0x80:0,
  2660. currentPartitionEx->Mbr.PartitionType,
  2661. ((fsType) ? fsType :
  2662. currentPartitionEx->Mbr.PartitionType),
  2663. (ULONG64) ((currentPartitionEx->StartingOffset.QuadPart)/
  2664. (pCurrentDisk->pDiskGeometry->BytesPerSector)),
  2665. (ULONG64) ((currentPartitionEx->PartitionLength.QuadPart)/
  2666. (pCurrentDisk->pDiskGeometry->BytesPerSector)),
  2667. pCurrentDisk->PartitionInfoTable[index].ClusterSize
  2668. );
  2669. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2670. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2671. ++partitionKey;
  2672. }
  2673. }
  2674. pCurrentDisk = pCurrentDisk->pNext;
  2675. }
  2676. return TRUE;
  2677. }
  2678. BOOL
  2679. AsrpWriteGptPartitionsSection(
  2680. IN CONST HANDLE SifHandle,
  2681. IN CONST PASR_DISK_INFO pDiskList,
  2682. IN CONST PASR_SYSTEM_INFO pSystemInfo
  2683. )
  2684. /*++
  2685. Routine Description:
  2686. Creates the PARTITIONS.GPT section of the ASR state file, and writes
  2687. out the entries in that section to file.
  2688. Arguments:
  2689. SifHandle - Handle to asr.sif, the ASR state file.
  2690. pDiskList - List of disks present on the current system.
  2691. pSystemInfo - Info about the current system, used to determine the current
  2692. boot and system partitions (and mark them appropriately in
  2693. asr.sif)
  2694. Return Value:
  2695. If the function succeeds, the return value is a nonzero value.
  2696. If the function fails, the return value is zero. To get extended error
  2697. information, call GetLastError().
  2698. --*/
  2699. {
  2700. DWORD size = 0,
  2701. index = 0,
  2702. partitionKey = 1;
  2703. UCHAR fsType = 0;
  2704. PWSTR volumeGuid = NULL,
  2705. partitionId = NULL,
  2706. partitionType = NULL;
  2707. BOOL writeVolumeGuid = FALSE;
  2708. RPC_STATUS rpcStatus = RPC_S_OK;
  2709. PASR_DISK_INFO pCurrentDisk = pDiskList;
  2710. WCHAR infstring[ASR_SIF_ENTRY_MAX_CHARS + 1];
  2711. PPARTITION_INFORMATION_EX currentPartitionEx = NULL;
  2712. //
  2713. // Write out the section name: [PARTITIONS.GPT]
  2714. //
  2715. swprintf(infstring, L"\r\n%ws\r\n", ASR_SIF_GPT_PARTITIONS_SECTION_NAME);
  2716. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2717. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2718. //
  2719. // Go through the list of disks, and write one entry for each partition on
  2720. // each of the GPT disks on the list.
  2721. //
  2722. while (pCurrentDisk) {
  2723. if (pCurrentDisk->pDriveLayoutEx) {
  2724. if (PARTITION_STYLE_GPT !=
  2725. pCurrentDisk->pDriveLayoutEx->PartitionStyle
  2726. ) {
  2727. //
  2728. // Skip non-GPT (i.e., MBR) disks.
  2729. //
  2730. pCurrentDisk = pCurrentDisk->pNext;
  2731. continue;
  2732. }
  2733. //
  2734. // Enumerate partitions on the disk. We expect to find only
  2735. // GPT partitions.
  2736. //
  2737. for (index =0;
  2738. index < pCurrentDisk->pDriveLayoutEx->PartitionCount;
  2739. index++) {
  2740. currentPartitionEx =
  2741. &pCurrentDisk->pDriveLayoutEx->PartitionEntry[index];
  2742. MYASSERT(currentPartitionEx->PartitionStyle ==
  2743. PARTITION_STYLE_GPT);
  2744. //
  2745. // Convert the Guids to printable strings
  2746. //
  2747. rpcStatus = UuidToStringW(
  2748. &currentPartitionEx->Gpt.PartitionType,
  2749. &partitionType
  2750. );
  2751. if (rpcStatus != RPC_S_OK) {
  2752. if (partitionType) {
  2753. RpcStringFreeW(&partitionType);
  2754. partitionType = NULL;
  2755. }
  2756. //
  2757. // The only error from UuidToString is RPC_S_OUT_OF_MEMORY
  2758. //
  2759. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2760. return FALSE;
  2761. }
  2762. rpcStatus = UuidToStringW(
  2763. &currentPartitionEx->Gpt.PartitionId,
  2764. &partitionId
  2765. );
  2766. if (rpcStatus != RPC_S_OK) {
  2767. if (partitionType) {
  2768. RpcStringFreeW(&partitionType);
  2769. partitionType = NULL;
  2770. }
  2771. if (partitionId) {
  2772. RpcStringFreeW(&partitionId);
  2773. partitionId = NULL;
  2774. }
  2775. //
  2776. // The only error from UuidToString is RPC_S_OUT_OF_MEMORY
  2777. //
  2778. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2779. return FALSE;
  2780. }
  2781. fsType =
  2782. pCurrentDisk->PartitionInfoTable[index].FileSystemType;
  2783. volumeGuid =
  2784. pCurrentDisk->PartitionInfoTable[index].szVolumeGuid;
  2785. //
  2786. // We only want to write out the Volume GUID for basic
  2787. // (recognized) partitions/volumes, since it does not make
  2788. // sense in the context of LDM or other unknown partition
  2789. // types which would need special handling from their
  2790. // respective recovery agents such as asr_ldm in GUI-mode
  2791. // Setup.
  2792. //
  2793. writeVolumeGuid = (wcslen(volumeGuid) > 0) &&
  2794. IsEqualGUID(&(partitionType), &(PARTITION_BASIC_DATA_GUID));
  2795. //
  2796. // Create the entry and write it to file.
  2797. //
  2798. swprintf(
  2799. infstring,
  2800. L"%d=%d,%d,%d,%ws%ws%ws,%ws%ws%ws,%ws%ws%ws,0x%I64x,%ws%ws%ws,0x%02x,%I64u,%I64u,0x%x\r\n",
  2801. partitionKey,
  2802. pCurrentDisk->SifDiskKey,
  2803. index, //slot-index
  2804. pCurrentDisk->PartitionInfoTable[index].PartitionFlags,
  2805. (writeVolumeGuid ? L"\"" : L""),
  2806. (writeVolumeGuid ? volumeGuid : L""),
  2807. (writeVolumeGuid ? L"\"" : L""),
  2808. (partitionType ? L"\"" : L""),
  2809. (partitionType ? partitionType : L""),
  2810. (partitionType ? L"\"" : L""),
  2811. (partitionId ? L"\"" : L""),
  2812. (partitionId ? partitionId : L""),
  2813. (partitionId ? L"\"" : L""),
  2814. currentPartitionEx->Gpt.Attributes,
  2815. (currentPartitionEx->Gpt.Name ? L"\"" : L""),
  2816. (currentPartitionEx->Gpt.Name ?
  2817. currentPartitionEx->Gpt.Name : L""),
  2818. (currentPartitionEx->Gpt.Name ? L"\"" : L""),
  2819. //
  2820. // ISSUE-2000/04/12-guhans: GetVolumeInformation does not
  2821. // work on GPT and fstype is always zero
  2822. //
  2823. fsType,
  2824. (ULONG64) ((currentPartitionEx->StartingOffset.QuadPart)/
  2825. (pCurrentDisk->pDiskGeometry->BytesPerSector)),
  2826. (ULONG64) ((currentPartitionEx->PartitionLength.QuadPart)/
  2827. (pCurrentDisk->pDiskGeometry->BytesPerSector)),
  2828. pCurrentDisk->PartitionInfoTable[index].ClusterSize
  2829. );
  2830. _AsrpCheckTrue(WriteFile(SifHandle, infstring,
  2831. wcslen(infstring)*sizeof(WCHAR), &size, NULL));
  2832. if (partitionType) {
  2833. RpcStringFreeW(&partitionType);
  2834. partitionType = NULL;
  2835. }
  2836. if (partitionId) {
  2837. RpcStringFreeW(&partitionId);
  2838. partitionId = NULL;
  2839. }
  2840. ++partitionKey;
  2841. }
  2842. }
  2843. pCurrentDisk = pCurrentDisk->pNext;
  2844. }
  2845. return TRUE;
  2846. }
  2847. BOOL
  2848. AsrpCreateEnvironmentBlock(
  2849. IN PCWSTR CriticalVolumeList,
  2850. IN HANDLE SifHandle,
  2851. OUT PWSTR *NewBlock
  2852. )
  2853. /*++
  2854. Routine Description:
  2855. Creates a new environment block that is passed in to apps launched as part
  2856. of an ASR backup. This routine retrieves the current process's
  2857. environment block, adds the ASR environment variables to it, and creates a
  2858. multi-sz suitable for being passed in as the lpEnvironment parameter of
  2859. CreateProcess.
  2860. Arguments:
  2861. CriticalVolumeList - A multi-string containing a list of the volume GUID's
  2862. of each of the critical volumes present on the system. The GUID's
  2863. must be in the NT name-space, i.e., must be of the form:
  2864. \??\Volume{GUID}
  2865. This multi-sz is used to create the semi-colon separated list of
  2866. volumes in the "_AsrCriticalVolumeList" variable in NewBlock.
  2867. SifHandle - A (duplicate) handle to asr.sif, the ASR state file. This is
  2868. used in creating the "_AsrContext" variable in NewBlock.
  2869. NewBlock - Receives the new environment block. In addition to all the
  2870. environment variables in the current process environment block,
  2871. this block contains two additional "ASR" variables:
  2872. _AsrContext=<DWORD_PTR value>
  2873. _AsrCriticalVolumeList=<volumeguid>;<volumeguid>;...;<volumeguid>
  2874. The caller is responsible for freeing this block when it is no
  2875. longer needed, using HeapFree(GetProcessHeap(),...).
  2876. Return Value:
  2877. If the function succeeds, the return value is a nonzero value.
  2878. If the function fails, the return value is zero. To get extended error
  2879. information, call GetLastError(). (*NewBlock) is set to NULL.
  2880. --*/
  2881. {
  2882. PCWSTR lpTemp = CriticalVolumeList;
  2883. PWSTR lpCurrentEnvStrings = NULL;
  2884. DWORD cchContextEntry = 0,
  2885. cchEnvBlock = 0,
  2886. cbEnvBlock = 0,
  2887. cbCurrentProcessEnvBlock = 0,
  2888. status = ERROR_SUCCESS;
  2889. HANDLE heapHandle = GetProcessHeap();
  2890. MYASSERT(NewBlock);
  2891. //
  2892. // Find out how much space the environment block will need
  2893. //
  2894. //
  2895. // For _AsrContext=1234 and _AsrCriticalVolumes="..." entries
  2896. //
  2897. lpTemp = CriticalVolumeList;
  2898. if (CriticalVolumeList) {
  2899. while (*lpTemp) {
  2900. lpTemp += (wcslen(lpTemp) + 1);
  2901. }
  2902. }
  2903. cbEnvBlock = (DWORD) ((lpTemp - CriticalVolumeList + 1) * sizeof(WCHAR));
  2904. cbEnvBlock += ASR_CCH_ENVBLOCK_ASR_ENTRIES * sizeof(WCHAR);
  2905. //
  2906. // For all the current environment strings
  2907. //
  2908. lpCurrentEnvStrings = GetEnvironmentStringsW();
  2909. lpTemp = lpCurrentEnvStrings;
  2910. if (lpCurrentEnvStrings ) {
  2911. while (*lpTemp) {
  2912. lpTemp += (wcslen(lpTemp) + 1);
  2913. }
  2914. }
  2915. cbCurrentProcessEnvBlock = (DWORD) ((lpTemp - lpCurrentEnvStrings + 1) * sizeof(WCHAR));
  2916. cbEnvBlock += cbCurrentProcessEnvBlock;
  2917. //
  2918. // And allocate the space
  2919. //
  2920. *NewBlock = (PWSTR) HeapAlloc(
  2921. heapHandle,
  2922. HEAP_ZERO_MEMORY,
  2923. cbEnvBlock
  2924. );
  2925. _AsrpErrExitCode(!(*NewBlock), status, ERROR_NOT_ENOUGH_MEMORY);
  2926. //
  2927. // First, add the AsrContext=1234 entry in the environment block
  2928. //
  2929. swprintf(
  2930. (*NewBlock),
  2931. ASR_ENVBLOCK_CONTEXT_ENTRY,
  2932. (ULONG64) (SifHandle)
  2933. );
  2934. //
  2935. // Keep track of where this entry ends, so we can add a NULL at this
  2936. // index later.
  2937. //
  2938. cchContextEntry = wcslen((*NewBlock));
  2939. wcscat((*NewBlock), L" "); // this character will be replaced by a NULL later
  2940. //
  2941. // Append each critical volume GUID, separated by a semi-colon.
  2942. //
  2943. wcscat((*NewBlock), ASR_ENVBLOCK_CRITICAL_VOLUME_ENTRY);
  2944. if (CriticalVolumeList) {
  2945. lpTemp = CriticalVolumeList;
  2946. while (*lpTemp) {
  2947. wcscat((*NewBlock), lpTemp);
  2948. wcscat((*NewBlock), L";");
  2949. lpTemp += (wcslen(lpTemp) + 1);
  2950. }
  2951. }
  2952. else {
  2953. wcscat((*NewBlock), L";");
  2954. }
  2955. //
  2956. // Mark the end with two NULL's
  2957. //
  2958. cchEnvBlock = wcslen(*NewBlock) - 1;
  2959. // (*NewBlock)[cchEnvBlock - 1] = L'"';
  2960. (*NewBlock)[cchEnvBlock] = L'\0';
  2961. //
  2962. // Separate the two entries with a NULL
  2963. //
  2964. (*NewBlock)[cchContextEntry] = L'\0';
  2965. //
  2966. // Copy over the current environment strings
  2967. //
  2968. RtlCopyMemory(&(*NewBlock)[cchEnvBlock + 1],
  2969. lpCurrentEnvStrings,
  2970. cbCurrentProcessEnvBlock
  2971. );
  2972. EXIT:
  2973. if (lpCurrentEnvStrings) {
  2974. FreeEnvironmentStringsW(lpCurrentEnvStrings);
  2975. lpCurrentEnvStrings = NULL;
  2976. }
  2977. if (ERROR_SUCCESS != status) {
  2978. _AsrpHeapFree((*NewBlock));
  2979. }
  2980. return (BOOL) (ERROR_SUCCESS == status);
  2981. }
  2982. BOOL
  2983. AsrpLaunchRegisteredCommands(
  2984. IN HANDLE SifHandle,
  2985. IN PCWSTR CriticalVolumeList
  2986. )
  2987. /*++
  2988. Routine Description:
  2989. This launches apps that have registered to be part of an ASR-backup. The
  2990. commands are read from the following ASR-Commands key:
  2991. "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Asr\\Commands"
  2992. This key contains a REG_EXPAND_SZ entry for each application to be
  2993. launched, with the data containing the full command-line to be invoked:
  2994. ApplicationName::REG_EXPAND_SZ::<Command-line with parameters>
  2995. Such as:
  2996. ASR utility::REG_EXPAND_SZ::"%systemroot%\\system32\\asr_fmt.exe /backup"
  2997. When invoking the app, we expand out all the environment variables in the
  2998. command-line. In addition, we append a "context" parameter to the command
  2999. line, which the app is expected to use in calls to AsrAddSifEntry.
  3000. The above entry would thus translate something like:
  3001. c:\windows\system32\asr_fmt.exe /backup /context=2000
  3002. The environment block of the process is a duplicate of the current process
  3003. environment block, with one exception--it contains two additional "Asr"
  3004. variables:
  3005. _AsrContext=<DWORD_PTR value>
  3006. _AsrCriticalVolumeList=<volumeguid>;<volumeguid>;...;<volumeguid>
  3007. Each application invoked must complete in the allowed time-out value.
  3008. The time-out is configurable in the registry, by changing the value of the
  3009. "ProcessTimeOut" value under the ASR key. We ship with a default of 3600
  3010. seconds, but the sys-admin can change it if needed. (0=infinite).
  3011. Arguments:
  3012. SifHandle - A handle to asr.sif, the ASR state file. A duplicate of this
  3013. handle is passed in to applications as the "context" parameter,
  3014. and as the "_AsrContext" variable in the environment block.
  3015. CriticalVolumeList - A multi-string containing a list of the volume GUID's
  3016. of each of the critical volumes present on the system. The GUID's
  3017. must be in the NT name-space, i.e., must be of the form:
  3018. \??\Volume{GUID}
  3019. This multi-sz is used to create the semi-colon separated list of
  3020. volumes in the "_AsrCriticalVolumeList" variable in the env
  3021. block of the new processes.
  3022. Applications (such as volume-managers) can use this list to
  3023. determine if they manage any critical volumes, and make a note of
  3024. it in the asr.sif. This way, they can intelligently decide to
  3025. abort the ASR restore process if needed.
  3026. Return Value:
  3027. If the function succeeds, the return value is a nonzero value. This
  3028. implies that all the applications invoked were successful (i.e.,
  3029. returned an exit code of 0).
  3030. If the function fails, the return value is zero. To get extended error
  3031. information, call GetLastError().
  3032. Note that if any of the applications returned an exit code other than 0,
  3033. we interpret that as a fatal error, and will return an error.
  3034. --*/
  3035. {
  3036. HKEY regKey = NULL;
  3037. DWORD status = ERROR_SUCCESS,
  3038. waitResult = WAIT_ABANDONED,
  3039. lpcValues = 0L,
  3040. index = 0L,
  3041. cbData = 0L,
  3042. cbMaxDataLen = 0L,
  3043. cchValueName = 0L,
  3044. cchMaxValueLen = 0L,
  3045. cbCommand = 0L,
  3046. cchReqd = 0L,
  3047. timeLeft = 0L,
  3048. maxTimeOutValue = 0L;
  3049. HANDLE heapHandle = NULL,
  3050. processHandle = NULL,
  3051. dupSifHandle = NULL;
  3052. PWSTR valueName = NULL,
  3053. data = NULL,
  3054. command = NULL,
  3055. lpEnvBlock = NULL;
  3056. WCHAR cmdLineSuffix[ASR_COMMANDLINE_SUFFIX_LEN + 1];
  3057. BOOL result = FALSE;
  3058. STARTUPINFOW startUpInfo;
  3059. PROCESS_INFORMATION processInfo;
  3060. heapHandle = GetProcessHeap();
  3061. processHandle = GetCurrentProcess();
  3062. MYASSERT(heapHandle && processHandle);
  3063. ZeroMemory(cmdLineSuffix, (ASR_COMMANDLINE_SUFFIX_LEN + 1) * sizeof(WCHAR));
  3064. ZeroMemory(&startUpInfo, sizeof(STARTUPINFOW));
  3065. ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
  3066. //
  3067. // Get the time out value for processes, if set in the registry
  3068. // If the key is missing, or is set to "0", the timeout is set
  3069. // to INFINITE.
  3070. //
  3071. status = RegOpenKeyExW(
  3072. HKEY_LOCAL_MACHINE, // hKey
  3073. ASR_REGKEY_ASR, // lpSubKey
  3074. 0, // ulOptions--Reserved, must be 0
  3075. MAXIMUM_ALLOWED, // samDesired
  3076. &regKey // phkResult
  3077. );
  3078. if ((regKey) && (ERROR_SUCCESS == status)) {
  3079. DWORD type = 0L,
  3080. timeOut = 0L,
  3081. cbTimeOut = (sizeof(DWORD));
  3082. status = RegQueryValueExW(
  3083. regKey, // hKey
  3084. ASR_REGVALUE_TIMEOUT, // lpValueName
  3085. NULL, // lpReserved
  3086. &type, // lpType
  3087. (LPBYTE) &timeOut, // lpData
  3088. &cbTimeOut // lpcbData
  3089. );
  3090. if ((ERROR_SUCCESS == status) && (REG_DWORD == type)) {
  3091. maxTimeOutValue = timeOut;
  3092. }
  3093. }
  3094. if (regKey) {
  3095. RegCloseKey(regKey);
  3096. regKey = NULL;
  3097. }
  3098. //
  3099. // Open and enumerate the entries in the ASR command key. If
  3100. // the key doesn't exist, we don't have to execute anything
  3101. //
  3102. status = RegOpenKeyExW(
  3103. HKEY_LOCAL_MACHINE, // hKey
  3104. ASR_REGKEY_ASR_COMMANDS, // lpSubKey
  3105. 0, // ulOptions--Reserved, must be 0
  3106. MAXIMUM_ALLOWED, // samDesired
  3107. &regKey // phkResult
  3108. );
  3109. if ((!regKey) || (ERROR_SUCCESS != status)) {
  3110. return TRUE;
  3111. }
  3112. //
  3113. // Get the max ValueName and Data entries, and
  3114. // allocate memory for them
  3115. //
  3116. status = RegQueryInfoKey(
  3117. regKey,
  3118. NULL, // class
  3119. NULL, // lpcClass
  3120. NULL, // lpReserved
  3121. NULL, // lpcSubKeys
  3122. NULL, // lpcMaxSubKeyLen
  3123. NULL, // lpcMaxClassLen,
  3124. &lpcValues, // number of values
  3125. &cchMaxValueLen, // max value length, in cch
  3126. &cbMaxDataLen, // max data length, in cb
  3127. NULL, // lpcbSecurityDescriptor
  3128. NULL // lpftLastWriteTime
  3129. );
  3130. _AsrpErrExitCode((ERROR_SUCCESS != status), status, status);
  3131. _AsrpErrExitCode((0 == lpcValues), status, ERROR_SUCCESS); // Key is empty, we're done
  3132. valueName = (PWSTR) HeapAlloc(
  3133. heapHandle,
  3134. HEAP_ZERO_MEMORY,
  3135. (cchMaxValueLen + 1) * sizeof (WCHAR) // cch not cb
  3136. );
  3137. _AsrpErrExitCode(!valueName, status, ERROR_NOT_ENOUGH_MEMORY);
  3138. data = (PWSTR) HeapAlloc(
  3139. heapHandle,
  3140. HEAP_ZERO_MEMORY,
  3141. cbMaxDataLen + ((ASR_COMMANDLINE_SUFFIX_LEN + 2) * sizeof(WCHAR))
  3142. );
  3143. _AsrpErrExitCode(!data, status, ERROR_NOT_ENOUGH_MEMORY);
  3144. //
  3145. // "command" will contain the full command string, after any environment
  3146. // variables (eg %systemroot%) in "data" have been expanded. We'll start
  3147. // off with "command" being MAX_PATH characters longer than "data", and
  3148. // we'll re-allocate a bigger buffer if/when needed
  3149. //
  3150. cbCommand = cbMaxDataLen +
  3151. ((ASR_COMMANDLINE_SUFFIX_LEN + MAX_PATH + 2) * sizeof(WCHAR));
  3152. command = (PWSTR) HeapAlloc(
  3153. heapHandle,
  3154. HEAP_ZERO_MEMORY,
  3155. cbCommand
  3156. );
  3157. _AsrpErrExitCode(!command, status, ERROR_NOT_ENOUGH_MEMORY);
  3158. do {
  3159. cchValueName = cchMaxValueLen + 1;
  3160. cbData = cbMaxDataLen + sizeof(WCHAR);
  3161. //
  3162. // Enumerate the commands, and execute them one after the other
  3163. //
  3164. status = RegEnumValueW(
  3165. regKey, // hKey
  3166. index++, // dwIndex
  3167. valueName, // lpValueName
  3168. &cchValueName, // lpcValueName
  3169. NULL, // lpReserved
  3170. NULL, // lpType
  3171. (LPBYTE)data, // lpData
  3172. &cbData // lpcbData
  3173. );
  3174. _AsrpErrExitCode((ERROR_NO_MORE_ITEMS == status),
  3175. status,
  3176. ERROR_SUCCESS
  3177. ); // done with enum
  3178. _AsrpErrExitCode((ERROR_SUCCESS != status), status, status);
  3179. //
  3180. // Create a copy of the sif handle to pass to the app launched.
  3181. // We clean-up close the handle after the app is done.
  3182. //
  3183. result = DuplicateHandle(
  3184. processHandle,
  3185. SifHandle,
  3186. processHandle,
  3187. &dupSifHandle,
  3188. 0L,
  3189. TRUE,
  3190. DUPLICATE_SAME_ACCESS
  3191. );
  3192. _AsrpErrExitCode((!result), status, GetLastError());
  3193. //
  3194. // Append the "/context=<duplicate-sif-handle>" to
  3195. // the command line
  3196. //
  3197. swprintf(cmdLineSuffix,
  3198. ASR_COMMANDLINE_SUFFIX,
  3199. (ULONG64)(dupSifHandle)
  3200. );
  3201. wcscat(data, cmdLineSuffix);
  3202. //
  3203. // Expand any environment strings in the command line
  3204. //
  3205. cchReqd = ExpandEnvironmentStringsW(data,
  3206. command,
  3207. (cbCommand / sizeof(WCHAR))
  3208. );
  3209. _AsrpErrExitCode((!cchReqd), status, GetLastError());
  3210. if ((cchReqd * sizeof(WCHAR)) > cbCommand) {
  3211. //
  3212. // Our "command" buffer wasn't big enough, re-allocate as needed
  3213. //
  3214. _AsrpHeapFree(command);
  3215. cbCommand = ((cchReqd + 1) * sizeof(WCHAR));
  3216. command = HeapAlloc(heapHandle, HEAP_ZERO_MEMORY, cbCommand);
  3217. _AsrpErrExitCode(!command, status, ERROR_NOT_ENOUGH_MEMORY);
  3218. //
  3219. // Try expanding the env strings again ...
  3220. //
  3221. cchReqd = ExpandEnvironmentStringsW(data,
  3222. command,
  3223. (cbCommand / sizeof(WCHAR))
  3224. );
  3225. _AsrpErrExitCode(
  3226. ((!cchReqd) || (cchReqd * sizeof(WCHAR)) > cbCommand),
  3227. status,
  3228. GetLastError()
  3229. );
  3230. }
  3231. //
  3232. // Create the environment block to be passed to the
  3233. // process being launched. The environment block
  3234. // contains the entries:
  3235. // _AsrCriticalVolumes=\??\Volume{Guid1};\??\Volume{Guid2}
  3236. // _AsrContext=<duplicate-sif-handle>
  3237. //
  3238. // in addition to all the environment strings in the current process.
  3239. //
  3240. result = AsrpCreateEnvironmentBlock(CriticalVolumeList,
  3241. dupSifHandle,
  3242. &lpEnvBlock
  3243. );
  3244. _AsrpErrExitCode((!result), status, GetLastError());
  3245. //
  3246. // Execute the command as a separate process
  3247. //
  3248. memset(&startUpInfo, 0L, sizeof (startUpInfo));
  3249. result = CreateProcessW(
  3250. NULL, // lpApplicationName
  3251. command, // lpCommandLine
  3252. NULL, // lpProcessAttributes
  3253. NULL, // lpThreadAttributes
  3254. TRUE, // bInheritHandles
  3255. CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
  3256. lpEnvBlock, // new environment block
  3257. NULL, // current directory name (null=current dir)
  3258. &startUpInfo, // statup information
  3259. &processInfo // process information
  3260. );
  3261. _AsrpErrExitCode((!result),
  3262. status,
  3263. GetLastError()
  3264. ); // process couldn't be launched
  3265. //
  3266. // Process was launched: start the timer countdown if a maximum
  3267. // timeout was specified in the registry. Loop till either the
  3268. // process completes, or the timer expires
  3269. //
  3270. timeLeft = maxTimeOutValue;
  3271. if (timeLeft) {
  3272. do {
  3273. waitResult = WaitForSingleObject(processInfo.hProcess, 1000); // 1000 ms = 1 sec
  3274. --timeLeft;
  3275. } while ((WAIT_TIMEOUT == waitResult) && (timeLeft));
  3276. if (!timeLeft) {
  3277. //
  3278. // The process did not terminate in the allowed time. We treat
  3279. // this as a fatal error--terminate the process, and set its
  3280. // error code to ERROR_TIMEOUT
  3281. //
  3282. TerminateProcess(processInfo.hProcess, ERROR_TIMEOUT);
  3283. }
  3284. }
  3285. else {
  3286. //
  3287. // No timeout was specified in the registry, wait for process to
  3288. // complete.
  3289. //
  3290. waitResult = WaitForSingleObject(processInfo.hProcess, INFINITE);
  3291. }
  3292. //
  3293. // Check if the wait failed above. If last error is something useful,
  3294. // we don't want to destroy it--if it's ERROR_SUCCESS, we'll set it to
  3295. // ERROR_TIMEOUT
  3296. //
  3297. status = GetLastError();
  3298. _AsrpErrExitCode((WAIT_OBJECT_0!=waitResult), status,
  3299. (ERROR_SUCCESS == status ? ERROR_TIMEOUT : status)); // wait failed above
  3300. //
  3301. // Get the process's exit code: if it doesn't return ERROR_SUCCESS,
  3302. // we exit the loop, set the last error to the error returned,
  3303. // and return FALSE
  3304. //
  3305. GetExitCodeProcess(processInfo.hProcess, &status);
  3306. _AsrpErrExitCode((ERROR_SUCCESS != status), status, status);
  3307. _AsrpCloseHandle(dupSifHandle);
  3308. _AsrpHeapFree(lpEnvBlock);
  3309. } while (ERROR_SUCCESS == status);
  3310. EXIT:
  3311. //
  3312. // Clean-up
  3313. //
  3314. if (regKey) {
  3315. RegCloseKey(regKey);
  3316. regKey = NULL;
  3317. }
  3318. _AsrpCloseHandle(dupSifHandle);
  3319. _AsrpHeapFree(valueName);
  3320. _AsrpHeapFree(data);
  3321. _AsrpHeapFree(command);
  3322. _AsrpHeapFree(lpEnvBlock);
  3323. if (ERROR_SUCCESS != status) {
  3324. SetLastError(status);
  3325. return FALSE;
  3326. }
  3327. else {
  3328. return TRUE;
  3329. }
  3330. }
  3331. BOOL
  3332. AsrpIsSupportedConfiguration(
  3333. IN CONST PASR_DISK_INFO pDiskList,
  3334. IN CONST PASR_SYSTEM_INFO pSystemInfo
  3335. )
  3336. /*++
  3337. Routine Description:
  3338. Checks if ASR backup can be performed on the system. We do not support
  3339. systems that have:
  3340. - PROCESSOR_ARCHITECTURE other than "x86", "amd64", or "ia64"
  3341. - any FT volumes present anywhere on the system
  3342. Arguments:
  3343. pDiskList - The list of disks on the system.
  3344. pSystemInfo - System information for this system.
  3345. Return Value:
  3346. If we support this ASR configuration, the return value is non-zero.
  3347. If this configuration is not supported, the return value is zero.
  3348. GetLastError() will return ERROR_NOT_SUPPORTED.
  3349. --*/
  3350. {
  3351. PASR_DISK_INFO pCurrentDisk = pDiskList;
  3352. ULONG index;
  3353. //
  3354. // 1. platform must be x86, amd64, or ia64
  3355. //
  3356. if (wcscmp(pSystemInfo->Platform, ASR_PLATFORM_X86) &&
  3357. wcscmp(pSystemInfo->Platform, ASR_PLATFORM_AMD64) &&
  3358. wcscmp(pSystemInfo->Platform, ASR_PLATFORM_IA64)) {
  3359. SetLastError(ERROR_NOT_SUPPORTED);
  3360. return FALSE;
  3361. }
  3362. //
  3363. // 2. System cannot any FT volumes. All mirrors, stripes and so on are
  3364. // expected to be LDM volumes on dynamic disks.
  3365. //
  3366. while (pCurrentDisk) {
  3367. if (!(pCurrentDisk->pDriveLayoutEx) || !(pCurrentDisk->pDiskGeometry)) {
  3368. MYASSERT(0);
  3369. pCurrentDisk = pCurrentDisk->pNext;
  3370. continue;
  3371. }
  3372. if (pCurrentDisk->pDriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR) {
  3373. for (index =0; index < pCurrentDisk->pDriveLayoutEx->PartitionCount; index++) {
  3374. MYASSERT(pCurrentDisk->pDriveLayoutEx->PartitionEntry[index].PartitionStyle == PARTITION_STYLE_MBR);
  3375. if (IsFTPartition(pCurrentDisk->pDriveLayoutEx->PartitionEntry[index].Mbr.PartitionType)) {
  3376. SetLastError(ERROR_NOT_SUPPORTED);
  3377. return FALSE;
  3378. }
  3379. }
  3380. }
  3381. else if (pCurrentDisk->pDriveLayoutEx->PartitionStyle == PARTITION_STYLE_GPT) {
  3382. //
  3383. // GPT disks can't have FT Mirrors.
  3384. //
  3385. }
  3386. pCurrentDisk = pCurrentDisk->pNext;
  3387. }
  3388. return TRUE;
  3389. }
  3390. //
  3391. // -----
  3392. // The following routines are helpers for AsrAddSifEntry
  3393. // -----
  3394. //
  3395. BOOL
  3396. AsrpSifCheckSectionNameSyntax(
  3397. IN PCWSTR lpSectionName
  3398. )
  3399. /*++
  3400. Routine Description:
  3401. Performs some basic validation of lpSectionName to make sure that
  3402. it conforms to the expected format for a section header
  3403. Arguments:
  3404. lpSectionName - The null-terminated string to be checked.
  3405. Return Value:
  3406. If lpSectionName appears to be a valid section name, the return value is a
  3407. nonzero value.
  3408. If lpSectionName does not pass our basic validation, the return value is
  3409. zero. Note that GetLastError will NOT return additional error
  3410. information in this case.
  3411. --*/
  3412. {
  3413. UINT i = 0;
  3414. WCHAR wch = 0;
  3415. //
  3416. // Must be non-null
  3417. //
  3418. if (!lpSectionName) {
  3419. return FALSE;
  3420. }
  3421. //
  3422. // Must have atleast 3 chars, ([.]) and at most ASR_SIF_ENTRY_MAX_CHARS
  3423. // chars
  3424. //
  3425. if ((ASR_SIF_ENTRY_MAX_CHARS < wcslen(lpSectionName)) ||
  3426. 3 > wcslen(lpSectionName)) {
  3427. return FALSE;
  3428. }
  3429. //
  3430. // First char must be [, and last char must be ].
  3431. //
  3432. if (L'[' != lpSectionName[0] ||
  3433. L']' != lpSectionName[wcslen(lpSectionName)-1]) {
  3434. return FALSE;
  3435. }
  3436. //
  3437. // Check for illegal characters. Legal set of chars: A-Z a-z . _
  3438. //
  3439. for (i = 1; i < wcslen(lpSectionName)-1; i++) {
  3440. wch = lpSectionName[i];
  3441. if ((wch < L'A' || wch > 'Z') &&
  3442. (wch < L'a' || wch > 'z') &&
  3443. (wch < L'0' || wch > '9') &&
  3444. (wch != L'.') &&
  3445. (wch != '_')) {
  3446. return FALSE;
  3447. }
  3448. }
  3449. return TRUE;
  3450. }
  3451. BOOL
  3452. AsrpSifCheckCommandsEntrySyntax(
  3453. PCWSTR pwszEntry
  3454. )
  3455. /*++
  3456. Routine Description:
  3457. Performs some basic validation of pwszEntry to make sure that it conforms
  3458. to the expected entry format for the Commands section
  3459. Arguments:
  3460. pwszEntry - The null-terminated string to be checked.
  3461. Return Value:
  3462. If pwszEntry appears to be a valid section name, the return value is a
  3463. nonzero value.
  3464. If pwszEntry does not pass our basic validation, the return value is
  3465. zero. Note that GetLastError will NOT return additional error
  3466. information in this case.
  3467. --*/
  3468. {
  3469. BOOL fValid = FALSE;
  3470. if (!pwszEntry) {
  3471. return TRUE; // NULL is okay
  3472. }
  3473. //
  3474. // COMMANDS section entry format:
  3475. // system-key,sequence-number,action-on-completion,"command","parameters"
  3476. // system-key must be 1
  3477. // 1000 <= sequence-number <= 4999
  3478. // 0 <= action-on-completion <= 1
  3479. // command: no syntax check
  3480. // parameters: no syntax check
  3481. //
  3482. fValid = (
  3483. // must be atleast 10 chars (1,0000,0,c)
  3484. 10 <= wcslen(pwszEntry) &&
  3485. // system-key must be 1
  3486. L'1' == pwszEntry[0] &&
  3487. L',' == pwszEntry[1] &&
  3488. // 1000 <= sequence-number <= 4999
  3489. L'1' <= pwszEntry[2] &&
  3490. L'4' >= pwszEntry[2] &&
  3491. L'0' <= pwszEntry[3] &&
  3492. L'9' >= pwszEntry[3] &&
  3493. L'0' <= pwszEntry[4] &&
  3494. L'9' >= pwszEntry[4] &&
  3495. L'0' <= pwszEntry[5] &&
  3496. L'9' >= pwszEntry[5] &&
  3497. L',' == pwszEntry[6] &&
  3498. // action-on-completion = [0|1]
  3499. L'0' <= pwszEntry[7] &&
  3500. L'1' >= pwszEntry[7]
  3501. );
  3502. return fValid;
  3503. }
  3504. INT
  3505. AsrpSkipMatchingQuotes(
  3506. IN PCWSTR pwszEntry,
  3507. IN const INT StartingOffset
  3508. )
  3509. /*++
  3510. Routine Description:
  3511. Checks if this entry starts with a quote. If it does, it finds the ending
  3512. quote, and returns the index of the char after the ending quote (usually
  3513. is a comma).
  3514. Arguments:
  3515. pwszEntry - The null-terminated string to check.
  3516. StartingOffset - The index of the starting-quote in pwszEntry.
  3517. Return Value:
  3518. If the character at StartingOffset is a quote, this returns the index of
  3519. the character after the next quote (the matching end-quote) in the
  3520. string. If a matching end-quote is not found, it returns -1.
  3521. If the character at StartingOffset is not a quote, this returns
  3522. StartingOffset.
  3523. Essentially, this returns the position where we expect the next comma in
  3524. the sif entry to be.
  3525. --*/
  3526. {
  3527. INT offset = StartingOffset;
  3528. if (pwszEntry[offset] == L'"') {
  3529. //
  3530. // Find the ending quote and make sure we don't go out of bounds.
  3531. //
  3532. while ( (pwszEntry[++offset]) &&
  3533. (pwszEntry[offset] != L'\"')) {
  3534. ;
  3535. }
  3536. if (!pwszEntry[offset]) {
  3537. //
  3538. // We didn't find the closing quotes--we went out of bounds
  3539. //
  3540. offset = -1;
  3541. }
  3542. else {
  3543. //
  3544. // Found closing quote
  3545. //
  3546. offset++;
  3547. }
  3548. }
  3549. return offset;
  3550. }
  3551. BOOL
  3552. AsrpSifCheckInstallFilesEntrySyntax(
  3553. IN PCWSTR pwszEntry,
  3554. OUT PINT DestinationFilePathIndex OPTIONAL
  3555. )
  3556. /*++
  3557. Routine Description:
  3558. Performs some basic validation of pwszEntry to make sure that it conforms
  3559. to the expected entry format for the InstallFiles section
  3560. Arguments:
  3561. pwszEntry - The null-terminated string to be checked.
  3562. DestinationFilePathIndex - This receives the index at which the
  3563. destination-file-path field in the sif entry (pwszEntry) begins.
  3564. This is an optional parameter.
  3565. Return Value:
  3566. If pwszEntry appears to be a valid section name, the return value is a
  3567. nonzero value.
  3568. If pwszEntry does not pass our basic validation, the return value is
  3569. zero. Note that GetLastError will NOT return additional error
  3570. information in this case.
  3571. --*/
  3572. {
  3573. INT offset = 0;
  3574. if (ARGUMENT_PRESENT(DestinationFilePathIndex)) {
  3575. *DestinationFilePathIndex = 0;
  3576. }
  3577. //
  3578. // NULL is okay
  3579. //
  3580. if (!pwszEntry) {
  3581. return TRUE;
  3582. }
  3583. //
  3584. // INSTALLFILES section entry format:
  3585. // system-key,source-media-label,source-device,
  3586. // source-file-path,destination-file-path,vendor-name,flags
  3587. //
  3588. // system-key must be 1
  3589. //
  3590. // must be atleast 10 chars (1,m,d,p,,v)
  3591. //
  3592. if (wcslen(pwszEntry) < 10) {
  3593. return FALSE;
  3594. }
  3595. //
  3596. // system-key must be 1
  3597. //
  3598. if (L'1' != pwszEntry[0] || L',' != pwszEntry[1] || L'"' != pwszEntry[2]) {
  3599. return FALSE;
  3600. }
  3601. offset = 2;
  3602. //
  3603. // source-media-label
  3604. //
  3605. offset = AsrpSkipMatchingQuotes(pwszEntry, offset);
  3606. if ((offset < 0) || L',' != pwszEntry[offset]) {
  3607. return FALSE;
  3608. }
  3609. //
  3610. // source-device
  3611. //
  3612. if (L'"' != pwszEntry[++offset]) {
  3613. return FALSE;
  3614. }
  3615. offset = AsrpSkipMatchingQuotes(pwszEntry, offset);
  3616. if ((offset < 0) || L',' != pwszEntry[offset]) {
  3617. return FALSE;
  3618. }
  3619. //
  3620. // source-file-path, must be enclosed in quotes.
  3621. //
  3622. if (L'"' != pwszEntry[++offset]) {
  3623. return FALSE;
  3624. }
  3625. offset = AsrpSkipMatchingQuotes(pwszEntry, offset);
  3626. if ((offset < 0) || L',' != pwszEntry[offset]) {
  3627. return FALSE;
  3628. }
  3629. //
  3630. // destination-file-path, must be enclosed in quotes.
  3631. //
  3632. if (L'"' != pwszEntry[++offset]) {
  3633. return FALSE;
  3634. }
  3635. if (ARGUMENT_PRESENT(DestinationFilePathIndex)) {
  3636. *DestinationFilePathIndex = offset;
  3637. }
  3638. offset = AsrpSkipMatchingQuotes(pwszEntry, offset);
  3639. if ((offset < 0) || L',' != pwszEntry[offset]) {
  3640. return FALSE;
  3641. }
  3642. //
  3643. // vendor-name, must be enclosed in quotes.
  3644. //
  3645. if (L'"' != pwszEntry[++offset]) {
  3646. return FALSE;
  3647. }
  3648. offset = AsrpSkipMatchingQuotes(pwszEntry, offset);
  3649. if (offset < 0) {
  3650. return FALSE;
  3651. }
  3652. return TRUE;
  3653. }
  3654. BOOL
  3655. AsrpIsRunningOnPersonalSKU(
  3656. VOID
  3657. )
  3658. /*++
  3659. Routine Description:
  3660. This function checks the system to see if we are running on the personal
  3661. version of the operating system.
  3662. The personal version is denoted by the product id equal to WINNT, which is
  3663. really workstation, and the product suite containing the personal suite
  3664. string.
  3665. This is lifted from "IsRunningOnPersonal" by WesW.
  3666. Arguments:
  3667. None.
  3668. Return Value:
  3669. TRUE if we are running on personal, FALSE otherwise.
  3670. --*/
  3671. {
  3672. OSVERSIONINFOEXW OsVer = {0};
  3673. ULONGLONG ConditionMask = 0;
  3674. OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  3675. OsVer.wSuiteMask = VER_SUITE_PERSONAL;
  3676. OsVer.wProductType = VER_NT_WORKSTATION;
  3677. VER_SET_CONDITION(ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
  3678. VER_SET_CONDITION(ConditionMask, VER_SUITENAME, VER_AND);
  3679. return VerifyVersionInfo(&OsVer,
  3680. VER_PRODUCT_TYPE | VER_SUITENAME,
  3681. ConditionMask
  3682. );
  3683. }
  3684. BOOL
  3685. AsrpIsInGroup(
  3686. IN CONST DWORD dwGroup
  3687. )
  3688. /*++
  3689. Routine Description:
  3690. This function checks to see if the specified SID is enabled
  3691. in the primary access token for the current thread.
  3692. This is based on a similar function in dmadmin.exe.
  3693. Arguments:
  3694. dwGroup - The SID to be checked for
  3695. Return Value:
  3696. TRUE if the specified SID is enabled, FALSE otherwise.
  3697. --*/
  3698. {
  3699. SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_NT_AUTHORITY;
  3700. PSID sidGroup = NULL;
  3701. BOOL bResult = FALSE,
  3702. bIsInGroup = TRUE;
  3703. //
  3704. // Build the SID for the Administrators group
  3705. //
  3706. bResult = AllocateAndInitializeSid(&sidAuth,
  3707. 2,
  3708. SECURITY_BUILTIN_DOMAIN_RID,
  3709. dwGroup,
  3710. 0,
  3711. 0,
  3712. 0,
  3713. 0,
  3714. 0,
  3715. 0,
  3716. &sidGroup
  3717. );
  3718. if (!bResult) {
  3719. return FALSE;
  3720. }
  3721. //
  3722. // Check the current thread token membership
  3723. //
  3724. bResult = CheckTokenMembership(NULL, sidGroup, &bIsInGroup);
  3725. FreeSid(sidGroup);
  3726. return (bResult && bIsInGroup);
  3727. }
  3728. BOOL
  3729. AsrpHasPrivilege(
  3730. CONST PCWSTR szPrivilege
  3731. )
  3732. /*++
  3733. Routine Description:
  3734. This function checks to see if the specified privilege is enabled
  3735. in the primary access token for the current thread.
  3736. This is based on a similar function in dmadmin.exe.
  3737. Arguments:
  3738. szPrivilege - The privilege to be checked for
  3739. Return Value:
  3740. TRUE if the specified privilege is enabled, FALSE otherwise.
  3741. --*/
  3742. {
  3743. LUID luidValue; // LUID (locally unique ID) for the privilege
  3744. BOOL bResult = FALSE,
  3745. bHasPrivilege = FALSE;
  3746. HANDLE hToken = NULL;
  3747. PRIVILEGE_SET privilegeSet;
  3748. //
  3749. // Get the LUID for the privilege from the privilege name
  3750. //
  3751. bResult = LookupPrivilegeValue(
  3752. NULL,
  3753. szPrivilege,
  3754. &luidValue
  3755. );
  3756. if (!bResult) {
  3757. return FALSE;
  3758. }
  3759. //
  3760. // We want to use the token for the current process
  3761. //
  3762. bResult = OpenProcessToken(GetCurrentProcess(),
  3763. MAXIMUM_ALLOWED,
  3764. &hToken
  3765. );
  3766. if (!bResult) {
  3767. return FALSE;
  3768. }
  3769. //
  3770. // And check for the privilege
  3771. //
  3772. privilegeSet.PrivilegeCount = 1;
  3773. privilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
  3774. privilegeSet.Privilege[0].Luid = luidValue;
  3775. privilegeSet.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
  3776. bResult = PrivilegeCheck(hToken, &privilegeSet, &bHasPrivilege);
  3777. CloseHandle(hToken);
  3778. return (bResult && bHasPrivilege);
  3779. }
  3780. BOOL
  3781. AsrpCheckBackupPrivilege(
  3782. VOID
  3783. )
  3784. /*++
  3785. Routine Description:
  3786. This function checks to see if the current process has the
  3787. SE_BACKUP_NAME privilege enabled.
  3788. This is based on a similar function in dmadmin.exe.
  3789. Arguments:
  3790. None.
  3791. Return Value:
  3792. TRUE if the SE_BACKUP_NAME privilege is enabled, FALSE otherwise.
  3793. --*/
  3794. {
  3795. BOOL bHasPrivilege = FALSE;
  3796. bHasPrivilege = AsrpHasPrivilege(SE_BACKUP_NAME);
  3797. /*
  3798. //
  3799. // Don't give up yet--check for the local administrator rights
  3800. //
  3801. if (!bHasPrivilege) {
  3802. bHasPrivilege = AsrpIsInGroup(DOMAIN_ALIAS_RID_ADMINS);
  3803. }
  3804. */
  3805. if (!bHasPrivilege) {
  3806. SetLastError(ERROR_PRIVILEGE_NOT_HELD);
  3807. }
  3808. return bHasPrivilege;
  3809. }
  3810. //
  3811. // -------------------
  3812. // Public functions
  3813. // -------------------
  3814. //
  3815. // The functions below are for use by external backup and
  3816. // restore applications supporting ASR.
  3817. //
  3818. //
  3819. // ---- AsrCreateStateFile
  3820. //
  3821. BOOL
  3822. AsrCreateStateFileW(
  3823. IN PCWSTR lpFilePath OPTIONAL,
  3824. IN PCWSTR lpProviderName OPTIONAL,
  3825. IN CONST BOOL bEnableAutoExtend,
  3826. IN PCWSTR mszCriticalVolumes,
  3827. OUT DWORD_PTR *lpAsrContext
  3828. )
  3829. /*--
  3830. Routine Description:
  3831. AsrCreateStateFile creates an ASR state file with basic information about
  3832. the system, and launches third-party applications that have been
  3833. registered to be run as part of an ASR backup.
  3834. Arguments:
  3835. lpFileName - Pointer to a null-terminated string that specifies the
  3836. full path where the ASR state-file is to be created. If a file
  3837. already exists at the location pointed to by this parameter, it is
  3838. over-written.
  3839. This parameter can be NULL. If it is NULL, the ASR state-file is
  3840. created at the default location (%systemroot%\repair\asr.sif).
  3841. lpProviderName - Pointer to a null-terminated string that specifies the
  3842. full name and version of the backup-and-restore application
  3843. calling AsrCreateStateFile. There is a string size limit of
  3844. (ASR_SIF_ENTRY_MAX_CHARS - ASR_SIF_CCH_PROVIDER_STRING) characters
  3845. for this parameter.
  3846. This parameter can be NULL. If it is NULL, a "Provider=" entry is
  3847. not created in the Version section of the ASR state file.
  3848. bEnableAutoExtend - Indicates whether partitions are to be auto-extended
  3849. during an ASR restore. If this parameter is TRUE, partitions will be
  3850. auto-extended during the ASR restore. If this is FALSE,
  3851. partitions will not be extended.
  3852. lpCriticalVolumes - Pointer to a multi-string containing volume-GUIDs for
  3853. the critical volumes. This list is used to obtain the list of
  3854. critical disks in the system that must be restored for a
  3855. successful ASR.
  3856. The volume-GUID's must be in the NT-namespace, of the form
  3857. \??\Volume{Guid}
  3858. This parameter cannot be NULL.
  3859. lpAsrContext - Pointer to a variable receiving an ASR context. The
  3860. context returned should be used in calls to the other ASR API,
  3861. including AsrAddSifEntry. The calling application must call
  3862. AsrFreeContext to free this context when it is no longer needed.
  3863. This parameter cannot be NULL.
  3864. Return Value:
  3865. If the function succeeds, the return value is a nonzero value.
  3866. If the function fails, the return value is zero. To get extended error
  3867. information, call GetLastError().
  3868. --*/
  3869. {
  3870. BOOL result = FALSE;
  3871. DWORD status = ERROR_SUCCESS,
  3872. size = 0;
  3873. ULONG maxDeviceNumber = 0;
  3874. HANDLE sifhandle = NULL,
  3875. heapHandle = NULL;
  3876. PWSTR asrSifPath = NULL,
  3877. pnpSifPath = NULL,
  3878. tempPointer = NULL;
  3879. UINT cchAsrSifPath = 0;
  3880. char UnicodeFlag[3];
  3881. WCHAR infstring[ASR_SIF_ENTRY_MAX_CHARS + 1];
  3882. SECURITY_ATTRIBUTES saSecurityAttributes;
  3883. SECURITY_DESCRIPTOR sdSecurityDescriptor;
  3884. ASR_SYSTEM_INFO SystemInfo;
  3885. PASR_DISK_INFO OriginalDiskList = NULL;
  3886. if (AsrpIsRunningOnPersonalSKU()) {
  3887. //
  3888. // ASR is not supported on the Personal SKU
  3889. //
  3890. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  3891. return FALSE;
  3892. }
  3893. if (!AsrpCheckBackupPrivilege()) {
  3894. //
  3895. // The caller needs to first acquire SE_BACKUP_NAME
  3896. //
  3897. SetLastError(ERROR_PRIVILEGE_NOT_HELD);
  3898. return FALSE;
  3899. }
  3900. //
  3901. // Check the IN parameters:
  3902. //
  3903. #ifdef PRERELEASE
  3904. //
  3905. // Don't enforce "CriticalVolumes must be non-NULL" for test
  3906. //
  3907. if (!(lpAsrContext))
  3908. #else
  3909. if (!(lpAsrContext && mszCriticalVolumes))
  3910. #endif
  3911. {
  3912. SetLastError(ERROR_INVALID_PARAMETER);
  3913. return FALSE;
  3914. }
  3915. //
  3916. // Set the OUT paramaters to known error values
  3917. //
  3918. *lpAsrContext = 0;
  3919. //
  3920. // Guard ourselves against returning ERROR_SUCCESS if we encountered
  3921. // an unexpected error. We should never actually return this, since
  3922. // we always SetLastError whereever we return FALSE from.
  3923. //
  3924. SetLastError(ERROR_CAN_NOT_COMPLETE);
  3925. //
  3926. // Zero out structs
  3927. //
  3928. memset(&SystemInfo, 0L, sizeof (SYSTEM_INFO));
  3929. heapHandle = GetProcessHeap();
  3930. //
  3931. // Determine the file-path. If lpFilePath is provided, copy it over to
  3932. // locally allocated memory and use it, else use the default path.
  3933. //
  3934. if (ARGUMENT_PRESENT(lpFilePath)) {
  3935. cchAsrSifPath = wcslen(lpFilePath);
  3936. //
  3937. // Do a sanity check: we don't want to allow a file path
  3938. // more than 4096 characters long.
  3939. //
  3940. if (cchAsrSifPath > ASR_SIF_ENTRY_MAX_CHARS) {
  3941. SetLastError(ERROR_INVALID_PARAMETER);
  3942. return FALSE;
  3943. }
  3944. asrSifPath = (PWSTR) HeapAlloc(
  3945. heapHandle,
  3946. HEAP_ZERO_MEMORY,
  3947. ((cchAsrSifPath + 1) * sizeof(WCHAR))
  3948. );
  3949. _AsrpErrExitCode(!asrSifPath, status, ERROR_NOT_ENOUGH_MEMORY);
  3950. wcsncpy(asrSifPath, lpFilePath, cchAsrSifPath);
  3951. }
  3952. else {
  3953. //
  3954. // lpFilePath is NULL, form the default path (of the form
  3955. // \\?\c:\windows\repair\asr.sif)
  3956. //
  3957. //
  3958. // Try with a reasonably sized buffer to begin with.
  3959. //
  3960. asrSifPath = AsrpExpandEnvStrings(ASR_DEFAULT_SIF_PATH);
  3961. _AsrpErrExitCode(!asrSifPath, status, ERROR_BAD_ENVIRONMENT);
  3962. //
  3963. // Set cchAsrSifPath to the size of the asrSif buffer, since we
  3964. // use this in determining the size of the pnpSif buffer below.
  3965. //
  3966. cchAsrSifPath = wcslen(asrSifPath);
  3967. }
  3968. //
  3969. // Determine the file-path of the asrpnp.sif file, based on the location
  3970. // of the asr.sif file.
  3971. //
  3972. pnpSifPath = (PWSTR) HeapAlloc(
  3973. heapHandle,
  3974. HEAP_ZERO_MEMORY,
  3975. ((cchAsrSifPath + 1 + wcslen(ASRPNP_DEFAULT_SIF_NAME))* sizeof(WCHAR))
  3976. );
  3977. _AsrpErrExitCode(!pnpSifPath, status, ERROR_NOT_ENOUGH_MEMORY);
  3978. wcscpy(pnpSifPath, asrSifPath);
  3979. tempPointer = pnpSifPath;
  3980. while (*tempPointer) {
  3981. tempPointer++;
  3982. }
  3983. while ((*tempPointer != L'\\')
  3984. && (*tempPointer != L':')
  3985. && (tempPointer >= pnpSifPath)
  3986. ) {
  3987. tempPointer--;
  3988. }
  3989. tempPointer++;
  3990. wcscpy(tempPointer, ASRPNP_DEFAULT_SIF_NAME);
  3991. //
  3992. // We need to make the handle to asr.sif inheritable, since it will
  3993. // be passed (in the guise of the "AsrContext") to apps that have
  3994. // registered to be run as part of ASR.
  3995. //
  3996. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  3997. saSecurityAttributes.nLength = sizeof (saSecurityAttributes);
  3998. saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor;
  3999. saSecurityAttributes.bInheritHandle = TRUE;
  4000. if (!AsrpConstructSecurityAttributes(&saSecurityAttributes, esatFile, TRUE)) {
  4001. _AsrpErrExitCode(TRUE, status, GetLastError());
  4002. }
  4003. //
  4004. // Create the file. The handle will be closed by the calling backup-app.
  4005. //
  4006. sifhandle = CreateFileW(
  4007. asrSifPath, // lpFileName
  4008. GENERIC_WRITE | GENERIC_READ, // dwDesiredAccess
  4009. FILE_SHARE_READ, // dwShareMode
  4010. &saSecurityAttributes, // lpSecurityAttributes
  4011. CREATE_ALWAYS, // dwCreationFlags
  4012. FILE_FLAG_BACKUP_SEMANTICS, // dwFlagsAndAttributes
  4013. NULL // hTemplateFile
  4014. );
  4015. if (!sifhandle || INVALID_HANDLE_VALUE == sifhandle) {
  4016. //
  4017. // LastError is set by CreateFile
  4018. //
  4019. _AsrpErrExitCode(TRUE, status, GetLastError());
  4020. }
  4021. //
  4022. // File was successfully created. Add the unicode flag at the beginning
  4023. // of the file, followed by comments.
  4024. //
  4025. sprintf(UnicodeFlag, "%c%c", 0xFF, 0xFE);
  4026. result = WriteFile(sifhandle, UnicodeFlag,
  4027. strlen(UnicodeFlag)*sizeof(char), &size, NULL);
  4028. _AsrpErrExitCode(!result, status, GetLastError());
  4029. wcscpy(infstring,
  4030. L";\r\n; Microsoft Windows Automated System Recovery State Information File\r\n;\r\n");
  4031. result = WriteFile(sifhandle, infstring,
  4032. wcslen(infstring)*sizeof(WCHAR), &size, NULL);
  4033. _AsrpErrExitCode(!result, status, GetLastError());
  4034. //
  4035. // Beyond this point, we must zero out asr.sif on any failure. Also, if
  4036. // there's any failure, we must be careful not to make further system
  4037. // calls that could change the error returned by GetLastError().
  4038. //
  4039. //
  4040. // Since the function return values below are and-ed, if any of the calls
  4041. // fails, we won't execute the ones following it.
  4042. //
  4043. result = (
  4044. //
  4045. // Initialise the global structures
  4046. //
  4047. AsrpInitSystemInformation(&SystemInfo, bEnableAutoExtend)
  4048. && AsrpInitDiskInformation(&OriginalDiskList)
  4049. && AsrpInitLayoutInformation(&SystemInfo,
  4050. OriginalDiskList,
  4051. &maxDeviceNumber,
  4052. TRUE,
  4053. FALSE
  4054. )
  4055. && AsrpInitClusterSharedDisks(OriginalDiskList)
  4056. && AsrpFreeNonFixedMedia(&OriginalDiskList)
  4057. && AsrpMarkCriticalDisks(OriginalDiskList,
  4058. mszCriticalVolumes,
  4059. maxDeviceNumber
  4060. )
  4061. //
  4062. // Check if the system configuration is supported
  4063. //
  4064. && AsrpIsSupportedConfiguration(OriginalDiskList, &SystemInfo)
  4065. //
  4066. // Write the required sections to asr.sif
  4067. //
  4068. && AsrpWriteVersionSection(sifhandle, lpProviderName)
  4069. && AsrpWriteSystemsSection(sifhandle, &SystemInfo)
  4070. && AsrpWriteBusesSection(sifhandle, OriginalDiskList)
  4071. && AsrpWriteMbrDisksSection(sifhandle, OriginalDiskList)
  4072. && AsrpWriteGptDisksSection(sifhandle, OriginalDiskList)
  4073. && AsrpWriteMbrPartitionsSection(sifhandle,
  4074. OriginalDiskList,
  4075. &SystemInfo
  4076. )
  4077. && AsrpWriteGptPartitionsSection(sifhandle,
  4078. OriginalDiskList,
  4079. &SystemInfo
  4080. )
  4081. && FlushFileBuffers(sifhandle)
  4082. //
  4083. // Create asrpnp.sif, containing entries needed to recover the PnP
  4084. // entries in the registry
  4085. //
  4086. && AsrCreatePnpStateFileW(pnpSifPath)
  4087. );
  4088. if (result) {
  4089. // everything above succeeded
  4090. //
  4091. // Launch the apps registered to be run as part of ASR-backup. If any
  4092. // of these apps don't complete successfully, we'll fail the ASR-
  4093. // backup.
  4094. //
  4095. result = (
  4096. AsrpLaunchRegisteredCommands(sifhandle, mszCriticalVolumes)
  4097. && FlushFileBuffers(sifhandle)
  4098. );
  4099. }
  4100. if (!result) {
  4101. //
  4102. // One of the functions above failed--we'll make asr.sif zero-length
  4103. // and return the error. CreateFileW or CloseHandle might over-write
  4104. // the LastError, so we save our error now and set it at the end.
  4105. //
  4106. status = GetLastError();
  4107. #ifndef PRERELEASE
  4108. //
  4109. // On release versions, we wipe out the asr.sif if we hit an error,
  4110. // so that the user doesn't unknowingly end up with an incomplete
  4111. // asr.sif
  4112. //
  4113. // We don't want to delete the incomplete asr.sif during test cycles,
  4114. // though, since the sif may be useful for debugging.
  4115. //
  4116. _AsrpCloseHandle(sifhandle);
  4117. //
  4118. // Delete asr.sif and create it again, so that we have a zero-length
  4119. // asr.sif
  4120. //
  4121. DeleteFileW(asrSifPath);
  4122. /* sifhandle = CreateFileW(
  4123. asrSifPath, // lpFileName
  4124. GENERIC_WRITE, // dwDesiredAccess
  4125. 0, // dwShareMode
  4126. &securityAttributes, // lpSecurityAttributes
  4127. CREATE_ALWAYS, // dwCreationFlags
  4128. FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
  4129. NULL // hTemplateFile
  4130. );
  4131. _AsrpCloseHandle(sifhandle);
  4132. */
  4133. #endif
  4134. SetLastError(status);
  4135. }
  4136. EXIT:
  4137. //
  4138. // Clean up
  4139. //
  4140. _AsrpHeapFree(asrSifPath);
  4141. _AsrpHeapFree(pnpSifPath);
  4142. AsrpCleanupSecurityAttributes(&saSecurityAttributes);
  4143. AsrpFreeStateInformation(&OriginalDiskList, &SystemInfo);
  4144. //
  4145. // Set the OUT parameters
  4146. //
  4147. *lpAsrContext = (DWORD_PTR)sifhandle;
  4148. if (ERROR_SUCCESS != status) {
  4149. SetLastError(status);
  4150. }
  4151. if (!result) {
  4152. if (ERROR_SUCCESS == GetLastError()) {
  4153. //
  4154. // We're going to return failure, but we haven't set the LastError to
  4155. // a failure code. This is bad, since we have no clue what went wrong.
  4156. //
  4157. // We shouldn't ever get here, because the function returning FALSE above
  4158. // should set the LastError as it sees fit.
  4159. //
  4160. // But I've added this in just to be safe. Let's set it to a generic
  4161. // error.
  4162. //
  4163. MYASSERT(0 && L"Returning failure, but LastError is not set");
  4164. SetLastError(ERROR_CAN_NOT_COMPLETE);
  4165. }
  4166. }
  4167. return ((result) && (ERROR_SUCCESS == status));
  4168. }
  4169. BOOL
  4170. AsrCreateStateFileA(
  4171. IN LPCSTR lpFilePath,
  4172. IN LPCSTR lpProviderName,
  4173. IN CONST BOOL bEnableAutoExtend,
  4174. IN LPCSTR mszCriticalVolumes,
  4175. OUT DWORD_PTR *lpAsrContext
  4176. )
  4177. /*++
  4178. Routine Description:
  4179. This is the ANSI wrapper for AsrCreateStateFile. Please see
  4180. AsrCreateStateFileW for a detailed description.
  4181. Arguments:
  4182. Return Value:
  4183. If the function succeeds, the return value is a nonzero value.
  4184. If the function fails, the return value is zero. To get extended error
  4185. information, call GetLastError().
  4186. --*/
  4187. {
  4188. PWSTR asrSifPath = NULL,
  4189. providerName = NULL,
  4190. lpwszCriticalVolumes = NULL;
  4191. DWORD cchString = 0,
  4192. status = ERROR_SUCCESS;
  4193. BOOL result = FALSE;
  4194. HANDLE heapHandle = GetProcessHeap();
  4195. if (AsrpIsRunningOnPersonalSKU()) {
  4196. //
  4197. // ASR is not supported on the Personal SKU
  4198. //
  4199. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  4200. return FALSE;
  4201. }
  4202. if (!AsrpCheckBackupPrivilege()) {
  4203. //
  4204. // The caller needs to first acquire SE_BACKUP_NAME
  4205. //
  4206. SetLastError(ERROR_PRIVILEGE_NOT_HELD);
  4207. return FALSE;
  4208. }
  4209. //
  4210. // Check the IN parameters
  4211. //
  4212. #ifdef PRERELEASE
  4213. //
  4214. // Don't enforce "CriticalVolumes must be non-NULL" for test
  4215. //
  4216. if (!(lpAsrContext)) {
  4217. #else
  4218. if (!(lpAsrContext && mszCriticalVolumes)) {
  4219. #endif
  4220. SetLastError(ERROR_INVALID_PARAMETER);
  4221. return FALSE;
  4222. }
  4223. //
  4224. // if lpFilePath is not NULL, allocate a big enough buffer to hold
  4225. // it, and convert it to wide char
  4226. //
  4227. if (lpFilePath) {
  4228. cchString = strlen(lpFilePath);
  4229. //
  4230. // Do a sanity check: we don't want to allow a file path
  4231. // more than 4096 characters long.
  4232. //
  4233. _AsrpErrExitCode(
  4234. (cchString > ASR_SIF_ENTRY_MAX_CHARS),
  4235. status,
  4236. ERROR_INVALID_PARAMETER
  4237. );
  4238. //
  4239. // Allocate a big enough buffer, and copy it over
  4240. //
  4241. asrSifPath = (PWSTR) HeapAlloc(
  4242. heapHandle,
  4243. HEAP_ZERO_MEMORY,
  4244. ((cchString + 1) * sizeof(WCHAR))
  4245. );
  4246. _AsrpErrExitCode(!asrSifPath, status, ERROR_NOT_ENOUGH_MEMORY);
  4247. result = MultiByteToWideChar(CP_ACP, // CodePage
  4248. 0, // dwFlags
  4249. lpFilePath, // lpMultiByteStr
  4250. -1, // cbMultiByte: -1 since lpMultiByteStr is null terminated
  4251. asrSifPath, // lpWideCharStr
  4252. (cchString + 1) // cchWideChar
  4253. );
  4254. _AsrpErrExitCode(!result, status, ERROR_INVALID_PARAMETER);
  4255. }
  4256. //
  4257. // if lpProviderName is not NULL, make sure it isn't insanely long,
  4258. // and convert it to wide char
  4259. //
  4260. if (lpProviderName) {
  4261. cchString = strlen(lpProviderName);
  4262. //
  4263. // Do a sanity check: we don't want to allow an entry
  4264. // more than 4096 characters long.
  4265. //
  4266. _AsrpErrExitCode(
  4267. (cchString > (ASR_SIF_ENTRY_MAX_CHARS - ASR_SIF_CCH_PROVIDER_STRING)),
  4268. status,
  4269. ERROR_INVALID_PARAMETER
  4270. );
  4271. //
  4272. // Allocate a big enough buffer, and copy it over
  4273. //
  4274. providerName = (PWSTR) HeapAlloc(
  4275. heapHandle,
  4276. HEAP_ZERO_MEMORY,
  4277. ((cchString + 1) * sizeof(WCHAR))
  4278. );
  4279. _AsrpErrExitCode(!providerName, status, ERROR_NOT_ENOUGH_MEMORY);
  4280. //
  4281. // Convert to wide string
  4282. //
  4283. result = MultiByteToWideChar(CP_ACP,
  4284. 0,
  4285. lpProviderName,
  4286. -1,
  4287. providerName,
  4288. cchString + 1
  4289. );
  4290. _AsrpErrExitCode(!result, status, ERROR_INVALID_PARAMETER);
  4291. }
  4292. if (mszCriticalVolumes) {
  4293. //
  4294. // Find the total length of mszCriticalVolumes
  4295. //
  4296. LPCSTR lpVolume = mszCriticalVolumes;
  4297. while (*lpVolume) {
  4298. lpVolume += (strlen(lpVolume) + 1);
  4299. }
  4300. //
  4301. // Convert the string to wide-chars
  4302. //
  4303. cchString = (DWORD) (lpVolume - mszCriticalVolumes + 1);
  4304. lpwszCriticalVolumes = (PWSTR) HeapAlloc(
  4305. heapHandle,
  4306. HEAP_ZERO_MEMORY,
  4307. (cchString + 1) * sizeof(WCHAR)
  4308. );
  4309. _AsrpErrExitCode(!lpwszCriticalVolumes, status, ERROR_NOT_ENOUGH_MEMORY);
  4310. result = MultiByteToWideChar(CP_ACP,
  4311. 0,
  4312. mszCriticalVolumes,
  4313. cchString,
  4314. lpwszCriticalVolumes,
  4315. cchString + 1
  4316. );
  4317. _AsrpErrExitCode(!result, status, ERROR_INVALID_PARAMETER);
  4318. }
  4319. result = AsrCreateStateFileW(
  4320. asrSifPath,
  4321. providerName,
  4322. bEnableAutoExtend,
  4323. lpwszCriticalVolumes,
  4324. lpAsrContext
  4325. );
  4326. EXIT:
  4327. _AsrpHeapFree(asrSifPath);
  4328. _AsrpHeapFree(providerName);
  4329. _AsrpHeapFree(lpwszCriticalVolumes);
  4330. return ((result) && (ERROR_SUCCESS == status));
  4331. }
  4332. //
  4333. // ---- AsrAddSifEntry
  4334. //
  4335. BOOL
  4336. AsrAddSifEntryW(
  4337. IN DWORD_PTR AsrContext,
  4338. IN PCWSTR lpSectionName,
  4339. IN PCWSTR lpSifEntry OPTIONAL
  4340. )
  4341. /*++
  4342. Routine Description:
  4343. The AsrSifEntry function adds entries to the ASR state file. It can be
  4344. used by applications that need to save application-specific information
  4345. in the ASR state file.
  4346. Arguments:
  4347. AsrContext - A valid ASR context. See the notes for more information
  4348. about this parameter.
  4349. lpSectionName - Pointer to a null-terminated string that specifies the
  4350. section name. This parameter cannot be NULL.
  4351. The section name has a string size limit of ASR_MAX_SIF_LINE
  4352. characters. This limit is related to how the AsrAddSifEntry
  4353. function parses entries in the ASR state file.
  4354. The section name is case-insensitive. It is converted to all-caps
  4355. before being added to the state file. The section name must not
  4356. contain spaces or non-printable characters. The valid character
  4357. set for section name is limited to letters (A-Z, a-z), numbers
  4358. (0-9), and the following special characters: underscore ("_")
  4359. and period ("."). If the state file does not contain a section
  4360. with the section name pointed to by lpSectionName, a new
  4361. section is created with this section name.
  4362. lpSifEntry - Pointer to a null-terminated string that is to be added to
  4363. the state file in the specified section. If *lpSifEntry is a
  4364. valid entry, there is a string size limit of
  4365. ASR_SIF_ENTRY_MAX_CHARS characters. This limit is related
  4366. to how the AsrAddSifEntry function parses entries in the
  4367. ASR state file.
  4368. If lpSifEntry parameter is NULL, an empty section with the
  4369. section name pointed to by lpSectionName is created if it
  4370. doesn't already exist.
  4371. Return Value:
  4372. If the function succeeds, the return value is a nonzero value.
  4373. If the function fails, the return value is zero. To get extended error
  4374. information, call GetLastError().
  4375. Notes:
  4376. The application calling AsrAddSifEntry obtains the ASR context by one of
  4377. two methods:
  4378. - If the application is the backup-and-restore application that creates
  4379. the ASR state file, it receives the context as a parameter returned by
  4380. AsrCreateStateFile.
  4381. - If the application is launched by AsrCreateStateFile as part of an ASR
  4382. backup, it receives the context to the state file as the /context
  4383. command-line parameter. The application is responsible for reading
  4384. this parameter to get the value of the context.
  4385. AsrAddSifEntry will fail if the section name is that of a reserved section
  4386. that applications are not allowed to add entries to. The following sections
  4387. in the ASR state file are reserved:
  4388. - Version, System, Disks.Mbr, Disk.Gpt, Partitions.Mbr and Partitions.Gpt
  4389. If the section name is recognised (Commands or InstallFiles), AsrAddSifEntry
  4390. will check the syntax of *lpSifEntry to ensure that it is in the proper
  4391. format. In addition, AsrAddSifEntry will check to ensure that there are no
  4392. filename collisions for the InstallFiles section. If a collision is
  4393. detected, the API returns ERROR_ALREADY_EXISTS. Applications must
  4394. use the following pre-defined values to access the recognised sections:
  4395. - ASR_COMMANDS_SECTION_NAME_W for the Commands section, and
  4396. - ASR_INSTALLFILES_SECTION_NAME for the InstallFiles section.
  4397. --*/
  4398. {
  4399. DWORD status = ERROR_SUCCESS,
  4400. nextKey = 0,
  4401. fileOffset = 0,
  4402. size = 0,
  4403. fileSize = 0,
  4404. bufferSize = 0,
  4405. destFilePos = 0;
  4406. HANDLE sifhandle = NULL;
  4407. WCHAR sifstring[ASR_SIF_ENTRY_MAX_CHARS *2 + 1],
  4408. ucaseSectionName[ASR_SIF_ENTRY_MAX_CHARS + 1]; // lpSectionName converted to upper case
  4409. PWSTR buffer = NULL,
  4410. sectionStart = NULL,
  4411. lastEqual = NULL,
  4412. nextSection = NULL,
  4413. nextChar = NULL,
  4414. sectionName = NULL;
  4415. BOOL commandsSection = FALSE,
  4416. installFilesSection = FALSE,
  4417. result = FALSE;
  4418. HANDLE heapHandle = NULL;
  4419. if (AsrpIsRunningOnPersonalSKU()) {
  4420. //
  4421. // ASR is not supported on the Personal SKU
  4422. //
  4423. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  4424. return FALSE;
  4425. }
  4426. if (!AsrpCheckBackupPrivilege()) {
  4427. //
  4428. // The caller needs to first acquire SE_BACKUP_NAME
  4429. //
  4430. SetLastError(ERROR_PRIVILEGE_NOT_HELD);
  4431. return FALSE;
  4432. }
  4433. heapHandle = GetProcessHeap();
  4434. MYASSERT(heapHandle);
  4435. //
  4436. // Zero out local structs
  4437. //
  4438. memset(sifstring, 0, (ASR_SIF_ENTRY_MAX_CHARS *2 + 1) * sizeof(WCHAR));
  4439. memset(ucaseSectionName, 0, (ASR_SIF_ENTRY_MAX_CHARS + 1) * (sizeof (WCHAR)));
  4440. //
  4441. // No OUT parameters
  4442. //
  4443. //
  4444. // Check the IN parameters: The SectionName should meet
  4445. // syntax requirements, SifEntry shouldn't be too long,
  4446. // and the sifhandle should be valid.
  4447. //
  4448. if ((!AsrpSifCheckSectionNameSyntax(lpSectionName)) ||
  4449. (ARGUMENT_PRESENT(lpSifEntry)
  4450. && (wcslen(lpSifEntry) > ASR_SIF_ENTRY_MAX_CHARS)) ||
  4451. ((!AsrContext) ||
  4452. (INVALID_HANDLE_VALUE == (HANDLE)AsrContext))
  4453. ) {
  4454. SetLastError(ERROR_INVALID_PARAMETER);
  4455. return FALSE;
  4456. }
  4457. while (lpSectionName[size]) {
  4458. if ((lpSectionName[size] >= L'a') && (lpSectionName[size] <= L'z')) {
  4459. ucaseSectionName[size] = lpSectionName[size] - L'a' + L'A';
  4460. }
  4461. else {
  4462. ucaseSectionName[size] = lpSectionName[size];
  4463. }
  4464. size++;
  4465. }
  4466. //
  4467. // If the section is a recognised section (COMMANDS or INSTALLFILES),
  4468. // we check the format of the sif entry.
  4469. //
  4470. if (!wcscmp(ucaseSectionName, ASR_SIF_SECTION_COMMANDS_W)) {
  4471. // COMMANDS section
  4472. if (!AsrpSifCheckCommandsEntrySyntax(lpSifEntry)) {
  4473. SetLastError(ERROR_INVALID_PARAMETER);
  4474. return FALSE;
  4475. }
  4476. commandsSection = TRUE;
  4477. }
  4478. else if(!wcscmp(ucaseSectionName, ASR_SIF_SECTION_INSTALLFILES_W)) {
  4479. // INSTALLFILES section
  4480. if (!AsrpSifCheckInstallFilesEntrySyntax(lpSifEntry, &destFilePos)) {
  4481. SetLastError(ERROR_INVALID_PARAMETER);
  4482. return FALSE;
  4483. }
  4484. installFilesSection = TRUE;
  4485. }
  4486. //
  4487. // We do not allow anyone to write to reserved sections:
  4488. // VERSION, SYSTEMS, DISKS.[MBR|GPT], PARTITIONS.[MBR|GPT]
  4489. //
  4490. else if (
  4491. !wcscmp(ucaseSectionName, ASR_SIF_VERSION_SECTION_NAME) ||
  4492. !wcscmp(ucaseSectionName, ASR_SIF_SYSTEM_SECTION_NAME) ||
  4493. !wcscmp(ucaseSectionName, ASR_SIF_MBR_DISKS_SECTION_NAME) ||
  4494. !wcscmp(ucaseSectionName, ASR_SIF_GPT_DISKS_SECTION_NAME) ||
  4495. !wcscmp(ucaseSectionName, ASR_SIF_MBR_PARTITIONS_SECTION_NAME) ||
  4496. !wcscmp(ucaseSectionName, ASR_SIF_GPT_PARTITIONS_SECTION_NAME)
  4497. ) {
  4498. SetLastError(ERROR_INVALID_PARAMETER);
  4499. return FALSE;
  4500. }
  4501. sectionName = (PWSTR) HeapAlloc(
  4502. heapHandle,
  4503. HEAP_ZERO_MEMORY,
  4504. (wcslen(ucaseSectionName) + 5) * sizeof (WCHAR)
  4505. );
  4506. _AsrpErrExitCode(!sectionName, status, ERROR_NOT_ENOUGH_MEMORY);
  4507. swprintf(sectionName, L"\r\n%ws\r\n", ucaseSectionName);
  4508. sifhandle = (HANDLE) AsrContext;
  4509. //
  4510. // The algorithm to add to the middle of asr.sif is rather ugly
  4511. // at the moment: we read the entire file into memory, make our
  4512. // necessary changes, and write back the changed portion of the
  4513. // file to disk. This is inefficient, but it's okay for now since
  4514. // we expect asr.sif to be about 5 or 6 KB at the most.
  4515. //
  4516. // We should revisit this if the performance is unacceptably poor.
  4517. //
  4518. //
  4519. // Allocate memory for the file
  4520. //
  4521. fileSize = GetFileSize(sifhandle, NULL);
  4522. GetLastError();
  4523. _AsrpErrExitCode((fileSize == 0xFFFFFFFF), status, ERROR_INVALID_DATA);
  4524. SetFilePointer(sifhandle, 0, NULL, FILE_BEGIN);
  4525. buffer = (PWSTR) HeapAlloc(
  4526. heapHandle,
  4527. HEAP_ZERO_MEMORY,
  4528. fileSize + 2
  4529. );
  4530. _AsrpErrExitCode(!buffer, status, ERROR_NOT_ENOUGH_MEMORY);
  4531. //
  4532. // And read file into memory.
  4533. //
  4534. result = ReadFile(sifhandle, buffer, fileSize, &size, NULL);
  4535. _AsrpErrExitCode(!result, status, GetLastError());
  4536. //
  4537. // Try to locate ucaseSectionName in the file
  4538. //
  4539. sectionStart = wcsstr(buffer, sectionName);
  4540. if (!sectionStart) {
  4541. //
  4542. // sectionName was not found, ie the section does not exist
  4543. // Add it at the end, and add the SifEntry right after it.
  4544. //
  4545. swprintf(sifstring,
  4546. L"\r\n%ws\r\n%ws%ws\r\n",
  4547. ucaseSectionName,
  4548. ((commandsSection || installFilesSection) ? L"1=" : L""),
  4549. (ARGUMENT_PRESENT(lpSifEntry) ? lpSifEntry : L"")
  4550. );
  4551. //
  4552. // File pointer already points to the end (because of ReadFile above)
  4553. //
  4554. if (!WriteFile(sifhandle, sifstring,
  4555. wcslen(sifstring)*sizeof (WCHAR), &size, NULL)) {
  4556. status = GetLastError();
  4557. }
  4558. // We're done
  4559. }
  4560. else {
  4561. //
  4562. // The section exists, if lpSifEntry is NULL, we're done
  4563. //
  4564. if (ARGUMENT_PRESENT(lpSifEntry)) {
  4565. //
  4566. // SifEntry is not NULL, we'll add it at the end of the section
  4567. //
  4568. nextChar = sectionStart + 4; // Move pointer from \r to . in \r\n[.
  4569. nextKey = 1;
  4570. //
  4571. // Find where this section ends--look either for the start
  4572. // of the next section, or for the end of the file
  4573. //
  4574. while(*nextChar && *nextChar != L'[') {
  4575. //
  4576. // If this is a recognised section, we need to generate
  4577. // the <key> to add the entry in a <key>=<entry> format.
  4578. // We go through each line, and find the last key that
  4579. // already exists. The new key will be last key + 1.
  4580. //
  4581. if (commandsSection || installFilesSection) {
  4582. UINT commaCount = 0;
  4583. BOOL tracking = FALSE;
  4584. UINT count = 0;
  4585. WCHAR c1, c2;
  4586. while (*nextChar && (*nextChar != L'[') && (*nextChar != L'\n')) {
  4587. if (installFilesSection) {
  4588. if (*nextChar == L',') {
  4589. commaCount++;
  4590. }
  4591. if ((commaCount > 2) && (L'"' == *nextChar)) {
  4592. if (tracking) {
  4593. // duplicate file name
  4594. _AsrpErrExitCode((L'"'== lpSifEntry[destFilePos + count]), status, ERROR_ALREADY_EXISTS);
  4595. }
  4596. else {
  4597. tracking = TRUE;
  4598. count = 0;
  4599. }
  4600. }
  4601. if (tracking) {
  4602. c1 = *nextChar;
  4603. if (c1 >= L'a' && c1 <= L'z') {
  4604. c1 = c1 - L'a' + L'A';
  4605. }
  4606. c2 = lpSifEntry[destFilePos + count];
  4607. if (c2 >= L'a' && c2 <= L'z') {
  4608. c2 = c2 - L'a' + L'A';
  4609. }
  4610. if (c1 == c2) {
  4611. count++;
  4612. }
  4613. else {
  4614. tracking = FALSE;
  4615. }
  4616. }
  4617. }
  4618. nextChar++;
  4619. }
  4620. if (*nextChar == L'\n') {
  4621. ++nextChar;
  4622. if (*nextChar >= L'0' && *nextChar <= L'9') {
  4623. nextKey = 0;
  4624. while (*nextChar >= L'0' && *nextChar <= L'9') {
  4625. nextKey = nextKey*10 + (*nextChar - L'0');
  4626. nextChar++;
  4627. }
  4628. nextKey++;
  4629. }
  4630. }
  4631. }
  4632. else {
  4633. nextChar++;
  4634. }
  4635. }
  4636. //
  4637. // We save a pointer to the next section in the sif, since we
  4638. // need to write it out to disk.
  4639. //
  4640. if (*nextChar) {
  4641. nextSection = nextChar;
  4642. }
  4643. else {
  4644. nextSection = NULL;
  4645. }
  4646. if (commandsSection || installFilesSection) {
  4647. //
  4648. // Form the <key>=<entry> string
  4649. //
  4650. swprintf(
  4651. sifstring,
  4652. L"%lu=%ws\r\n",
  4653. nextKey,
  4654. lpSifEntry
  4655. );
  4656. }
  4657. else {
  4658. //
  4659. // Not a recognised section: don't add the <key>=<entry>
  4660. // format, keep the string exactly as passed in
  4661. //
  4662. wcscpy(sifstring, lpSifEntry);
  4663. wcscat(sifstring, L"\r\n");
  4664. }
  4665. if (nextSection) {
  4666. //
  4667. // There are sections following the section we're adding to
  4668. // We need to mark the point where the new entry is added.
  4669. // While writing out to disk, we'll start from this point.
  4670. //
  4671. fileOffset = (DWORD) (((LPBYTE)nextSection) - ((LPBYTE)buffer) - sizeof(WCHAR)*2);
  4672. // section start - file start - "\r\n"
  4673. SetFilePointer(sifhandle, fileOffset, NULL, FILE_BEGIN);
  4674. }
  4675. //
  4676. // file pointer points to where the entry must be added
  4677. //
  4678. if (!WriteFile(sifhandle, sifstring, wcslen(sifstring)*sizeof(WCHAR), &size, NULL)) {
  4679. status = GetLastError();
  4680. }
  4681. else if (nextSection) {
  4682. //
  4683. // write out all sections following this entry
  4684. //
  4685. if (!WriteFile(
  4686. sifhandle,
  4687. ((LPBYTE)nextSection) - (sizeof(WCHAR)*2),
  4688. fileSize - fileOffset,
  4689. &size,
  4690. NULL
  4691. )) {
  4692. status = GetLastError();
  4693. }
  4694. }
  4695. }
  4696. }
  4697. EXIT:
  4698. _AsrpHeapFree(sectionName);
  4699. _AsrpHeapFree(buffer);
  4700. return (BOOL) (ERROR_SUCCESS == status);
  4701. }
  4702. BOOL
  4703. AsrAddSifEntryA(
  4704. IN DWORD_PTR AsrContext,
  4705. IN LPCSTR lpSectionName,
  4706. IN LPCSTR lpSifEntry OPTIONAL
  4707. )
  4708. /*++
  4709. This is the ANSI wrapper for AsrAddSifEntry.
  4710. See AsrAddSifEntryW for a full description.
  4711. --*/
  4712. {
  4713. WCHAR wszSectionName[ASR_SIF_ENTRY_MAX_CHARS + 1];
  4714. WCHAR wszSifEntry[ASR_SIF_ENTRY_MAX_CHARS + 1];
  4715. if (AsrpIsRunningOnPersonalSKU()) {
  4716. //
  4717. // ASR is not supported on the Personal SKU
  4718. //
  4719. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  4720. return FALSE;
  4721. }
  4722. if (!AsrpCheckBackupPrivilege()) {
  4723. //
  4724. // The caller needs to first acquire SE_BACKUP_NAME
  4725. //
  4726. SetLastError(ERROR_PRIVILEGE_NOT_HELD);
  4727. return FALSE;
  4728. }
  4729. memset(wszSectionName, 0L, ASR_SIF_ENTRY_MAX_CHARS + 1);
  4730. memset(wszSifEntry, 0L, ASR_SIF_ENTRY_MAX_CHARS + 1);
  4731. //
  4732. // lpSectionName must be non-NULL
  4733. //
  4734. if ((!lpSectionName) || !(MultiByteToWideChar(
  4735. CP_ACP,
  4736. 0,
  4737. lpSectionName,
  4738. -1,
  4739. wszSectionName,
  4740. ASR_SIF_ENTRY_MAX_CHARS + 1
  4741. ))) {
  4742. SetLastError(ERROR_INVALID_PARAMETER);
  4743. return FALSE;
  4744. }
  4745. //
  4746. // lpSifEntry is allowed to be NULL
  4747. //
  4748. if (ARGUMENT_PRESENT(lpSifEntry) && !(MultiByteToWideChar(
  4749. CP_ACP,
  4750. 0,
  4751. lpSifEntry,
  4752. -1,
  4753. wszSifEntry,
  4754. ASR_SIF_ENTRY_MAX_CHARS + 1
  4755. ))) {
  4756. SetLastError(ERROR_INVALID_PARAMETER);
  4757. return FALSE;
  4758. }
  4759. return AsrAddSifEntryW(
  4760. AsrContext,
  4761. wszSectionName,
  4762. wszSifEntry
  4763. );
  4764. }
  4765. //
  4766. // ---- AsrFreeContext
  4767. //
  4768. BOOL
  4769. AsrFreeContext(
  4770. IN OUT DWORD_PTR *lpAsrContext
  4771. )
  4772. /*++
  4773. Routine Description:
  4774. AsrFreeContext frees the Asr Context, and sets lpAsrContext
  4775. to NULL.
  4776. Arguments:
  4777. lpAsrContext This is the Asr context to be freed. This argument must
  4778. not be NULL.
  4779. AsrFreeContext will set this value to NULL after freeing
  4780. it, to prevent further unintended accesses to the freed
  4781. object.
  4782. Return Value:
  4783. If the function succeeds, the return value is a nonzero value.
  4784. If the function fails, the return value is zero. To get extended error
  4785. information, call GetLastError().
  4786. --*/
  4787. {
  4788. BOOL result = FALSE;
  4789. if (AsrpIsRunningOnPersonalSKU()) {
  4790. //
  4791. // ASR is not supported on the Personal SKU
  4792. //
  4793. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  4794. return FALSE;
  4795. }
  4796. //
  4797. // Essentially, the lpAsrContext is just a file handle, and all we need
  4798. // to do to free it is call CloseHandle.
  4799. //
  4800. if ((lpAsrContext) &&
  4801. (*lpAsrContext) &&
  4802. (INVALID_HANDLE_VALUE != (HANDLE)(*lpAsrContext))
  4803. ) {
  4804. result = CloseHandle((HANDLE)*lpAsrContext);
  4805. *lpAsrContext = 0;
  4806. }
  4807. else {
  4808. SetLastError(ERROR_INVALID_PARAMETER);
  4809. }
  4810. return result;
  4811. }