Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1087 lines
24 KiB

  1. /*++
  2. Copyright (c) 1991-1994 Microsoft Corporation
  3. Module Name:
  4. ntlow.c
  5. Abstract:
  6. This file contains the low-level I/O routines, implemented
  7. to run on NT.
  8. Author:
  9. Ted Miller (tedm) 8-Nov-1991
  10. Revision History:
  11. Bob Rinne (bobri) 2-Feb-1994
  12. Dynamic partitioning changes.
  13. --*/
  14. #include "fdisk.h"
  15. #include <stdio.h>
  16. #include <string.h>
  17. STATUS_CODE
  18. LowQueryFdiskPathList(
  19. OUT PCHAR **PathList,
  20. OUT PULONG ListLength
  21. )
  22. /*++
  23. Routine Description:
  24. This routine determines how many drives are present in the
  25. system and returns a list of Ascii strings for the names of
  26. each of the drives found.
  27. When a drive is located, a check is made to insure that the
  28. associated DosName for the physical drive is also present in
  29. the system.
  30. Arguments:
  31. PathList - pointer to a pointer for the list
  32. ListLength - the number of entries returned in the list
  33. Return Value:
  34. Error status if there is a problem.
  35. --*/
  36. {
  37. HANDLE dummyHandle;
  38. STATUS_CODE status;
  39. ULONG count = 0;
  40. ULONG i;
  41. char buffer[100];
  42. PCHAR *pathArray;
  43. while (1) {
  44. sprintf(buffer, "\\device\\harddisk%u", count);
  45. status = LowOpenDisk(buffer, &dummyHandle);
  46. // Only STATUS_OBJECT_PATH_NOT_FOUND can terminate the count.
  47. if (NT_SUCCESS(status)) {
  48. char dosNameBuffer[80];
  49. LowCloseDisk(dummyHandle);
  50. // Insure that the physicaldrive name is present
  51. sprintf(dosNameBuffer, "\\dosdevices\\PhysicalDrive%u", count);
  52. status = LowOpenNtName(dosNameBuffer, &dummyHandle);
  53. if (NT_SUCCESS(status)) {
  54. LowCloseDisk(dummyHandle);
  55. } else {
  56. // Not there, create it.
  57. sprintf(buffer, "\\device\\harddisk%u\\Partition0", count);
  58. DefineDosDevice(DDD_RAW_TARGET_PATH, (LPCTSTR) dosNameBuffer, (LPCTSTR) buffer);
  59. }
  60. } else if (status == STATUS_OBJECT_PATH_NOT_FOUND) {
  61. break;
  62. } else if (status == STATUS_ACCESS_DENIED) {
  63. return status;
  64. }
  65. count++;
  66. }
  67. pathArray = Malloc(count * sizeof(PCHAR));
  68. for (i=0; i<count; i++) {
  69. sprintf(buffer, "\\device\\harddisk%u", i);
  70. pathArray[i] = Malloc(lstrlenA(buffer)+1);
  71. strcpy(pathArray[i], buffer);
  72. }
  73. *PathList = pathArray;
  74. *ListLength = count;
  75. return OK_STATUS;
  76. }
  77. STATUS_CODE
  78. LowFreeFdiskPathList(
  79. IN OUT PCHAR* PathList,
  80. IN ULONG ListLength
  81. )
  82. /*++
  83. Routine Description:
  84. Walk the provided list up to its length and free the memory
  85. allocated. Upon completion, free the memory for the list
  86. itself.
  87. Arguments:
  88. PathList - pointer to base of path list
  89. ListLength - number of entries in the list
  90. Return Value:
  91. Always OK_STATUS
  92. --*/
  93. {
  94. ULONG i;
  95. for (i=0; i<ListLength; i++) {
  96. FreeMemory(PathList[i]);
  97. }
  98. FreeMemory(PathList);
  99. return OK_STATUS;
  100. }
  101. STATUS_CODE
  102. LowOpenNtName(
  103. IN PCHAR Name,
  104. IN HANDLE_PT Handle
  105. )
  106. /*++
  107. Routine Description:
  108. This is an internal "Low" routine to handle open requests.
  109. Arguments:
  110. Name - pointer to the NT name for the open.
  111. Handle - pointer for the handle returned.
  112. Return Value:
  113. NT status
  114. --*/
  115. {
  116. OBJECT_ATTRIBUTES oa;
  117. NTSTATUS status;
  118. IO_STATUS_BLOCK statusBlock;
  119. ANSI_STRING ansiName;
  120. UNICODE_STRING unicodeName;
  121. RtlInitAnsiString(&ansiName, Name);
  122. status = RtlAnsiStringToUnicodeString(&unicodeName, &ansiName, TRUE);
  123. if (!NT_SUCCESS(status)) {
  124. return status;
  125. }
  126. memset(&oa, 0, sizeof(OBJECT_ATTRIBUTES));
  127. oa.Length = sizeof(OBJECT_ATTRIBUTES);
  128. oa.ObjectName = &unicodeName;
  129. oa.Attributes = OBJ_CASE_INSENSITIVE;
  130. status = DmOpenFile(Handle,
  131. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  132. &oa,
  133. &statusBlock,
  134. FILE_SHARE_READ | FILE_SHARE_WRITE,
  135. FILE_SYNCHRONOUS_IO_ALERT);
  136. if (!NT_SUCCESS(status)) {
  137. FDLOG((1,"LowOpen: 1st open failed with 0x%x\n", status));
  138. // try a 2nd time to get around an FS glitch or a test
  139. // bug where this doesn't work on an attempt to delete a
  140. // partition
  141. Sleep(500);
  142. status = DmOpenFile(Handle,
  143. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  144. &oa,
  145. &statusBlock,
  146. FILE_SHARE_READ | FILE_SHARE_WRITE,
  147. FILE_SYNCHRONOUS_IO_ALERT);
  148. FDLOG((1,"LowOpen: 2nd open 0x%x\n", status));
  149. }
  150. RtlFreeUnicodeString(&unicodeName);
  151. return status;
  152. }
  153. STATUS_CODE
  154. LowOpenDriveLetter(
  155. IN CHAR DriveLetter,
  156. IN HANDLE_PT Handle
  157. )
  158. /*++
  159. Routine Description:
  160. Given a drive letter, open it and return a handle.
  161. Arguments:
  162. DriveLetter - the letter to open
  163. Handle - a pointer to a handle
  164. Return Value:
  165. NT status
  166. --*/
  167. {
  168. char ntDeviceName[100];
  169. sprintf(ntDeviceName,
  170. "\\DosDevices\\%c:",
  171. DriveLetter);
  172. return LowOpenNtName(ntDeviceName, Handle);
  173. }
  174. STATUS_CODE
  175. LowOpenPartition(
  176. IN PCHAR DevicePath,
  177. IN ULONG Partition,
  178. OUT HANDLE_PT Handle
  179. )
  180. /*++
  181. Routine Description:
  182. Construct the NT device name for the Partition value given
  183. and perform the NT APIs to open the device.
  184. Arguments:
  185. DevicePath - the string to the device without the partition
  186. portion of the name. This is constructed using
  187. the Partition value passed
  188. Partition - the partion desired
  189. Handle - pointer to a handle pointer for the result
  190. Return Value:
  191. NT status
  192. --*/
  193. {
  194. char ntDeviceName[100];
  195. sprintf(ntDeviceName,
  196. "%s\\partition%u",
  197. DevicePath,
  198. Partition);
  199. return LowOpenNtName(ntDeviceName, Handle);
  200. }
  201. STATUS_CODE
  202. LowOpenDisk(
  203. IN PCHAR DevicePath,
  204. OUT HANDLE_PT DiskId
  205. )
  206. /*++
  207. Routine Description:
  208. Perform the NT actions to open a device.
  209. Arguments:
  210. DevicePath - Ascii device name
  211. DiskId - pointer to a handle pointer for the returned
  212. handle value
  213. Return Value:
  214. NT status
  215. --*/
  216. {
  217. return(LowOpenPartition(DevicePath, 0, DiskId));
  218. }
  219. STATUS_CODE
  220. LowCloseDisk(
  221. IN HANDLE_T DiskId
  222. )
  223. /*++
  224. Routine Description:
  225. Close a disk handle.
  226. Arguments:
  227. DiskId - the actual NT handle
  228. Return Value:
  229. NT status
  230. --*/
  231. {
  232. return(DmClose(DiskId));
  233. }
  234. STATUS_CODE
  235. LowLockDrive(
  236. IN HANDLE_T DiskId
  237. )
  238. /*++
  239. Routine Description:
  240. Perform the NT API to cause a volume to be locked.
  241. This is a File System device control.
  242. Arguments:
  243. DiskId - the actual NT handle to the drive
  244. Return Value:
  245. NT status
  246. --*/
  247. {
  248. NTSTATUS status;
  249. IO_STATUS_BLOCK statusBlock;
  250. status = NtFsControlFile(DiskId,
  251. 0,
  252. NULL,
  253. NULL,
  254. &statusBlock,
  255. FSCTL_LOCK_VOLUME,
  256. NULL,
  257. 0,
  258. NULL,
  259. 0);
  260. if (!NT_SUCCESS(status)) {
  261. FDLOG((1, "LowLock: failed with 0x%x\n", status));
  262. }
  263. return status;
  264. }
  265. STATUS_CODE
  266. LowUnlockDrive(
  267. IN HANDLE_T DiskId
  268. )
  269. /*++
  270. Routine Description:
  271. Perform the NT API to cause a volume to be unlocked.
  272. This is a File System device control.
  273. Arguments:
  274. DiskId - the actual NT handle to the drive
  275. Return Value:
  276. NT status
  277. --*/
  278. {
  279. NTSTATUS status;
  280. IO_STATUS_BLOCK statusBlock;
  281. status = NtFsControlFile(DiskId,
  282. 0,
  283. NULL,
  284. NULL,
  285. &statusBlock,
  286. FSCTL_DISMOUNT_VOLUME,
  287. NULL,
  288. 0,
  289. NULL,
  290. 0);
  291. status = NtFsControlFile(DiskId,
  292. 0,
  293. NULL,
  294. NULL,
  295. &statusBlock,
  296. FSCTL_UNLOCK_VOLUME,
  297. NULL,
  298. 0,
  299. NULL,
  300. 0);
  301. return status;
  302. }
  303. STATUS_CODE
  304. LowGetDriveGeometry(
  305. IN PCHAR Path,
  306. OUT PULONG TotalSectorCount,
  307. OUT PULONG SectorSize,
  308. OUT PULONG SectorsPerTrack,
  309. OUT PULONG Heads
  310. )
  311. /*++
  312. Routine Description:
  313. Routine collects information concerning the geometry
  314. of a specific drive.
  315. Arguments:
  316. Path - Ascii path name to get to disk object
  317. this is not a full path, but rather
  318. a path without the Partition indicator
  319. \device\harddiskX
  320. TotalSectorCount- pointer to ULONG for result
  321. SectorSize - pointer to ULONG for result
  322. SectorsPerTrack - pointer to ULONG for result
  323. Heads - pointer to ULONG for result
  324. Return Value:
  325. NT status
  326. --*/
  327. {
  328. IO_STATUS_BLOCK statusBlock;
  329. DISK_GEOMETRY diskGeometry;
  330. STATUS_CODE status;
  331. HANDLE handle;
  332. if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS) {
  333. return status;
  334. }
  335. status = NtDeviceIoControlFile(handle,
  336. 0,
  337. NULL,
  338. NULL,
  339. &statusBlock,
  340. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  341. NULL,
  342. 0,
  343. &diskGeometry,
  344. sizeof(DISK_GEOMETRY));
  345. if (!NT_SUCCESS(status)) {
  346. return (STATUS_CODE)status;
  347. }
  348. LowCloseDisk(handle);
  349. *SectorSize = diskGeometry.BytesPerSector;
  350. *SectorsPerTrack = diskGeometry.SectorsPerTrack;
  351. *Heads = diskGeometry.TracksPerCylinder;
  352. *TotalSectorCount = (RtlExtendedIntegerMultiply(diskGeometry.Cylinders,
  353. *SectorsPerTrack * *Heads)).LowPart;
  354. return(OK_STATUS);
  355. }
  356. STATUS_CODE
  357. LowGetDiskLayout(
  358. IN PCHAR Path,
  359. OUT PDRIVE_LAYOUT_INFORMATION *DriveLayout
  360. )
  361. /*++
  362. Routine Description:
  363. Perform the necessary NT API calls to get the drive
  364. layout from the disk and return it in a memory buffer
  365. allocated by this routine.
  366. Arguments:
  367. Path - Ascii path name to get to disk object
  368. this is not a full path, but rather
  369. a path without the Partition indicator
  370. \device\harddiskX
  371. DriveLayout - pointer to pointer for the drive layout result
  372. Return Value:
  373. NT status
  374. --*/
  375. {
  376. PDRIVE_LAYOUT_INFORMATION layout;
  377. IO_STATUS_BLOCK statusBlock;
  378. STATUS_CODE status;
  379. ULONG bufferSize;
  380. HANDLE handle;
  381. bufferSize = sizeof(DRIVE_LAYOUT_INFORMATION)
  382. + (500 * sizeof(PARTITION_INFORMATION));
  383. if ((layout = AllocateMemory(bufferSize)) == NULL) {
  384. RETURN_OUT_OF_MEMORY;
  385. }
  386. if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS) {
  387. FreeMemory(layout);
  388. return status;
  389. }
  390. status = NtDeviceIoControlFile(handle,
  391. 0,
  392. NULL,
  393. NULL,
  394. &statusBlock,
  395. IOCTL_DISK_GET_DRIVE_LAYOUT,
  396. NULL,
  397. 0,
  398. layout,
  399. bufferSize);
  400. LowCloseDisk(handle);
  401. if (!NT_SUCCESS(status)) {
  402. if (status == STATUS_BAD_MASTER_BOOT_RECORD) {
  403. FDLOG((1,"LowGetDiskLayout: Disk device %s has bad MBR\n",Path));
  404. // Zero the drive layout information for the fdengine to process.
  405. RtlZeroMemory(layout, bufferSize);
  406. } else {
  407. FDLOG((0,"LowGetDiskLayout: Status %lx getting layout for disk device %s\n",status,Path));
  408. FreeMemory(layout);
  409. return status;
  410. }
  411. } else {
  412. FDLOG((2,"LowGetDiskLayout: layout received from ioctl for %s follows:\n",Path));
  413. LOG_DRIVE_LAYOUT(layout);
  414. }
  415. // Check to insure that the drive supports dynamic partitioning.
  416. *DriveLayout = layout;
  417. return OK_STATUS;
  418. }
  419. STATUS_CODE
  420. LowSetDiskLayout(
  421. IN PCHAR Path,
  422. IN PDRIVE_LAYOUT_INFORMATION DriveLayout
  423. )
  424. /*++
  425. Routine Description:
  426. Perform the NT API actions of opening Partition0 for
  427. the specified drive and setting the drive layout.
  428. Arguments:
  429. Path - Ascii path name to get to disk object
  430. this is not a full path, but rather
  431. a path without the Partition indicator
  432. \device\harddiskX
  433. DriveLayout - new layout to set
  434. Return Value:
  435. NT status
  436. --*/
  437. {
  438. IO_STATUS_BLOCK statusBlock;
  439. STATUS_CODE status;
  440. HANDLE handle;
  441. ULONG bufferSize;
  442. if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS) {
  443. return status;
  444. } else {
  445. FDLOG((2, "LowSetDiskLayout: calling ioctl for %s, layout follows:\n", Path));
  446. LOG_DRIVE_LAYOUT(DriveLayout);
  447. }
  448. bufferSize = sizeof(DRIVE_LAYOUT_INFORMATION)
  449. + ( (DriveLayout->PartitionCount - 1)
  450. * sizeof(PARTITION_INFORMATION));
  451. status = NtDeviceIoControlFile(handle,
  452. 0,
  453. NULL,
  454. NULL,
  455. &statusBlock,
  456. IOCTL_DISK_SET_DRIVE_LAYOUT,
  457. DriveLayout,
  458. bufferSize,
  459. DriveLayout,
  460. bufferSize);
  461. LowCloseDisk(handle);
  462. return status;
  463. }
  464. STATUS_CODE
  465. LowWriteSectors(
  466. IN HANDLE_T VolumeId,
  467. IN ULONG SectorSize,
  468. IN ULONG StartingSector,
  469. IN ULONG NumberOfSectors,
  470. IN PVOID Buffer
  471. )
  472. /*++
  473. Routine Description:
  474. Routine to write to a volume handle. This routine
  475. insulates the NT issues concerning the call from the
  476. caller.
  477. Arguments:
  478. VolumeId - actually the NT handle.
  479. SectorSize - used to calculate starting byte offset for I/O
  480. StartingSector - starting sector for write.
  481. NumberOfSectors - size of I/O in sectors
  482. Buffer - the location for the data
  483. Return Value:
  484. Standard NT status values
  485. --*/
  486. {
  487. IO_STATUS_BLOCK statusBlock;
  488. LARGE_INTEGER byteOffset;
  489. byteOffset = RtlExtendedIntegerMultiply(RtlConvertUlongToLargeInteger(StartingSector), (LONG)SectorSize);
  490. statusBlock.Status = 0;
  491. statusBlock.Information = 0;
  492. return(NtWriteFile(VolumeId,
  493. 0,
  494. NULL,
  495. NULL,
  496. &statusBlock,
  497. Buffer,
  498. NumberOfSectors * SectorSize,
  499. &byteOffset,
  500. NULL));
  501. }
  502. STATUS_CODE
  503. LowReadSectors(
  504. IN HANDLE_T VolumeId,
  505. IN ULONG SectorSize,
  506. IN ULONG StartingSector,
  507. IN ULONG NumberOfSectors,
  508. IN PVOID Buffer
  509. )
  510. /*++
  511. Routine Description:
  512. Routine to read from a volume handle. This routine
  513. insulates the NT issues concerning the call from the
  514. caller.
  515. Arguments:
  516. VolumeId - actually the NT handle.
  517. SectorSize - used to calculate starting byte offset for I/O
  518. StartingSector - starting sector for write.
  519. NumberOfSectors - size of I/O in sectors
  520. Buffer - the location for the data
  521. Return Value:
  522. Standard NT status values
  523. --*/
  524. {
  525. IO_STATUS_BLOCK statusBlock;
  526. LARGE_INTEGER byteOffset;
  527. byteOffset = RtlExtendedIntegerMultiply(RtlConvertUlongToLargeInteger(StartingSector), (LONG)SectorSize);
  528. statusBlock.Status = 0;
  529. statusBlock.Information = 0;
  530. return(NtReadFile(VolumeId,
  531. 0,
  532. NULL,
  533. NULL,
  534. &statusBlock,
  535. Buffer,
  536. NumberOfSectors * SectorSize,
  537. &byteOffset,
  538. NULL));
  539. }
  540. STATUS_CODE
  541. LowFtVolumeStatus(
  542. IN ULONG Disk,
  543. IN ULONG Partition,
  544. IN PFT_SET_STATUS FtStatus,
  545. IN PULONG NumberOfMembers
  546. )
  547. /*++
  548. Routine Description:
  549. Open the requested partition and query the FT state.
  550. Arguments:
  551. DriveLetter - the letter for the current state
  552. FtState - a pointer to a location to return state
  553. NumberOfMembers - a pointer to a ULONG for number of members
  554. in the FT set.
  555. Return Value:
  556. Standard NT status values
  557. --*/
  558. {
  559. HANDLE handle;
  560. STATUS_CODE status;
  561. IO_STATUS_BLOCK statusBlock;
  562. FT_SET_INFORMATION setInfo;
  563. status = LowOpenPartition(GetDiskName(Disk),
  564. Partition,
  565. &handle);
  566. if (status == OK_STATUS) {
  567. status = NtDeviceIoControlFile(handle,
  568. 0,
  569. NULL,
  570. NULL,
  571. &statusBlock,
  572. FT_QUERY_SET_STATE,
  573. NULL,
  574. 0,
  575. &setInfo,
  576. sizeof(setInfo));
  577. LowCloseDisk(handle);
  578. if (status == OK_STATUS) {
  579. switch (setInfo.SetState) {
  580. case FtStateOk:
  581. *FtStatus = FtSetHealthy;
  582. break;
  583. case FtHasOrphan:
  584. switch (setInfo.Type) {
  585. case Mirror:
  586. *FtStatus = FtSetBroken;
  587. break;
  588. case StripeWithParity:
  589. *FtStatus = FtSetRecoverable;
  590. break;
  591. }
  592. break;
  593. case FtRegenerating:
  594. *FtStatus = FtSetRegenerating;
  595. break;
  596. case FtCheckParity:
  597. *FtStatus = FtSetInitializationFailed;
  598. break;
  599. case FtInitializing:
  600. *FtStatus = FtSetInitializing;
  601. break;
  602. case FtDisabled:
  603. // This will never happen.
  604. *FtStatus = FtSetDisabled;
  605. break;
  606. case FtNoCheckData:
  607. default:
  608. // BUGBUG: there is no mapping here.
  609. *FtStatus = FtSetHealthy;
  610. break;
  611. }
  612. *NumberOfMembers = setInfo.NumberOfMembers;
  613. }
  614. } else {
  615. // If the FT set could not be opened, then it must be
  616. // disabled if the return code is "No such device".
  617. if (status == 0xc000000e) {
  618. *FtStatus = FtSetDisabled;
  619. status = OK_STATUS;
  620. }
  621. }
  622. // Always update the state to the caller.
  623. return status;
  624. }
  625. STATUS_CODE
  626. LowFtVolumeStatusByLetter(
  627. IN CHAR DriveLetter,
  628. IN PFT_SET_STATUS FtStatus,
  629. IN PULONG NumberOfMembers
  630. )
  631. /*++
  632. Routine Description:
  633. Open the requested drive letter and query the FT state.
  634. Arguments:
  635. DriveLetter - the letter for the current state
  636. FtState - a pointer to a location to return state
  637. NumberOfMembers - a pointer to a ULONG for number of members
  638. in the FT set.
  639. Return Value:
  640. Standard NT status values
  641. --*/
  642. {
  643. HANDLE handle;
  644. STATUS_CODE status;
  645. IO_STATUS_BLOCK statusBlock;
  646. FT_SET_INFORMATION setInfo;
  647. *NumberOfMembers = 1;
  648. status = LowOpenDriveLetter(DriveLetter,
  649. &handle);
  650. if (status == OK_STATUS) {
  651. status = NtDeviceIoControlFile(handle,
  652. 0,
  653. NULL,
  654. NULL,
  655. &statusBlock,
  656. FT_QUERY_SET_STATE,
  657. NULL,
  658. 0,
  659. &setInfo,
  660. sizeof(setInfo));
  661. LowCloseDisk(handle);
  662. if (status == OK_STATUS) {
  663. switch (setInfo.SetState) {
  664. case FtStateOk:
  665. *FtStatus = FtSetHealthy;
  666. break;
  667. case FtHasOrphan:
  668. switch (setInfo.Type) {
  669. case Mirror:
  670. *FtStatus = FtSetBroken;
  671. break;
  672. case StripeWithParity:
  673. *FtStatus = FtSetRecoverable;
  674. break;
  675. }
  676. break;
  677. case FtRegenerating:
  678. *FtStatus = FtSetRegenerating;
  679. break;
  680. case FtCheckParity:
  681. *FtStatus = FtSetInitializationFailed;
  682. break;
  683. case FtInitializing:
  684. *FtStatus = FtSetInitializing;
  685. break;
  686. case FtDisabled:
  687. // This will never happen.
  688. *FtStatus = FtSetDisabled;
  689. break;
  690. case FtNoCheckData:
  691. default:
  692. // BUGBUG: there is no mapping here.
  693. *FtStatus = FtSetHealthy;
  694. break;
  695. }
  696. *NumberOfMembers = setInfo.NumberOfMembers;
  697. }
  698. } else {
  699. // If the FT set could not be opened, then it must be
  700. // disabled if the return code is "No such device".
  701. if (status == 0xc000000e) {
  702. *FtStatus = FtSetDisabled;
  703. status = OK_STATUS;
  704. }
  705. }
  706. // Always update the state to the caller.
  707. return status;
  708. }
  709. #define NUMBER_OF_HANDLES_TRACKED 500
  710. HANDLE OpenHandleArray[NUMBER_OF_HANDLES_TRACKED];
  711. BOOLEAN DmFirstTime = TRUE;
  712. ULONG HandleHighWaterMark = 0;
  713. NTSTATUS
  714. DmOpenFile(
  715. OUT PHANDLE FileHandle,
  716. IN ACCESS_MASK DesiredAccess,
  717. IN POBJECT_ATTRIBUTES ObjectAttributes,
  718. OUT PIO_STATUS_BLOCK IoStatusBlock,
  719. IN ULONG ShareAccess,
  720. IN ULONG OpenOptions
  721. )
  722. /*++
  723. Routine Description:
  724. A debugging aid to track open and closes of partitions.
  725. Arguments:
  726. Same as for NtOpenFile()
  727. Return Value:
  728. Same as for NtOpenFile()
  729. --*/
  730. {
  731. ULONG index;
  732. NTSTATUS status;
  733. if (DmFirstTime) {
  734. DmFirstTime = FALSE;
  735. for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++) {
  736. OpenHandleArray[index] = (HANDLE) 0;
  737. }
  738. }
  739. status = NtOpenFile(FileHandle,
  740. DesiredAccess,
  741. ObjectAttributes,
  742. IoStatusBlock,
  743. ShareAccess,
  744. OpenOptions);
  745. if (NT_SUCCESS(status)) {
  746. for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++) {
  747. if (OpenHandleArray[index] == (HANDLE) 0) {
  748. OpenHandleArray[index] = *FileHandle;
  749. if (index > HandleHighWaterMark) {
  750. HandleHighWaterMark = index;
  751. }
  752. break;
  753. }
  754. }
  755. }
  756. return status;
  757. }
  758. NTSTATUS
  759. DmClose(
  760. IN HANDLE Handle
  761. )
  762. /*++
  763. Routine Description:
  764. A debugging aid for tracking open and closes
  765. Arguments:
  766. Same as for NtClose()
  767. Return Value:
  768. Same as for NtClose()
  769. --*/
  770. {
  771. ULONG index;
  772. for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++) {
  773. if (OpenHandleArray[index] == Handle) {
  774. OpenHandleArray[index] = (HANDLE) 0;
  775. break;
  776. }
  777. }
  778. return NtClose(Handle);
  779. }