win32sup.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. win32sup.c
  9. Abstract:
  10. This module implements Windows support functions for the setup application.
  11. Author:
  12. Evan Green 8-Oct-2014
  13. Environment:
  14. Win32
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #define INITGUID
  20. //
  21. // Set to XP/2003 for FindFirstVolume.
  22. //
  23. #define _WIN32_WINNT 0x0500
  24. #include <errno.h>
  25. #include <stdio.h>
  26. #include <windows.h>
  27. #include <SetupApi.h>
  28. #include <winioctl.h>
  29. #include <minoca/devinfo/part.h>
  30. #include "win32sup.h"
  31. //
  32. // ---------------------------------------------------------------- Definitions
  33. //
  34. #define SETUP_WIN32_DISK_LAYOUT_SIZE 4096
  35. //
  36. // ------------------------------------------------------ Data Type Definitions
  37. //
  38. //
  39. // This should come from #include <ddk/ntddstor.h>, but for some very annoying
  40. // reason it's not possible to include both <winioctl.h> and <ddk/ntddstor.h>,
  41. // so the declaration is duplicated here.
  42. //
  43. typedef struct _STORAGE_DEVICE_NUMBER {
  44. DEVICE_TYPE DeviceType;
  45. ULONG DeviceNumber;
  46. ULONG PartitionNumber;
  47. } STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;
  48. //
  49. // ----------------------------------------------- Internal Function Prototypes
  50. //
  51. INT
  52. SetupWin32GetDiskSize (
  53. HANDLE Handle,
  54. PULONGLONG SectorCount,
  55. PULONG SectorSize
  56. );
  57. INT
  58. SetupWin32UnmountVolumesForDisk (
  59. DWORD DiskNumber
  60. );
  61. BOOL
  62. SetupWin32IsVolumeInDisk (
  63. HANDLE VolumeHandle,
  64. DWORD DiskNumber
  65. );
  66. INT
  67. SetupWin32FillInEntriesForDisk (
  68. PSETUP_WIN32_PARTITION_DESCRIPTION *Partitions,
  69. PULONG PartitionCount,
  70. PSTR DevicePath,
  71. PSTORAGE_DEVICE_NUMBER DeviceNumber,
  72. PDRIVE_LAYOUT_INFORMATION_EX DiskLayout,
  73. ULONGLONG BlockCount,
  74. ULONG BlockSize
  75. );
  76. INT
  77. SetupWin32AddPartitionEntry (
  78. PSETUP_WIN32_PARTITION_DESCRIPTION *Partitions,
  79. PULONG PartitionCount,
  80. PSETUP_WIN32_PARTITION_DESCRIPTION NewEntry
  81. );
  82. //
  83. // -------------------------------------------------------------------- Globals
  84. //
  85. //
  86. // This should also come from <ddk/ntddstor.h>, a header that cannot be
  87. // included with winioctl.h.
  88. //
  89. DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, \
  90. 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
  91. //
  92. // ------------------------------------------------------------------ Functions
  93. //
  94. INT
  95. SetupWin32EnumerateDevices (
  96. PSETUP_WIN32_PARTITION_DESCRIPTION *Devices,
  97. PULONG DeviceCount
  98. )
  99. /*++
  100. Routine Description:
  101. This routine enumerates all devices and partitions in the system.
  102. Arguments:
  103. Devices - Supplies a pointer where an array of partition descriptions will
  104. be returned on success. The caller is responsible for freeing this
  105. array when finished (it's just a single free plus each device path).
  106. DeviceCount - Supplies a pointer where the number of elements in the
  107. array will be returned.
  108. Return Value:
  109. 0 on success.
  110. Non-zero on failure.
  111. --*/
  112. {
  113. ULONGLONG BlockCount;
  114. ULONG BlockSize;
  115. DWORD BytesReturned;
  116. DWORD DeviceIndex;
  117. SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
  118. PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
  119. HANDLE Disk;
  120. HDEVINFO DiskClassDevices;
  121. PDRIVE_LAYOUT_INFORMATION_EX DiskLayout;
  122. STORAGE_DEVICE_NUMBER DiskNumber;
  123. DWORD Flags;
  124. ULONG PartitionCount;
  125. ULONG PartitionIndex;
  126. PSETUP_WIN32_PARTITION_DESCRIPTION Partitions;
  127. DWORD RequiredSize;
  128. INT Result;
  129. DeviceInterfaceDetailData = NULL;
  130. Disk = INVALID_HANDLE_VALUE;
  131. DiskLayout = NULL;
  132. PartitionCount = 0;
  133. Partitions = NULL;
  134. Result = -1;
  135. //
  136. // Get the handle to the device information set for installed disk class
  137. // devices. This returns only devices that are present and have exposed
  138. // and interface.
  139. //
  140. Flags = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE;
  141. DiskClassDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK,
  142. NULL,
  143. NULL,
  144. Flags);
  145. if (DiskClassDevices == INVALID_HANDLE_VALUE) {
  146. fprintf(stderr, "SetupDiGetClassDevs failed: ");
  147. SetupWin32PrintLastError();
  148. goto Win32EnumerateDevicesEnd;
  149. }
  150. ZeroMemory(&DeviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
  151. DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  152. DeviceIndex = 0;
  153. //
  154. // Loop through all the disk interfaces returned.
  155. //
  156. while (TRUE) {
  157. Result = SetupDiEnumDeviceInterfaces(DiskClassDevices,
  158. NULL,
  159. &GUID_DEVINTERFACE_DISK,
  160. DeviceIndex,
  161. &DeviceInterfaceData);
  162. if (Result == FALSE) {
  163. break;
  164. }
  165. DeviceIndex += 1;
  166. SetupDiGetDeviceInterfaceDetail(DiskClassDevices,
  167. &DeviceInterfaceData,
  168. NULL,
  169. 0,
  170. &RequiredSize,
  171. NULL);
  172. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  173. fprintf(stderr, "SetupDiGetDeviceInterfaceDetail failed: ");
  174. SetupWin32PrintLastError();
  175. Result = -1;
  176. goto Win32EnumerateDevicesEnd;
  177. }
  178. DeviceInterfaceDetailData = malloc(RequiredSize);
  179. if (DeviceInterfaceDetailData == NULL) {
  180. Result = ENOMEM;
  181. goto Win32EnumerateDevicesEnd;
  182. }
  183. ZeroMemory(DeviceInterfaceDetailData, RequiredSize);
  184. DeviceInterfaceDetailData->cbSize =
  185. sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  186. Result = SetupDiGetDeviceInterfaceDetail(DiskClassDevices,
  187. &DeviceInterfaceData,
  188. DeviceInterfaceDetailData,
  189. RequiredSize,
  190. NULL,
  191. NULL);
  192. if (Result == FALSE) {
  193. fprintf(stderr, "SetupDiGetDeviceInterfaceDetail (2) failed: ");
  194. SetupWin32PrintLastError();
  195. Result = -1;
  196. goto Win32EnumerateDevicesEnd;
  197. }
  198. //
  199. // Open the disk.
  200. //
  201. Disk = CreateFile(DeviceInterfaceDetailData->DevicePath,
  202. GENERIC_READ,
  203. FILE_SHARE_READ | FILE_SHARE_WRITE,
  204. NULL,
  205. OPEN_EXISTING,
  206. FILE_ATTRIBUTE_NORMAL,
  207. NULL);
  208. if (Disk == INVALID_HANDLE_VALUE) {
  209. if (GetLastError() == ERROR_ACCESS_DENIED) {
  210. fprintf(stderr,
  211. "Unable to open disk. Try running as administrator.\n");
  212. } else {
  213. fprintf(stderr, "Open disk failed: ");
  214. SetupWin32PrintLastError();
  215. Result = -1;
  216. goto Win32EnumerateDevicesEnd;
  217. }
  218. free(DeviceInterfaceDetailData);
  219. DeviceInterfaceDetailData = NULL;
  220. continue;
  221. }
  222. Result = DeviceIoControl(Disk,
  223. IOCTL_STORAGE_GET_DEVICE_NUMBER,
  224. NULL,
  225. 0,
  226. &DiskNumber,
  227. sizeof(STORAGE_DEVICE_NUMBER),
  228. &BytesReturned,
  229. NULL);
  230. if (Result == FALSE) {
  231. fprintf(stderr, "IOCTL_STORAGE_GET_DEVICE_NUMBER failed: ");
  232. SetupWin32PrintLastError();
  233. Result = -1;
  234. goto Win32EnumerateDevicesEnd;
  235. }
  236. Result = SetupWin32GetDiskSize(Disk, &BlockCount, &BlockSize);
  237. if (Result != 0) {
  238. BlockCount = 0;
  239. BlockSize = 0;
  240. }
  241. DiskLayout = malloc(SETUP_WIN32_DISK_LAYOUT_SIZE);
  242. if (DiskLayout == NULL) {
  243. Result = ENOMEM;
  244. goto Win32EnumerateDevicesEnd;
  245. }
  246. Result = DeviceIoControl(Disk,
  247. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  248. NULL,
  249. 0,
  250. DiskLayout,
  251. SETUP_WIN32_DISK_LAYOUT_SIZE,
  252. &BytesReturned,
  253. NULL);
  254. if (Result == FALSE) {
  255. fprintf(stderr, "IOCTL_DISK_GET_DRIVE_LAYOUT_EX failed: ");
  256. SetupWin32PrintLastError();
  257. Result = -1;
  258. goto Win32EnumerateDevicesEnd;
  259. }
  260. Result = SetupWin32FillInEntriesForDisk(
  261. &Partitions,
  262. &PartitionCount,
  263. DeviceInterfaceDetailData->DevicePath,
  264. &DiskNumber,
  265. DiskLayout,
  266. BlockCount,
  267. BlockSize);
  268. if (Result != 0) {
  269. goto Win32EnumerateDevicesEnd;
  270. }
  271. CloseHandle(Disk);
  272. Disk = INVALID_HANDLE_VALUE;
  273. free(DeviceInterfaceDetailData);
  274. DeviceInterfaceDetailData = NULL;
  275. free(DiskLayout);
  276. DiskLayout = NULL;
  277. }
  278. Win32EnumerateDevicesEnd:
  279. if (Result != 0) {
  280. if (Partitions != NULL) {
  281. for (PartitionIndex = 0;
  282. PartitionIndex < PartitionCount;
  283. PartitionIndex += 1) {
  284. if (Partitions[PartitionIndex].DevicePath != NULL) {
  285. free(Partitions[PartitionIndex].DevicePath);
  286. }
  287. }
  288. free(Partitions);
  289. Partitions = NULL;
  290. }
  291. PartitionCount = 0;
  292. }
  293. if (DiskLayout != NULL) {
  294. free(DiskLayout);
  295. }
  296. if (Disk != INVALID_HANDLE_VALUE) {
  297. CloseHandle(Disk);
  298. }
  299. if (DeviceInterfaceDetailData != NULL) {
  300. free(DeviceInterfaceDetailData);
  301. }
  302. if (DiskClassDevices != INVALID_HANDLE_VALUE) {
  303. SetupDiDestroyDeviceInfoList(DiskClassDevices);
  304. }
  305. *Devices = Partitions;
  306. *DeviceCount = PartitionCount;
  307. return Result;
  308. }
  309. VOID
  310. SetupWin32PrintLastError (
  311. VOID
  312. )
  313. /*++
  314. Routine Description:
  315. This routine prints a description of GetLastError to standard error and
  316. also prints a newline.
  317. Arguments:
  318. None.
  319. Return Value:
  320. None.
  321. --*/
  322. {
  323. char *Message;
  324. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  325. NULL,
  326. GetLastError(),
  327. 0,
  328. (LPSTR)&Message,
  329. 0,
  330. NULL);
  331. fprintf(stderr, "%s\n", Message);
  332. LocalFree(Message);
  333. return;
  334. }
  335. PVOID
  336. SetupWin32OpenDeviceId (
  337. ULONGLONG DeviceId
  338. )
  339. /*++
  340. Routine Description:
  341. This routine opens a handle to a disk or partition ID.
  342. Arguments:
  343. DeviceId - Supplies the device ID to open.
  344. Return Value:
  345. Returns the open handle on success.
  346. NULL on failure.
  347. --*/
  348. {
  349. ULONG DiskNumber;
  350. HANDLE Handle;
  351. ULONG PartitionNumber;
  352. CHAR Path[512];
  353. INT Result;
  354. DiskNumber = (DeviceId >> 16) & 0xFFFF;
  355. PartitionNumber = DeviceId & 0xFFFF;
  356. if (PartitionNumber == 0) {
  357. snprintf(Path, sizeof(Path), "\\\\.\\PhysicalDrive%d", DiskNumber);
  358. } else {
  359. fprintf(stderr,
  360. "Error: Installing to partitions on Windows is not yet "
  361. "supported.\n");
  362. return NULL;
  363. }
  364. Result = SetupWin32UnmountVolumesForDisk(DiskNumber);
  365. if (Result != 0) {
  366. fprintf(stderr,
  367. "Error: Failed to unmount volumes for disk %d.\n",
  368. DiskNumber);
  369. return NULL;
  370. }
  371. Handle = CreateFile(Path,
  372. GENERIC_READ | GENERIC_WRITE,
  373. FILE_SHARE_READ | FILE_SHARE_WRITE,
  374. NULL,
  375. OPEN_EXISTING,
  376. 0,
  377. NULL);
  378. if (Handle == INVALID_HANDLE_VALUE) {
  379. fprintf(stderr, "Failed to open %s: ", Path);
  380. SetupWin32PrintLastError();
  381. return NULL;
  382. }
  383. return Handle;
  384. }
  385. VOID
  386. SetupWin32Close (
  387. PVOID Handle
  388. )
  389. /*++
  390. Routine Description:
  391. This routine closes a handle.
  392. Arguments:
  393. Handle - Supplies a pointer to the destination to open.
  394. Return Value:
  395. None.
  396. --*/
  397. {
  398. CloseHandle(Handle);
  399. return;
  400. }
  401. ssize_t
  402. SetupWin32Read (
  403. PVOID Handle,
  404. void *Buffer,
  405. size_t ByteCount
  406. )
  407. /*++
  408. Routine Description:
  409. This routine reads from an open handle.
  410. Arguments:
  411. Handle - Supplies the handle.
  412. Buffer - Supplies a pointer where the read bytes will be returned.
  413. ByteCount - Supplies the number of bytes to read.
  414. Return Value:
  415. Returns the number of bytes read.
  416. -1 on failure.
  417. --*/
  418. {
  419. DWORD BytesCompleted;
  420. BOOL Result;
  421. ssize_t TotalBytesRead;
  422. TotalBytesRead = 0;
  423. while (ByteCount != 0) {
  424. Result = ReadFile(Handle, Buffer, ByteCount, &BytesCompleted, NULL);
  425. if (Result == FALSE) {
  426. fprintf(stderr, "Error: Failed to read: ");
  427. SetupWin32PrintLastError();
  428. break;
  429. }
  430. Buffer += BytesCompleted;
  431. TotalBytesRead += BytesCompleted;
  432. ByteCount -= BytesCompleted;
  433. }
  434. return TotalBytesRead;
  435. }
  436. ssize_t
  437. SetupWin32Write (
  438. PVOID Handle,
  439. void *Buffer,
  440. size_t ByteCount
  441. )
  442. /*++
  443. Routine Description:
  444. This routine writes data to an open handle.
  445. Arguments:
  446. Handle - Supplies the handle.
  447. Buffer - Supplies a pointer to the bytes to write.
  448. ByteCount - Supplies the number of bytes to read.
  449. Return Value:
  450. Returns the number of bytes written.
  451. -1 on failure.
  452. --*/
  453. {
  454. DWORD BytesCompleted;
  455. BOOL Result;
  456. ssize_t TotalBytesWritten;
  457. TotalBytesWritten = 0;
  458. while (ByteCount != 0) {
  459. Result = WriteFile(Handle, Buffer, ByteCount, &BytesCompleted, NULL);
  460. if (Result == FALSE) {
  461. fprintf(stderr, "Error: Failed to write: ");
  462. SetupWin32PrintLastError();
  463. break;
  464. }
  465. Buffer += BytesCompleted;
  466. TotalBytesWritten += BytesCompleted;
  467. ByteCount -= BytesCompleted;
  468. }
  469. return TotalBytesWritten;
  470. }
  471. LONGLONG
  472. SetupWin32Seek (
  473. PVOID Handle,
  474. LONGLONG Offset
  475. )
  476. /*++
  477. Routine Description:
  478. This routine seeks in the current file or device.
  479. Arguments:
  480. Handle - Supplies the handle.
  481. Offset - Supplies the new offset to set.
  482. Return Value:
  483. Returns the resulting file offset after the operation.
  484. -1 on failure, and errno will contain more information. The file offset
  485. will remain unchanged.
  486. --*/
  487. {
  488. LARGE_INTEGER DistanceToMove;
  489. LARGE_INTEGER NewOffset;
  490. BOOL Result;
  491. DistanceToMove.QuadPart = Offset;
  492. NewOffset.QuadPart = 0;
  493. Result = SetFilePointerEx(Handle, DistanceToMove, &NewOffset, FILE_BEGIN);
  494. if (Result == FALSE) {
  495. fprintf(stderr, "Error: Failed to seek: ");
  496. SetupWin32PrintLastError();
  497. }
  498. return NewOffset.QuadPart;
  499. }
  500. LONGLONG
  501. SetupWin32Tell (
  502. PVOID Handle
  503. )
  504. /*++
  505. Routine Description:
  506. This routine returns the current file pointer.
  507. Arguments:
  508. Handle - Supplies the handle.
  509. Return Value:
  510. Returns the file offset on success.
  511. -1 on failure, and errno will contain more information. The file offset
  512. will remain unchanged.
  513. --*/
  514. {
  515. LARGE_INTEGER DistanceToMove;
  516. LARGE_INTEGER NewOffset;
  517. BOOL Result;
  518. DistanceToMove.QuadPart = 0;
  519. NewOffset.QuadPart = 0;
  520. Result = SetFilePointerEx(Handle, DistanceToMove, &NewOffset, FILE_CURRENT);
  521. if (Result == FALSE) {
  522. fprintf(stderr, "Error: Failed to tell: ");
  523. SetupWin32PrintLastError();
  524. }
  525. return NewOffset.QuadPart;
  526. }
  527. INT
  528. SetupWin32FileStat (
  529. PVOID Handle,
  530. PULONGLONG FileSize
  531. )
  532. /*++
  533. Routine Description:
  534. This routine gets details for the given open file.
  535. Arguments:
  536. Handle - Supplies the handle.
  537. FileSize - Supplies an optional pointer where the file size will be
  538. returned on success.
  539. Return Value:
  540. 0 on success.
  541. Non-zero on failure.
  542. --*/
  543. {
  544. INT Result;
  545. ULONGLONG SectorCount;
  546. ULONG SectorSize;
  547. Result = SetupWin32GetDiskSize(Handle, &SectorCount, &SectorSize);
  548. if (Result != 0) {
  549. fprintf(stderr, "Error: Failed to get disk size: ");
  550. SetupWin32PrintLastError();
  551. return -1;
  552. }
  553. *FileSize = SectorSize * SectorCount;
  554. return 0;
  555. }
  556. //
  557. // --------------------------------------------------------- Internal Functions
  558. //
  559. INT
  560. SetupWin32GetDiskSize (
  561. HANDLE Handle,
  562. PULONGLONG SectorCount,
  563. PULONG SectorSize
  564. )
  565. /*++
  566. Routine Description:
  567. This routine queries the disk size for the given handle.
  568. Arguments:
  569. Handle - Supplies the open handle to the disk.
  570. SectorCount - Supplies a pointer where the number of sectors on the disk
  571. will be returned.
  572. SectorSize - Supplies a pointer where the size of a single sector in bytes
  573. will be returned.
  574. Return Value:
  575. 0 on success.
  576. Non-zero on failure.
  577. --*/
  578. {
  579. DWORD BytesRead;
  580. DISK_GEOMETRY_EX DiskGeometry;
  581. BOOL Result;
  582. Result = DeviceIoControl(Handle,
  583. IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
  584. NULL,
  585. 0,
  586. &DiskGeometry,
  587. sizeof(DISK_GEOMETRY_EX),
  588. &BytesRead,
  589. NULL);
  590. if (Result == FALSE) {
  591. if (GetLastError() != ERROR_NOT_READY) {
  592. fprintf(stderr, "IOCTL_DISK_GET_DRIVE_GEOMETRY_EX failed: ");
  593. SetupWin32PrintLastError();
  594. }
  595. return -1;
  596. }
  597. *SectorSize = DiskGeometry.Geometry.BytesPerSector;
  598. *SectorCount = DiskGeometry.DiskSize.QuadPart /
  599. DiskGeometry.Geometry.BytesPerSector;
  600. return 0;
  601. }
  602. INT
  603. SetupWin32UnmountVolumesForDisk (
  604. DWORD DiskNumber
  605. )
  606. /*++
  607. Routine Description:
  608. This routine unmounts all volumes associated with the given disk number.
  609. Arguments:
  610. DiskNumber - Supplies the disk number.
  611. Return Value:
  612. 0 on success.
  613. Non-zero on failure.
  614. --*/
  615. {
  616. DWORD BytesRead;
  617. HANDLE Handle;
  618. CHAR Path[1024];
  619. ULONG PathLength;
  620. BOOL Result;
  621. HANDLE SearchHandle;
  622. SearchHandle = FindFirstVolume(Path, sizeof(Path));
  623. if (SearchHandle == INVALID_HANDLE_VALUE) {
  624. return 0;
  625. }
  626. while (TRUE) {
  627. PathLength = strlen(Path);
  628. if ((PathLength != 0) && (Path[PathLength - 1] == '\\')) {
  629. Path[PathLength - 1] = '\0';
  630. }
  631. Handle = CreateFile(Path,
  632. GENERIC_WRITE,
  633. FILE_SHARE_READ | FILE_SHARE_WRITE,
  634. NULL,
  635. OPEN_EXISTING,
  636. 0,
  637. NULL);
  638. if (Handle != INVALID_HANDLE_VALUE) {
  639. if (SetupWin32IsVolumeInDisk(Handle, DiskNumber) != FALSE) {
  640. Result = DeviceIoControl(Handle,
  641. FSCTL_LOCK_VOLUME,
  642. NULL,
  643. 0,
  644. NULL,
  645. 0,
  646. &BytesRead,
  647. NULL);
  648. if (Result == FALSE) {
  649. fprintf(stderr,
  650. "Warning: Failed to lock volume '%s': ",
  651. Path);
  652. SetupWin32PrintLastError();
  653. }
  654. Result = DeviceIoControl(Handle,
  655. FSCTL_DISMOUNT_VOLUME,
  656. NULL,
  657. 0,
  658. NULL,
  659. 0,
  660. &BytesRead,
  661. NULL);
  662. if (Result == FALSE) {
  663. fprintf(stderr,
  664. "Warning: Failed to unmount '%s': ",
  665. Path);
  666. SetupWin32PrintLastError();
  667. }
  668. //
  669. // "Lose" the handle so it stays open and the volume stays
  670. // locked. The volume unlocks itself when the application
  671. // exits. This is not very good form, consider storing these
  672. // volume handles in a structure associated with the disk
  673. // handle.
  674. //
  675. Handle = INVALID_HANDLE_VALUE;
  676. }
  677. if (Handle != INVALID_HANDLE_VALUE) {
  678. CloseHandle(Handle);
  679. }
  680. }
  681. Result = FindNextVolume(SearchHandle, Path, sizeof(Path));
  682. if (Result == FALSE) {
  683. break;
  684. }
  685. }
  686. FindVolumeClose(SearchHandle);
  687. return 0;
  688. }
  689. BOOL
  690. SetupWin32IsVolumeInDisk (
  691. HANDLE VolumeHandle,
  692. DWORD DiskNumber
  693. )
  694. /*++
  695. Routine Description:
  696. This routine determines in the given volume resides on the given disk.
  697. Arguments:
  698. VolumeHandle - Supplies the open handle to the volume.
  699. DiskNumber - Supplies the disk number to query.
  700. Return Value:
  701. TRUE if the volume is on the disk.
  702. FALSE if the volume is not on the disk.
  703. --*/
  704. {
  705. DWORD BytesReturned;
  706. PDISK_EXTENT Extent;
  707. PVOLUME_DISK_EXTENTS Extents;
  708. ULONG Index;
  709. BOOL Result;
  710. Extents = malloc(SETUP_WIN32_DISK_LAYOUT_SIZE);
  711. if (Extents == NULL) {
  712. return FALSE;
  713. }
  714. Result = DeviceIoControl(VolumeHandle,
  715. IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
  716. NULL,
  717. 0,
  718. Extents,
  719. SETUP_WIN32_DISK_LAYOUT_SIZE,
  720. &BytesReturned,
  721. NULL);
  722. if (Result == FALSE) {
  723. return FALSE;
  724. }
  725. Extent = Extents->Extents;
  726. for (Index = 0; Index < Extents->NumberOfDiskExtents; Index += 1) {
  727. if (Extent[Index].DiskNumber == DiskNumber) {
  728. free(Extents);
  729. return TRUE;
  730. }
  731. }
  732. free(Extents);
  733. return FALSE;
  734. }
  735. INT
  736. SetupWin32FillInEntriesForDisk (
  737. PSETUP_WIN32_PARTITION_DESCRIPTION *Partitions,
  738. PULONG PartitionCount,
  739. PSTR DevicePath,
  740. PSTORAGE_DEVICE_NUMBER DeviceNumber,
  741. PDRIVE_LAYOUT_INFORMATION_EX DiskLayout,
  742. ULONGLONG BlockCount,
  743. ULONG BlockSize
  744. )
  745. /*++
  746. Routine Description:
  747. This routine adds the appropriate entries for the disk and its partitions
  748. to the resulting enumeration array.
  749. Arguments:
  750. Partitions - Supplies a pointer that on input contains a pointer to the
  751. array of partitions to return. This array may be reallocated and
  752. expanded to contain the new entries.
  753. PartitionCount - Supplies a pointer that on input contains the number of
  754. elements in the partition array. On output this will reflect the new
  755. correct element count.
  756. DevicePath - Supplies a pointer to the device path.
  757. DeviceNumber - Supplies a pointer to the disk device number information.
  758. DiskLayout - Supplies a pointer to the disk layout information.
  759. BlockCount - Supplies the total number of blocks in the disk.
  760. BlockSize - Supplies the disk block size in bytes.
  761. Return Value:
  762. 0 on success.
  763. Non-zero on failure.
  764. --*/
  765. {
  766. SETUP_WIN32_PARTITION_DESCRIPTION NewEntry;
  767. PARTITION_INFORMATION_EX *Partition;
  768. ULONG PartitionIndex;
  769. INT Result;
  770. if (BlockCount == 0) {
  771. return 0;
  772. }
  773. //
  774. // Add the entry for the disk itself.
  775. //
  776. memset(&NewEntry, 0, sizeof(SETUP_WIN32_PARTITION_DESCRIPTION));
  777. NewEntry.DiskNumber = DeviceNumber->DeviceNumber;
  778. NewEntry.PartitionNumber = DeviceNumber->PartitionNumber;
  779. NewEntry.Partition.BlockSize = BlockSize;
  780. NewEntry.Partition.Number = DeviceNumber->PartitionNumber;
  781. NewEntry.Partition.FirstBlock = 0;
  782. NewEntry.Partition.LastBlock = BlockCount - 1;
  783. if (DiskLayout->PartitionStyle == PARTITION_STYLE_MBR) {
  784. NewEntry.Partition.PartitionFormat = PartitionFormatMbr;
  785. memcpy(NewEntry.Partition.DiskId,
  786. &(DiskLayout->Mbr.Signature),
  787. sizeof(ULONG));
  788. } else if (DiskLayout->PartitionStyle == PARTITION_STYLE_GPT) {
  789. NewEntry.Partition.PartitionFormat = PartitionFormatGpt;
  790. memcpy(NewEntry.Partition.DiskId,
  791. &(DiskLayout->Gpt.DiskId),
  792. DISK_IDENTIFIER_SIZE);
  793. } else if (DiskLayout->PartitionStyle == PARTITION_STYLE_RAW) {
  794. NewEntry.Partition.PartitionFormat = PartitionFormatNone;
  795. }
  796. NewEntry.Partition.Flags = PARTITION_FLAG_RAW_DISK;
  797. NewEntry.DevicePath = strdup(DevicePath);
  798. Result = SetupWin32AddPartitionEntry(Partitions, PartitionCount, &NewEntry);
  799. if (Result != 0) {
  800. goto Win32FillInEntriesForDiskEnd;
  801. }
  802. NewEntry.DevicePath = NULL;
  803. Partition = DiskLayout->PartitionEntry;
  804. for (PartitionIndex = 0;
  805. PartitionIndex < DiskLayout->PartitionCount;
  806. PartitionIndex += 1) {
  807. NewEntry.PartitionNumber = PartitionIndex + 1;
  808. NewEntry.Partition.Number = PartitionIndex + 1;
  809. NewEntry.Partition.FirstBlock = Partition->StartingOffset.QuadPart /
  810. BlockSize;
  811. NewEntry.Partition.LastBlock =
  812. NewEntry.Partition.FirstBlock +
  813. (Partition->PartitionLength.QuadPart / BlockSize) - 1;
  814. ZeroMemory(&(NewEntry.Partition.PartitionId),
  815. PARTITION_IDENTIFIER_SIZE);
  816. ZeroMemory(&(NewEntry.Partition.PartitionTypeId),
  817. PARTITION_TYPE_SIZE);
  818. NewEntry.Partition.Flags = 0;
  819. if (Partition->PartitionStyle == PARTITION_STYLE_MBR) {
  820. if (Partition->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) {
  821. Partition += 1;
  822. continue;
  823. }
  824. memcpy(&(NewEntry.Partition.PartitionId[0]),
  825. &(DiskLayout->Mbr.Signature),
  826. sizeof(ULONG));
  827. memcpy(&(NewEntry.Partition.PartitionId[sizeof(ULONG)]),
  828. &(Partition->PartitionNumber),
  829. sizeof(ULONG));
  830. NewEntry.Partition.PartitionTypeId[0] =
  831. Partition->Mbr.PartitionType;
  832. if (Partition->Mbr.BootIndicator != FALSE) {
  833. NewEntry.Partition.Flags |= PARTITION_FLAG_BOOT;
  834. }
  835. } else if (Partition->PartitionStyle == PARTITION_STYLE_GPT) {
  836. memcpy(&(NewEntry.Partition.PartitionId),
  837. &(Partition->Gpt.PartitionId),
  838. PARTITION_IDENTIFIER_SIZE);
  839. memcpy(&(NewEntry.Partition.PartitionTypeId),
  840. &(Partition->Gpt.PartitionType),
  841. PARTITION_TYPE_SIZE);
  842. }
  843. Result = SetupWin32AddPartitionEntry(Partitions,
  844. PartitionCount,
  845. &NewEntry);
  846. if (Result != 0) {
  847. goto Win32FillInEntriesForDiskEnd;
  848. }
  849. Partition += 1;
  850. }
  851. Win32FillInEntriesForDiskEnd:
  852. return Result;
  853. }
  854. INT
  855. SetupWin32AddPartitionEntry (
  856. PSETUP_WIN32_PARTITION_DESCRIPTION *Partitions,
  857. PULONG PartitionCount,
  858. PSETUP_WIN32_PARTITION_DESCRIPTION NewEntry
  859. )
  860. /*++
  861. Routine Description:
  862. This routine appends an entry to the partition array.
  863. Arguments:
  864. Partitions - Supplies a pointer that on input contains a pointer to the
  865. array of partitions to return. This array may be reallocated and
  866. expanded to contain the new entries.
  867. PartitionCount - Supplies a pointer that on input contains the number of
  868. elements in the partition array. On output this will reflect the new
  869. correct element count.
  870. NewEntry - Supplies a pointer to the entry to append to the array.
  871. Return Value:
  872. 0 on success.
  873. Non-zero on failure.
  874. --*/
  875. {
  876. PVOID NewBuffer;
  877. ULONG NewSize;
  878. PVOID NextEntry;
  879. NewEntry->Partition.Version = PARTITION_DEVICE_INFORMATION_VERSION;
  880. NewSize = (*PartitionCount + 1) *
  881. sizeof(SETUP_WIN32_PARTITION_DESCRIPTION);
  882. NewBuffer = realloc(*Partitions, NewSize);
  883. if (NewBuffer == NULL) {
  884. return ENOMEM;
  885. }
  886. *Partitions = NewBuffer;
  887. NextEntry = NewBuffer +
  888. (*PartitionCount *
  889. sizeof(SETUP_WIN32_PARTITION_DESCRIPTION));
  890. memcpy(NextEntry, NewEntry, sizeof(SETUP_WIN32_PARTITION_DESCRIPTION));
  891. *PartitionCount += 1;
  892. return 0;
  893. }