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.

3734 lines
85 KiB

  1. /*++
  2. Copyright (c) 1991-1994 Microsoft Corporation
  3. Module Name:
  4. fdengine.c
  5. Abstract:
  6. This module contains the disk partitioning engine. The code
  7. in this module can be compiled for either the NT platform
  8. or the ARC platform (-DARC).
  9. Author:
  10. Ted Miller (tedm) Nov-1991
  11. Revision History:
  12. Bob Rinne (bobri) Feb-1994
  13. Moved as actual part of Disk Administrator enlistment instead of being
  14. copied from ArcInst. This is due to dynamic partition changes. Removed
  15. string table that made this an internationalized file.
  16. --*/
  17. #include "fdisk.h"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. // Attached disk devices.
  21. ULONG CountOfDisks;
  22. PCHAR *DiskNames;
  23. // Information about attached disks.
  24. DISKGEOM *DiskGeometryArray;
  25. PPARTITION *PrimaryPartitions,
  26. *LogicalVolumes;
  27. // A 'signature' is a unique 4-byte value immediately preceeding the
  28. // partition table in the MBR.
  29. PULONG Signatures;
  30. // Array keeping track of whether each disk is off line.
  31. PBOOLEAN OffLine;
  32. // Keeps track of whether changes have been requested
  33. // to each disk's partition structure.
  34. BOOLEAN *ChangesRequested;
  35. BOOLEAN *ChangesCommitted;
  36. // Value used to indicate that the partition entry has changed but in a non-
  37. // destructive way (ie, made active/inactive).
  38. #define CHANGED_DONT_ZAP ((BOOLEAN)(5))
  39. // forward declarations
  40. STATUS_CODE
  41. OpenDisks(
  42. VOID
  43. );
  44. VOID
  45. CloseDisks(
  46. VOID
  47. );
  48. STATUS_CODE
  49. GetGeometry(
  50. VOID
  51. );
  52. BOOLEAN
  53. CheckIfDiskIsOffLine(
  54. IN ULONG Disk
  55. );
  56. STATUS_CODE
  57. InitializePartitionLists(
  58. VOID
  59. );
  60. STATUS_CODE
  61. GetRegions(
  62. IN ULONG Disk,
  63. IN PPARTITION p,
  64. IN BOOLEAN WantUsedRegions,
  65. IN BOOLEAN WantFreeRegions,
  66. IN BOOLEAN WantLogicalRegions,
  67. OUT PREGION_DESCRIPTOR *Region,
  68. OUT ULONG *RegionCount,
  69. IN REGION_TYPE RegionType
  70. );
  71. BOOLEAN
  72. AddRegionEntry(
  73. IN OUT PREGION_DESCRIPTOR *Regions,
  74. IN OUT ULONG *RegionCount,
  75. IN ULONG SizeMB,
  76. IN REGION_TYPE RegionType,
  77. IN PPARTITION Partition,
  78. IN LARGE_INTEGER AlignedRegionOffset,
  79. IN LARGE_INTEGER AlignedRegionSize
  80. );
  81. VOID
  82. AddPartitionToLinkedList(
  83. IN PARTITION **Head,
  84. IN PARTITION *p
  85. );
  86. BOOLEAN
  87. IsInLinkedList(
  88. IN PPARTITION p,
  89. IN PPARTITION List
  90. );
  91. BOOLEAN
  92. IsInLogicalList(
  93. IN ULONG Disk,
  94. IN PPARTITION p
  95. );
  96. BOOLEAN
  97. IsInPartitionList(
  98. IN ULONG Disk,
  99. IN PPARTITION p
  100. );
  101. LARGE_INTEGER
  102. AlignTowardsDiskStart(
  103. IN ULONG Disk,
  104. IN LARGE_INTEGER Offset
  105. );
  106. LARGE_INTEGER
  107. AlignTowardsDiskEnd(
  108. IN ULONG Disk,
  109. IN LARGE_INTEGER Offset
  110. );
  111. VOID
  112. FreeLinkedPartitionList(
  113. IN PARTITION **q
  114. );
  115. VOID
  116. MergeFreePartitions(
  117. IN PPARTITION p
  118. );
  119. VOID
  120. FreePartitionInfoLinkedLists(
  121. IN PARTITION **ListHeadArray
  122. );
  123. LARGE_INTEGER
  124. DiskLengthBytes(
  125. IN ULONG Disk
  126. );
  127. PPARTITION
  128. AllocatePartitionStructure(
  129. IN ULONG Disk,
  130. IN LARGE_INTEGER Offset,
  131. IN LARGE_INTEGER Length,
  132. IN UCHAR SysID,
  133. IN BOOLEAN Update,
  134. IN BOOLEAN Active,
  135. IN BOOLEAN Recognized
  136. );
  137. STATUS_CODE
  138. LowFreeFdiskPathList(
  139. IN OUT PCHAR* PathList,
  140. IN ULONG ListLength
  141. );
  142. STATUS_CODE
  143. LowQueryFdiskPathList(
  144. OUT PCHAR **PathList,
  145. OUT PULONG ListLength
  146. );
  147. STATUS_CODE
  148. FdiskInitialize(
  149. VOID
  150. )
  151. /*++
  152. Routine Description:
  153. This routine initializes the partitioning engine, including allocating
  154. arrays, determining attached disk devices, and reading their
  155. partition tables.
  156. Arguments:
  157. None.
  158. Return Value:
  159. OK_STATUS or error code.
  160. --*/
  161. {
  162. STATUS_CODE status;
  163. ULONG i;
  164. if ((status = LowQueryFdiskPathList(&DiskNames, &CountOfDisks)) != OK_STATUS) {
  165. return status;
  166. }
  167. DiskGeometryArray = NULL;
  168. PrimaryPartitions = NULL;
  169. LogicalVolumes = NULL;
  170. if (((DiskGeometryArray = AllocateMemory(CountOfDisks * sizeof(DISKGEOM ))) == NULL)
  171. || ((ChangesRequested = AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
  172. || ((ChangesCommitted = AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
  173. || ((PrimaryPartitions = AllocateMemory(CountOfDisks * sizeof(PPARTITION))) == NULL)
  174. || ((Signatures = AllocateMemory(CountOfDisks * sizeof(ULONG ))) == NULL)
  175. || ((OffLine = AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
  176. || ((LogicalVolumes = AllocateMemory(CountOfDisks * sizeof(PPARTITION))) == NULL))
  177. {
  178. RETURN_OUT_OF_MEMORY;
  179. }
  180. for (i=0; i<CountOfDisks; i++) {
  181. PrimaryPartitions[i] = NULL;
  182. LogicalVolumes[i] = NULL;
  183. ChangesRequested[i] = FALSE;
  184. ChangesCommitted[i] = FALSE;
  185. OffLine[i] = CheckIfDiskIsOffLine(i);
  186. }
  187. if (((status = GetGeometry() ) != OK_STATUS)
  188. || ((status = InitializePartitionLists()) != OK_STATUS)) {
  189. return status;
  190. }
  191. return OK_STATUS;
  192. }
  193. VOID
  194. FdiskCleanUp(
  195. VOID
  196. )
  197. /*++
  198. Routine Description:
  199. This routine deallocates storage used by the partitioning engine.
  200. Arguments:
  201. None.
  202. Return Value:
  203. None.
  204. --*/
  205. {
  206. LowFreeFdiskPathList(DiskNames, CountOfDisks);
  207. if (DiskGeometryArray != NULL) {
  208. FreeMemory(DiskGeometryArray);
  209. }
  210. if (PrimaryPartitions != NULL) {
  211. FreePartitionInfoLinkedLists(PrimaryPartitions);
  212. FreeMemory(PrimaryPartitions);
  213. }
  214. if (LogicalVolumes != NULL) {
  215. FreePartitionInfoLinkedLists(LogicalVolumes);
  216. FreeMemory(LogicalVolumes);
  217. }
  218. if (ChangesRequested != NULL) {
  219. FreeMemory(ChangesRequested);
  220. }
  221. if (ChangesCommitted != NULL) {
  222. FreeMemory(ChangesCommitted);
  223. }
  224. if (OffLine != NULL) {
  225. FreeMemory(OffLine);
  226. }
  227. if (Signatures != NULL) {
  228. FreeMemory(Signatures);
  229. }
  230. }
  231. BOOLEAN
  232. CheckIfDiskIsOffLine(
  233. IN ULONG Disk
  234. )
  235. /*++
  236. Routine Description:
  237. Determine whether a disk is off-line by attempting to open it.
  238. If this is diskman, also attempt to read from it.
  239. Arguments:
  240. Disk - supplies number of the disk to check
  241. Return Value:
  242. TRUE if disk is off-line, FALSE is disk is on-line.
  243. --*/
  244. {
  245. HANDLE_T handle;
  246. UINT errorMode;
  247. BOOLEAN isOffLine = TRUE;
  248. errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  249. if (LowOpenDisk(GetDiskName(Disk), &handle) == OK_STATUS) {
  250. ULONG dummy,
  251. bps;
  252. PVOID unalignedBuffer,
  253. buffer;
  254. // The open might succeed even if the disk is off line. So to be
  255. // sure, read the first sector from the disk.
  256. if (NT_SUCCESS(LowGetDriveGeometry(GetDiskName(Disk), &dummy, &bps, &dummy, &dummy))) {
  257. unalignedBuffer = Malloc(2*bps);
  258. buffer = (PVOID)(((ULONG)unalignedBuffer+bps) & ~(bps-1));
  259. if (NT_SUCCESS(LowReadSectors(handle,bps,0,1,buffer))) {
  260. isOffLine = FALSE;
  261. }
  262. Free(unalignedBuffer);
  263. } else {
  264. // It is possible this is a removable drive.
  265. if (IsRemovable(Disk)) {
  266. isOffLine = FALSE;
  267. }
  268. }
  269. LowCloseDisk(handle);
  270. }
  271. SetErrorMode(errorMode);
  272. return isOffLine;
  273. }
  274. STATUS_CODE
  275. GetGeometry(
  276. VOID
  277. )
  278. /*++
  279. Routine Description:
  280. This routine determines disk geometry for each disk device.
  281. Disk geometry includes heads, sectors per track, cylinder count,
  282. and bytes per sector. It also includes bytes per track and
  283. bytes per cylinder, which are calculated from the other values
  284. for the convenience of the rest of this module.
  285. Geometry information is placed in the DiskGeometryArray global variable.
  286. Geometry information is undefined for an off-line disk.
  287. Arguments:
  288. None.
  289. Return Value:
  290. OK_STATUS or error code.
  291. --*/
  292. {
  293. ULONG i;
  294. STATUS_CODE status;
  295. ULONG TotalSectorCount,
  296. SectorSize,
  297. SectorsPerTrack,
  298. Heads;
  299. for (i=0; i<CountOfDisks; i++) {
  300. if (OffLine[i]) {
  301. continue;
  302. }
  303. if ((status = LowGetDriveGeometry(DiskNames[i],&TotalSectorCount,&SectorSize,&SectorsPerTrack,&Heads)) != OK_STATUS) {
  304. return(status);
  305. }
  306. DiskGeometryArray[i].BytesPerSector = SectorSize;
  307. DiskGeometryArray[i].SectorsPerTrack = SectorsPerTrack;
  308. DiskGeometryArray[i].Heads = Heads;
  309. DiskGeometryArray[i].Cylinders.QuadPart = (TotalSectorCount / (SectorsPerTrack * Heads));
  310. DiskGeometryArray[i].BytesPerTrack = SectorsPerTrack * SectorSize;
  311. DiskGeometryArray[i].BytesPerCylinder = SectorsPerTrack * SectorSize * Heads;
  312. }
  313. return(OK_STATUS);
  314. }
  315. #if i386
  316. VOID
  317. SetPartitionActiveFlag(
  318. IN PREGION_DESCRIPTOR Region,
  319. IN UCHAR value
  320. )
  321. /*++
  322. Routine Description:
  323. Arguments:
  324. Return Value:
  325. --*/
  326. {
  327. PPARTITION p = ((PREGION_DATA)Region->Reserved)->Partition;
  328. if((UCHAR)p->Active != value) {
  329. //
  330. // Unfortuneately, the Update flag becomes the RewritePartition flag
  331. // at commit time. This causes us to zap the boot sector. To avoid
  332. // this, we use a spacial non-boolean value that can be checked for
  333. // at commit time and that will cause us NOT to zap the bootsector
  334. // even though RewritePartition will be TRUE.
  335. //
  336. p->Active = value;
  337. if(!p->Update) {
  338. p->Update = CHANGED_DONT_ZAP;
  339. }
  340. ChangesRequested[p->Disk] = TRUE;
  341. }
  342. }
  343. #endif
  344. VOID
  345. DetermineCreateSizeAndOffset(
  346. IN PREGION_DESCRIPTOR Region,
  347. IN LARGE_INTEGER MinimumSize,
  348. IN ULONG CreationSizeMB,
  349. IN REGION_TYPE Type,
  350. OUT PLARGE_INTEGER CreationStart,
  351. OUT PLARGE_INTEGER CreationSize
  352. )
  353. /*++
  354. Routine Description:
  355. Determine the actual offset and size of the partition, given the
  356. size in megabytes.
  357. Arguments:
  358. Region - a region descriptor returned by GetDiskRegions(). Must
  359. be an unused region.
  360. MinimumSize - if non-0, this is the minimum size that the partition
  361. or logical drive can be.
  362. CreationSizeMB - If MinimumSize is 0, size of partition to create, in MB.
  363. Type - REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL, for
  364. creating a primary partition, extended partition, or
  365. logical volume, respectively.
  366. CreationStart - receives the offset where the partition should be placed.
  367. CreationSize - receives the exact size for the partition.
  368. Return Value:
  369. None.
  370. --*/
  371. {
  372. PREGION_DATA createData = Region->Reserved;
  373. ULONG bpc = DiskGeometryArray[Region->Disk].BytesPerCylinder;
  374. ULONG bpt = DiskGeometryArray[Region->Disk].BytesPerTrack;
  375. LARGE_INTEGER cSize,
  376. cStart,
  377. mod;
  378. //
  379. // If we are creating a partition at offset 0, adjust the aligned region
  380. // offset and the aligned region size, because no partition can actually
  381. // start at offset 0.
  382. //
  383. if (!createData->AlignedRegionOffset.QuadPart) {
  384. LARGE_INTEGER delta;
  385. if (Type == REGION_EXTENDED) {
  386. delta.QuadPart = bpc;
  387. } else {
  388. delta.QuadPart = bpt;
  389. }
  390. createData->AlignedRegionOffset = delta;
  391. createData->AlignedRegionSize.QuadPart -= delta.QuadPart;
  392. }
  393. cStart = createData->AlignedRegionOffset;
  394. if (!MinimumSize.QuadPart) {
  395. cSize.QuadPart = UInt32x32To64(CreationSizeMB, ONE_MEG);
  396. } else {
  397. cSize = MinimumSize;
  398. if (Type == REGION_LOGICAL) {
  399. cSize.QuadPart += bpt;
  400. }
  401. }
  402. //
  403. // Decide whether to align the ending cylinder up or down.
  404. // If the offset of end of the partition is more than half way into the
  405. // final cylinder, align towrds the disk end. Otherwise align toward
  406. // the disk start.
  407. //
  408. mod.QuadPart = (cStart.QuadPart + cSize.QuadPart) % bpc;
  409. if (mod.QuadPart) {
  410. if ((MinimumSize.QuadPart) || (mod.QuadPart > (bpc/2))) {
  411. cSize.QuadPart += ((LONGLONG)bpc - mod.QuadPart);
  412. } else {
  413. cSize.QuadPart -= mod.QuadPart; // snap downwards to cyl boundary
  414. }
  415. }
  416. if (cSize.QuadPart > createData->AlignedRegionSize.QuadPart) {
  417. //
  418. // Space available in the free space isn't large enough to accomodate
  419. // the request; just use the entire free space.
  420. //
  421. cSize = createData->AlignedRegionSize;
  422. }
  423. *CreationStart = cStart;
  424. *CreationSize = cSize;
  425. }
  426. STATUS_CODE
  427. CreatePartitionEx(
  428. IN PREGION_DESCRIPTOR Region,
  429. IN LARGE_INTEGER MinimumSize,
  430. IN ULONG CreationSizeMB,
  431. IN REGION_TYPE Type,
  432. IN UCHAR SysId
  433. )
  434. /*++
  435. Routine Description:
  436. This routine creates a partition from a free region on the disk. The
  437. partition is always created at the beginning of the free space, and any
  438. left over space at the end is kept on the free space list.
  439. Arguments:
  440. Region - a region descriptor returned by GetDiskRegions(). Must
  441. be an unused region.
  442. CreationSizeMB - size of partition to create, in MB.
  443. Type - REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL, for
  444. creating a primary partition, extended pasrtition, or
  445. logical volume, respectively.
  446. SysId - system ID byte to be assigned to the partition
  447. Return Value:
  448. OK_STATUS or error code.
  449. --*/
  450. {
  451. PPARTITION p1,
  452. p2,
  453. p3;
  454. PREGION_DATA createData = Region->Reserved;
  455. LARGE_INTEGER creationStart,
  456. creationSize,
  457. leftOver,
  458. offset,
  459. length;
  460. PPARTITION *partitionList;
  461. DetermineCreateSizeAndOffset(Region,
  462. MinimumSize,
  463. CreationSizeMB,
  464. Type,
  465. &creationStart,
  466. &creationSize);
  467. // now we've got the start and size of the partition to be created.
  468. // If there's left-over at the beginning of the free space (after
  469. // alignment), make a new PARTITION structure.
  470. p1 = NULL;
  471. offset = createData->Partition->Offset;
  472. length = createData->Partition->Length;
  473. leftOver.QuadPart = creationStart.QuadPart - offset.QuadPart;
  474. if (leftOver.QuadPart > 0) {
  475. p1 = AllocatePartitionStructure(Region->Disk,
  476. createData->Partition->Offset,
  477. leftOver,
  478. SYSID_UNUSED,
  479. FALSE,
  480. FALSE,
  481. FALSE);
  482. if (p1 == NULL) {
  483. RETURN_OUT_OF_MEMORY;
  484. }
  485. }
  486. // make a new partition structure for space being left free as
  487. // a result of this creation.
  488. p2 = NULL;
  489. leftOver.QuadPart = (offset.QuadPart + length.QuadPart) -
  490. (creationStart.QuadPart + creationSize.QuadPart);
  491. if (leftOver.QuadPart) {
  492. LARGE_INTEGER temp;
  493. temp.QuadPart = creationStart.QuadPart + creationSize.QuadPart;
  494. p2 = AllocatePartitionStructure(Region->Disk,
  495. temp,
  496. leftOver,
  497. SYSID_UNUSED,
  498. FALSE,
  499. FALSE,
  500. FALSE);
  501. if (p2 == NULL) {
  502. RETURN_OUT_OF_MEMORY;
  503. }
  504. }
  505. // adjust the free partition's fields.
  506. createData->Partition->Offset = creationStart;
  507. createData->Partition->Length = creationSize;
  508. createData->Partition->SysID = SysId;
  509. createData->Partition->Update = TRUE;
  510. createData->Partition->Recognized = TRUE;
  511. // if we just created an extended partition, show the whole thing
  512. // as one free logical region.
  513. if (Type == REGION_EXTENDED) {
  514. p3 = AllocatePartitionStructure(Region->Disk,
  515. creationStart,
  516. creationSize,
  517. SYSID_UNUSED,
  518. FALSE,
  519. FALSE,
  520. FALSE);
  521. if (p3 == NULL) {
  522. RETURN_OUT_OF_MEMORY;
  523. }
  524. AddPartitionToLinkedList(&LogicalVolumes[Region->Disk], p3);
  525. }
  526. partitionList = (Type == REGION_LOGICAL)
  527. ? &LogicalVolumes[Region->Disk]
  528. : &PrimaryPartitions[Region->Disk];
  529. if (p1) {
  530. AddPartitionToLinkedList(partitionList, p1);
  531. }
  532. if (p2) {
  533. AddPartitionToLinkedList(partitionList, p2);
  534. }
  535. MergeFreePartitions(*partitionList);
  536. ChangesRequested[Region->Disk] = TRUE;
  537. return(OK_STATUS);
  538. }
  539. STATUS_CODE
  540. CreatePartition(
  541. IN PREGION_DESCRIPTOR Region,
  542. IN ULONG CreationSizeMB,
  543. IN REGION_TYPE Type
  544. )
  545. /*++
  546. Routine Description:
  547. Create a partition.
  548. Arguments:
  549. Region - A region descriptor pointer.
  550. CreationSizeMB - the size for the new region.
  551. Type - the type of region being created.
  552. Return Value:
  553. OK_STATUS or error code
  554. --*/
  555. {
  556. LARGE_INTEGER zero;
  557. zero.QuadPart = 0;
  558. return CreatePartitionEx(Region,
  559. zero,
  560. CreationSizeMB,
  561. Type,
  562. (UCHAR)((Type == REGION_EXTENDED) ? SYSID_EXTENDED
  563. : SYSID_BIGFAT));
  564. }
  565. STATUS_CODE
  566. DeletePartition(
  567. IN PREGION_DESCRIPTOR Region
  568. )
  569. /*++
  570. Routine Description:
  571. This routine deletes a partition, returning its space to the
  572. free space on the disk. If deleting the extended partition,
  573. all logical volumes within it are also deleted.
  574. Arguments:
  575. Region - a region descriptor returned by GetDiskRegions(). Must
  576. be a used region.
  577. Return Value:
  578. OK_STATUS or error code.
  579. --*/
  580. {
  581. PREGION_DATA RegionData = Region->Reserved;
  582. PPARTITION *PartitionList;
  583. if(IsExtended(Region->SysID)) {
  584. // Deleting extended partition. Also delete all logical volumes.
  585. FreeLinkedPartitionList(&LogicalVolumes[Region->Disk]);
  586. }
  587. RegionData->Partition->SysID = SYSID_UNUSED;
  588. RegionData->Partition->Update = TRUE;
  589. RegionData->Partition->Active = FALSE;
  590. RegionData->Partition->OriginalPartitionNumber = 0;
  591. PartitionList = (Region->RegionType == REGION_LOGICAL)
  592. ? &LogicalVolumes[Region->Disk]
  593. : &PrimaryPartitions[Region->Disk];
  594. MergeFreePartitions(*PartitionList);
  595. ChangesRequested[Region->Disk] = TRUE;
  596. return OK_STATUS;
  597. }
  598. STATUS_CODE
  599. GetDiskRegions(
  600. IN ULONG Disk,
  601. IN BOOLEAN WantUsedRegions,
  602. IN BOOLEAN WantFreeRegions,
  603. IN BOOLEAN WantPrimaryRegions,
  604. IN BOOLEAN WantLogicalRegions,
  605. OUT PREGION_DESCRIPTOR *Region,
  606. OUT ULONG *RegionCount
  607. )
  608. /*++
  609. Routine Description:
  610. This routine returns an array of region descriptors to the caller.
  611. A region desscriptor describes a space on the disk, either used
  612. or free. The caller can control which type of regions are returned.
  613. The caller must free the returned array via FreeRegionArray().
  614. Arguments:
  615. Disk - index of disk whose regions are to be returned
  616. WantUsedRegions - whether to return used disk regions
  617. WantFreeRegions - whether to return free disk regions
  618. WantPrimaryRegions - whether to return regions not in the
  619. extended partition
  620. WantLogicalRegions - whether to return regions within the
  621. extended partition
  622. Region - where to put a pointer to the array of regions
  623. RegionCount - where to put the number of items in the returned
  624. Region array
  625. Return Value:
  626. OK_STATUS or error code.
  627. --*/
  628. {
  629. *Region = AllocateMemory(0);
  630. *RegionCount = 0;
  631. if (WantPrimaryRegions) {
  632. return GetRegions(Disk,
  633. PrimaryPartitions[Disk],
  634. WantUsedRegions,
  635. WantFreeRegions,
  636. WantLogicalRegions,
  637. Region,
  638. RegionCount,
  639. REGION_PRIMARY);
  640. } else if (WantLogicalRegions) {
  641. return GetRegions(Disk,
  642. LogicalVolumes[Disk],
  643. WantUsedRegions,
  644. WantFreeRegions,
  645. FALSE,
  646. Region,
  647. RegionCount,
  648. REGION_LOGICAL);
  649. }
  650. return OK_STATUS;
  651. }
  652. // workers for GetDiskRegions
  653. STATUS_CODE
  654. GetRegions(
  655. IN ULONG Disk,
  656. IN PPARTITION p,
  657. IN BOOLEAN WantUsedRegions,
  658. IN BOOLEAN WantFreeRegions,
  659. IN BOOLEAN WantLogicalRegions,
  660. OUT PREGION_DESCRIPTOR *Region,
  661. OUT ULONG *RegionCount,
  662. IN REGION_TYPE RegionType
  663. )
  664. /*++
  665. Routine Description:
  666. Arguments:
  667. Return Value:
  668. --*/
  669. {
  670. STATUS_CODE status;
  671. LARGE_INTEGER alignedOffset,
  672. alignedSize,
  673. temp;
  674. ULONG sizeMB;
  675. while (p) {
  676. if (p->SysID == SYSID_UNUSED) {
  677. if (WantFreeRegions) {
  678. alignedOffset = AlignTowardsDiskEnd(p->Disk,p->Offset);
  679. temp.QuadPart = p->Offset.QuadPart + p->Length.QuadPart;
  680. temp = AlignTowardsDiskStart(p->Disk, temp);
  681. alignedSize.QuadPart = temp.QuadPart - alignedOffset.QuadPart;
  682. sizeMB = SIZEMB(alignedSize);
  683. // Show the space free if it is greater than 1 meg, AND
  684. // it is not a space starting at the beginning of the disk
  685. // and of length <= 1 cylinder.
  686. // This prevents the user from seeing the first cylinder
  687. // of the disk as free (could otherwise happen with an
  688. // extended partition starting on cylinder 1 and cylinders
  689. // of 1 megabyte or larger).
  690. if ((alignedSize.QuadPart > 0) && sizeMB &&
  691. ((p->Offset.QuadPart) ||
  692. (p->Length.QuadPart > (DiskGeometryArray[p->Disk].BytesPerCylinder)))) {
  693. if (!AddRegionEntry(Region,
  694. RegionCount,
  695. sizeMB,
  696. RegionType,
  697. p,
  698. alignedOffset,
  699. alignedSize)) {
  700. RETURN_OUT_OF_MEMORY;
  701. }
  702. }
  703. }
  704. } else {
  705. if (WantUsedRegions) {
  706. alignedOffset = p->Offset;
  707. alignedSize = p->Length;
  708. sizeMB = SIZEMB(alignedSize);
  709. if (!AddRegionEntry(Region,
  710. RegionCount,
  711. sizeMB,
  712. RegionType,
  713. p,
  714. alignedOffset,
  715. alignedSize)) {
  716. RETURN_OUT_OF_MEMORY;
  717. }
  718. }
  719. if (IsExtended(p->SysID) && WantLogicalRegions) {
  720. status = GetRegions(Disk,
  721. LogicalVolumes[Disk],
  722. WantUsedRegions,
  723. WantFreeRegions,
  724. FALSE,
  725. Region,
  726. RegionCount,
  727. REGION_LOGICAL);
  728. if (status != OK_STATUS) {
  729. return status;
  730. }
  731. }
  732. }
  733. p = p->Next;
  734. }
  735. return OK_STATUS;
  736. }
  737. BOOLEAN
  738. AddRegionEntry(
  739. OUT PREGION_DESCRIPTOR *Regions,
  740. OUT ULONG *RegionCount,
  741. IN ULONG SizeMB,
  742. IN REGION_TYPE RegionType,
  743. IN PPARTITION Partition,
  744. IN LARGE_INTEGER AlignedRegionOffset,
  745. IN LARGE_INTEGER AlignedRegionSize
  746. )
  747. /*++
  748. Routine Description:
  749. Allocate space for the region descriptor and copy the provided data.
  750. Arguments:
  751. Regions - return the pointer to the new region
  752. RegionCount - number of regions on the disk so far
  753. SizeMB - size of the region
  754. RegionType - type of the region
  755. Partition - partition structure with other related information
  756. AlignedRegionOffset - region starting location
  757. AlignedRegionSize - region size.
  758. Return Value:
  759. TRUE - The region was added successfully
  760. FALSE - it wasn't
  761. --*/
  762. {
  763. PREGION_DESCRIPTOR regionDescriptor;
  764. PREGION_DATA regionData;
  765. regionDescriptor = ReallocateMemory(*Regions,(((*RegionCount) + 1) * sizeof(REGION_DESCRIPTOR)) + 20);
  766. if (regionDescriptor == NULL) {
  767. return FALSE;
  768. } else {
  769. *Regions = regionDescriptor;
  770. (*RegionCount)++;
  771. }
  772. regionDescriptor = &(*Regions)[(*RegionCount)-1];
  773. if (!(regionDescriptor->Reserved = AllocateMemory(sizeof(REGION_DATA)))) {
  774. return FALSE;
  775. }
  776. regionDescriptor->Disk = Partition->Disk;
  777. regionDescriptor->SysID = Partition->SysID;
  778. regionDescriptor->SizeMB = SizeMB;
  779. regionDescriptor->Active = Partition->Active;
  780. regionDescriptor->Recognized = Partition->Recognized;
  781. regionDescriptor->PartitionNumber = Partition->PartitionNumber;
  782. regionDescriptor->OriginalPartitionNumber = Partition->OriginalPartitionNumber;
  783. regionDescriptor->RegionType = RegionType;
  784. regionDescriptor->PersistentData = Partition->PersistentData;
  785. regionData = regionDescriptor->Reserved;
  786. regionData->Partition = Partition;
  787. regionData->AlignedRegionOffset = AlignedRegionOffset;
  788. regionData->AlignedRegionSize = AlignedRegionSize;
  789. return TRUE;
  790. }
  791. VOID
  792. FreeRegionArray(
  793. IN PREGION_DESCRIPTOR Region,
  794. IN ULONG RegionCount
  795. )
  796. /*++
  797. Routine Description:
  798. This routine frees a region array returned by GetDiskRegions().
  799. Arguments:
  800. Region - pointer to the array of regions to be freed
  801. RegionCount - number of items in the Region array
  802. Return Value:
  803. None.
  804. --*/
  805. {
  806. ULONG i;
  807. for (i = 0; i < RegionCount; i++) {
  808. if (Region[i].Reserved) {
  809. FreeMemory(Region[i].Reserved);
  810. }
  811. }
  812. FreeMemory(Region);
  813. }
  814. VOID
  815. AddPartitionToLinkedList(
  816. IN OUT PARTITION **Head,
  817. IN PARTITION *p
  818. )
  819. /*++
  820. Routine Description:
  821. This routine adds a PARTITION structure to a doubly-linked
  822. list, sorted by the Offset field in ascending order.
  823. Arguments:
  824. Head - pointer to pointer to first element in list
  825. p - pointer to item to be added to list
  826. Return Value:
  827. None.
  828. --*/
  829. {
  830. PARTITION *cur,
  831. *prev;
  832. if ((cur = *Head) == NULL) {
  833. *Head = p;
  834. return;
  835. }
  836. if (p->Offset.QuadPart < cur->Offset.QuadPart) {
  837. p->Next = cur;
  838. cur->Prev = p;
  839. *Head = p;
  840. return;
  841. }
  842. prev = *Head;
  843. cur = cur->Next;
  844. while (cur) {
  845. if (p->Offset.QuadPart < cur->Offset.QuadPart) {
  846. p->Next = cur;
  847. p->Prev = prev;
  848. prev->Next = p;
  849. cur->Prev = p;
  850. return;
  851. }
  852. prev = cur;
  853. cur = cur->Next;
  854. }
  855. prev->Next = p;
  856. p->Prev = prev;
  857. return;
  858. }
  859. BOOLEAN
  860. IsInLinkedList(
  861. IN PPARTITION p,
  862. IN PPARTITION List
  863. )
  864. /*++
  865. Routine Description:
  866. This routine determines whether a PARTITION element is in
  867. a given linked list of PARTITION elements.
  868. Arguments:
  869. p - pointer to element to be checked for
  870. List - first element in list to be scanned
  871. Return Value:
  872. true if p found in List, false otherwise
  873. --*/
  874. {
  875. while (List) {
  876. if (p == List) {
  877. return TRUE;
  878. }
  879. List = List->Next;
  880. }
  881. return FALSE;
  882. }
  883. BOOLEAN
  884. IsInLogicalList(
  885. IN ULONG Disk,
  886. IN PPARTITION p
  887. )
  888. /*++
  889. Routine Description:
  890. This routine determines whether a PARTITION element is in
  891. the logical volume list for a given disk.
  892. Arguments:
  893. Disk - index of disk to be checked
  894. p - pointer to element to be checked for
  895. Return Value:
  896. true if p found in Disk's logical volume list, false otherwise
  897. --*/
  898. {
  899. return IsInLinkedList(p, LogicalVolumes[Disk]);
  900. }
  901. BOOLEAN
  902. IsInPartitionList(
  903. IN ULONG Disk,
  904. IN PPARTITION p
  905. )
  906. /*++
  907. Routine Description:
  908. This routine determines whether a PARTITION element is in
  909. the primary partition list for a given disk.
  910. Arguments:
  911. Disk - index of disk to be checked
  912. p - pointer to element to be checked for
  913. Return Value:
  914. true if p found in Disk's primary partition list, false otherwise
  915. --*/
  916. {
  917. return IsInLinkedList(p, PrimaryPartitions[Disk]);
  918. }
  919. VOID
  920. MergeFreePartitions(
  921. IN PPARTITION p
  922. )
  923. /*++
  924. Routine Description:
  925. This routine merges adjacent free space elements in the
  926. given linked list of PARTITION elements. It is designed
  927. to be called after adding or deleting a partition.
  928. Arguments:
  929. p - pointer to first item in list whose free elements are to
  930. be merged.
  931. Return Value:
  932. None.
  933. --*/
  934. {
  935. PPARTITION next;
  936. while (p && p->Next) {
  937. if ((p->SysID == SYSID_UNUSED) && (p->Next->SysID == SYSID_UNUSED)) {
  938. next = p->Next;
  939. p->Length.QuadPart = (next->Offset.QuadPart + next->Length.QuadPart) - p->Offset.QuadPart;
  940. if (p->Next = next->Next) {
  941. next->Next->Prev = p;
  942. }
  943. FreeMemory(next);
  944. } else {
  945. p = p->Next;
  946. }
  947. }
  948. }
  949. PPARTITION
  950. FindPartitionElement(
  951. IN ULONG Disk,
  952. IN ULONG Partition
  953. )
  954. /*++
  955. Routine Description:
  956. This routine locates a PARTITION element for a disk/partition
  957. number pair. The partition number is the number that the
  958. system assigns to the partition.
  959. Arguments:
  960. Disk - index of relevent disk
  961. Partition - partition number of partition to find
  962. Return Value:
  963. pointer to PARTITION element, or NULL if not found.
  964. --*/
  965. {
  966. PPARTITION p;
  967. p = PrimaryPartitions[Disk];
  968. while (p) {
  969. if ((p->SysID != SYSID_UNUSED) && !IsExtended(p->SysID) && (p->PartitionNumber == Partition)) {
  970. return p;
  971. }
  972. p = p->Next;
  973. }
  974. p = LogicalVolumes[Disk];
  975. while (p) {
  976. if ((p->SysID != SYSID_UNUSED) && (p->PartitionNumber == Partition)) {
  977. return p;
  978. }
  979. p = p->Next;
  980. }
  981. return NULL;
  982. }
  983. VOID
  984. SetSysID(
  985. IN ULONG Disk,
  986. IN ULONG Partition,
  987. IN UCHAR SysID
  988. )
  989. /*++
  990. Routine Description:
  991. This routine sets the system id of the given partition
  992. on the given disk.
  993. Arguments:
  994. Disk - index of relevent disk
  995. Partition - partition number of relevent partition
  996. SysID - new system ID for Partition on Disk
  997. Return Value:
  998. None.
  999. --*/
  1000. {
  1001. PPARTITION p = FindPartitionElement(Disk,Partition);
  1002. if (p) {
  1003. p->SysID = SysID;
  1004. if (!p->Update) {
  1005. p->Update = CHANGED_DONT_ZAP;
  1006. }
  1007. ChangesRequested[p->Disk] = TRUE;
  1008. }
  1009. }
  1010. VOID
  1011. SetSysID2(
  1012. IN PREGION_DESCRIPTOR Region,
  1013. IN UCHAR SysID
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. Arguments:
  1018. Return Value:
  1019. --*/
  1020. {
  1021. PPARTITION p = ((PREGION_DATA)(Region->Reserved))->Partition;
  1022. p->SysID = SysID;
  1023. if (!p->Update) {
  1024. p->Update = CHANGED_DONT_ZAP;
  1025. }
  1026. ChangesRequested[p->Disk] = TRUE;
  1027. }
  1028. VOID
  1029. FreeLinkedPartitionList(
  1030. IN OUT PPARTITION *q
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. This routine frees a linked list of PARTITION elements. The head
  1035. pointer is set to NULL.
  1036. Arguments:
  1037. p - pointer to pointer to first element of list to free.
  1038. Return Value:
  1039. None.
  1040. --*/
  1041. {
  1042. PARTITION *n;
  1043. PARTITION *p = *q;
  1044. while(p) {
  1045. n = p->Next;
  1046. FreeMemory(p);
  1047. p = n;
  1048. }
  1049. *q = NULL;
  1050. }
  1051. VOID
  1052. FreePartitionInfoLinkedLists(
  1053. IN PPARTITION *ListHeadArray
  1054. )
  1055. /*++
  1056. Routine Description:
  1057. This routine frees the linked lists of PARTITION elements
  1058. for each disk.
  1059. Arguments:
  1060. ListHeadArray - pointer to array of pointers to first elements of
  1061. PARTITION element lists.
  1062. Return Value:
  1063. None.
  1064. --*/
  1065. {
  1066. ULONG i;
  1067. for (i = 0; i < CountOfDisks; i++) {
  1068. FreeLinkedPartitionList(&ListHeadArray[i]);
  1069. }
  1070. }
  1071. PPARTITION
  1072. AllocatePartitionStructure(
  1073. IN ULONG Disk,
  1074. IN LARGE_INTEGER Offset,
  1075. IN LARGE_INTEGER Length,
  1076. IN UCHAR SysID,
  1077. IN BOOLEAN Update,
  1078. IN BOOLEAN Active,
  1079. IN BOOLEAN Recognized
  1080. )
  1081. /*++
  1082. Routine Description:
  1083. This routine allocates space for, and initializes a PARTITION
  1084. structure.
  1085. Arguments:
  1086. Disk - index of disk, one of whose regions the new PARTITION
  1087. strucure describes.
  1088. Offset - byte offset of region on the disk
  1089. Length - length in bytes of the region
  1090. SysID - system id of region, of SYSID_UNUSED of this PARTITION
  1091. is actually a free space.
  1092. Update - whether this PARTITION is dirty, ie, has changed and needs
  1093. to be written to disk.
  1094. Active - flag for the BootIndicator field in a partition table entry,
  1095. indicates to the x86 master boot program which partition
  1096. is active.
  1097. Recognized - whether the partition is a type recognized by NT
  1098. Return Value:
  1099. NULL if allocation failed, or new initialized PARTITION strucure.
  1100. --*/
  1101. {
  1102. PPARTITION p = AllocateMemory(sizeof(PARTITION));
  1103. if (p) {
  1104. p->Next = NULL;
  1105. p->Prev = NULL;
  1106. p->Offset = Offset;
  1107. p->Length = Length;
  1108. p->Disk = Disk;
  1109. p->Update = Update;
  1110. p->Active = Active;
  1111. p->Recognized = Recognized;
  1112. p->SysID = SysID;
  1113. p->OriginalPartitionNumber = 0;
  1114. p->PartitionNumber = 0;
  1115. p->PersistentData = 0;
  1116. p->CommitMirrorBreakNeeded = FALSE;
  1117. }
  1118. return(p);
  1119. }
  1120. STATUS_CODE
  1121. InitializeFreeSpace(
  1122. IN ULONG Disk,
  1123. IN PPARTITION *PartitionList, // list the free space goes in
  1124. IN LARGE_INTEGER StartOffset,
  1125. IN LARGE_INTEGER Length
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. This routine determines all the free spaces within a given area
  1130. on a disk, allocates PARTITION structures to describe them,
  1131. and adds these structures to the relevent partition list
  1132. (primary partitions or logical volumes).
  1133. No rounding or alignment is performed here. Spaces of even one
  1134. byte will be counted and inserted in the partition list.
  1135. Arguments:
  1136. Disk - index of disk whose free spaces are being sought.
  1137. PartitionList - pointer to first element on PARTITION list that
  1138. the free spaces will go in.
  1139. StartOffset - start offset of area on disk to consider (ie, 0 for
  1140. primary spaces or the first byte of the extended
  1141. partition for logical spaces).
  1142. Length - length of area on disk to consider (ie, size of disk
  1143. for primary spaces or size of extended partition for
  1144. logical spaces).
  1145. Return Value:
  1146. OK_STATUS or error code.
  1147. --*/
  1148. {
  1149. PPARTITION p = *PartitionList,
  1150. q;
  1151. LARGE_INTEGER start,
  1152. size;
  1153. start = StartOffset;
  1154. while (p) {
  1155. size.QuadPart = p->Offset.QuadPart - start.QuadPart;
  1156. if (size.QuadPart > 0) {
  1157. if (!(q = AllocatePartitionStructure(Disk,
  1158. start,
  1159. size,
  1160. SYSID_UNUSED,
  1161. FALSE,
  1162. FALSE,
  1163. FALSE))) {
  1164. RETURN_OUT_OF_MEMORY;
  1165. }
  1166. AddPartitionToLinkedList(PartitionList, q);
  1167. }
  1168. start.QuadPart = p->Offset.QuadPart + p->Length.QuadPart;
  1169. p = p->Next;
  1170. }
  1171. size.QuadPart = (StartOffset.QuadPart + Length.QuadPart) - start.QuadPart;
  1172. if (size.QuadPart > 0) {
  1173. if (!(q = AllocatePartitionStructure(Disk,
  1174. start,
  1175. size,
  1176. SYSID_UNUSED,
  1177. FALSE,
  1178. FALSE,
  1179. FALSE))) {
  1180. RETURN_OUT_OF_MEMORY;
  1181. }
  1182. AddPartitionToLinkedList(PartitionList, q);
  1183. }
  1184. return OK_STATUS;
  1185. }
  1186. STATUS_CODE
  1187. InitializeLogicalVolumeList(
  1188. IN ULONG Disk,
  1189. IN PDRIVE_LAYOUT_INFORMATION DriveLayout
  1190. )
  1191. /*++
  1192. Routine Description:
  1193. This routine creates the logical volume linked list of
  1194. PARTITION structures for the given disk.
  1195. Arguments:
  1196. Disk - index of disk
  1197. DriveLayout - pointer to structure describing the raw partition
  1198. layout of the disk.
  1199. Return Value:
  1200. OK_STATUS or error code.
  1201. --*/
  1202. {
  1203. PPARTITION p,
  1204. q;
  1205. ULONG i,
  1206. j;
  1207. PPARTITION_INFORMATION d;
  1208. LARGE_INTEGER HiddenBytes;
  1209. ULONG BytesPerSector = DiskGeometryArray[Disk].BytesPerSector;
  1210. FreeLinkedPartitionList(&LogicalVolumes[Disk]);
  1211. p = PrimaryPartitions[Disk];
  1212. while (p) {
  1213. if (IsExtended(p->SysID)) {
  1214. break;
  1215. }
  1216. p = p->Next;
  1217. }
  1218. if (p) {
  1219. for (i=ENTRIES_PER_BOOTSECTOR; i<DriveLayout->PartitionCount; i+=ENTRIES_PER_BOOTSECTOR) {
  1220. for (j=i; j<i+ENTRIES_PER_BOOTSECTOR; j++) {
  1221. d = &DriveLayout->PartitionEntry[j];
  1222. if ((d->PartitionType != SYSID_UNUSED) && (d->PartitionType != SYSID_EXTENDED)) {
  1223. LARGE_INTEGER t1,
  1224. t2;
  1225. HiddenBytes.QuadPart = (LONGLONG)d->HiddenSectors * (LONGLONG)BytesPerSector;
  1226. t1.QuadPart = d->StartingOffset.QuadPart - HiddenBytes.QuadPart;
  1227. t2.QuadPart = d->PartitionLength.QuadPart + HiddenBytes.QuadPart;
  1228. if (!(q = AllocatePartitionStructure(Disk,
  1229. t1,
  1230. t2,
  1231. d->PartitionType,
  1232. FALSE,
  1233. d->BootIndicator,
  1234. d->RecognizedPartition))) {
  1235. RETURN_OUT_OF_MEMORY;
  1236. }
  1237. q->PartitionNumber =
  1238. q->OriginalPartitionNumber = d->PartitionNumber;
  1239. AddPartitionToLinkedList(&LogicalVolumes[Disk],q);
  1240. break;
  1241. }
  1242. }
  1243. }
  1244. return InitializeFreeSpace(Disk,
  1245. &LogicalVolumes[Disk],
  1246. p->Offset,
  1247. p->Length);
  1248. }
  1249. return OK_STATUS;
  1250. }
  1251. STATUS_CODE
  1252. InitializePrimaryPartitionList(
  1253. IN ULONG Disk,
  1254. IN PDRIVE_LAYOUT_INFORMATION DriveLayout
  1255. )
  1256. /*++
  1257. Routine Description:
  1258. This routine creates the primary partition linked list of
  1259. PARTITION structures for the given disk.
  1260. Arguments:
  1261. Disk - index of disk
  1262. DriveLayout - pointer to structure describing the raw partition
  1263. layout of the disk.
  1264. Return Value:
  1265. OK_STATUS or error code.
  1266. --*/
  1267. {
  1268. LARGE_INTEGER zero;
  1269. ULONG i;
  1270. PPARTITION p;
  1271. PPARTITION_INFORMATION d;
  1272. zero.QuadPart = 0;
  1273. FreeLinkedPartitionList(&PrimaryPartitions[Disk]);
  1274. if (DriveLayout->PartitionCount >= ENTRIES_PER_BOOTSECTOR) {
  1275. for (i=0; i<ENTRIES_PER_BOOTSECTOR; i++) {
  1276. d = &DriveLayout->PartitionEntry[i];
  1277. if (d->PartitionType != SYSID_UNUSED) {
  1278. if (!(p = AllocatePartitionStructure(Disk,
  1279. d->StartingOffset,
  1280. d->PartitionLength,
  1281. d->PartitionType,
  1282. FALSE,
  1283. d->BootIndicator,
  1284. d->RecognizedPartition))) {
  1285. RETURN_OUT_OF_MEMORY;
  1286. }
  1287. p->PartitionNumber =
  1288. p->OriginalPartitionNumber = IsExtended(p->SysID)
  1289. ? 0
  1290. : d->PartitionNumber;
  1291. AddPartitionToLinkedList(&PrimaryPartitions[Disk],p);
  1292. }
  1293. }
  1294. }
  1295. return InitializeFreeSpace(Disk,
  1296. &PrimaryPartitions[Disk],
  1297. zero,
  1298. DiskLengthBytes(Disk));
  1299. }
  1300. VOID
  1301. ReconcilePartitionNumbers(
  1302. ULONG Disk,
  1303. PDRIVE_LAYOUT_INFORMATION DriveLayout
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. With dynamic partitioning, the partitions on the disk will no longer
  1308. follow sequencial numbering schemes. It will be possible for a disk
  1309. to have a partition #1 that is the last partition on the disk and a
  1310. partition #3 that is the first. This routine runs through the NT
  1311. namespace for harddisks to resolve this inconsistency.
  1312. This routine has the problem that it will not locate partitions that
  1313. are part of an FT set because the partition information for these
  1314. partitions will be modified to reflect the size of the set, not the
  1315. size of the partition.
  1316. Arguments:
  1317. Disk - the disk number
  1318. DriveLayout - the partitioning information
  1319. Return Value:
  1320. None
  1321. --*/
  1322. {
  1323. #define BUFFERSIZE 1024
  1324. NTSTATUS status;
  1325. IO_STATUS_BLOCK statusBlock;
  1326. HANDLE directoryHandle,
  1327. partitionHandle;
  1328. CLONG continueProcessing;
  1329. ULONG context = 0,
  1330. returnedLength,
  1331. index;
  1332. POBJECT_DIRECTORY_INFORMATION dirInfo;
  1333. PARTITION_INFORMATION partitionInfo;
  1334. PPARTITION_INFORMATION partitionInfoPtr;
  1335. OBJECT_ATTRIBUTES attributes;
  1336. UNICODE_STRING unicodeString;
  1337. ANSI_STRING ansiName;
  1338. PUCHAR deviceName;
  1339. PUCHAR buffer;
  1340. deviceName = Malloc(100);
  1341. if (!deviceName) {
  1342. return;
  1343. }
  1344. buffer = Malloc(BUFFERSIZE);
  1345. if (!buffer) {
  1346. Free(deviceName);
  1347. return;
  1348. }
  1349. sprintf(deviceName, "\\Device\\Harddisk%d", Disk);
  1350. RtlInitAnsiString(&ansiName, deviceName);
  1351. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiName, TRUE);
  1352. if (!NT_SUCCESS(status)) {
  1353. Free(deviceName);
  1354. Free(buffer);
  1355. return;
  1356. }
  1357. InitializeObjectAttributes(&attributes,
  1358. &unicodeString,
  1359. OBJ_CASE_INSENSITIVE,
  1360. NULL,
  1361. NULL);
  1362. status = NtOpenDirectoryObject(&directoryHandle,
  1363. DIRECTORY_QUERY,
  1364. &attributes);
  1365. if (!NT_SUCCESS(status)) {
  1366. Free(deviceName);
  1367. Free(buffer);
  1368. return;
  1369. }
  1370. // Query the entire directory in one sweep
  1371. continueProcessing = 1;
  1372. while (continueProcessing) {
  1373. RtlZeroMemory(buffer, BUFFERSIZE);
  1374. status = NtQueryDirectoryObject(directoryHandle,
  1375. buffer,
  1376. BUFFERSIZE,
  1377. FALSE,
  1378. FALSE,
  1379. &context,
  1380. &returnedLength);
  1381. // Check the status of the operation.
  1382. if (!NT_SUCCESS(status)) {
  1383. if (status != STATUS_NO_MORE_FILES) {
  1384. break;
  1385. }
  1386. continueProcessing = 0;
  1387. }
  1388. // For every record in the buffer check for partition name
  1389. for (dirInfo = (POBJECT_DIRECTORY_INFORMATION) buffer;
  1390. TRUE;
  1391. dirInfo = (POBJECT_DIRECTORY_INFORMATION) (((PUCHAR) dirInfo) +
  1392. sizeof(OBJECT_DIRECTORY_INFORMATION))) {
  1393. // Check if there is another record. If there isn't, then get out
  1394. // of the loop now
  1395. if (dirInfo->Name.Length == 0) {
  1396. break;
  1397. }
  1398. // compare the name to see if it is a Partition
  1399. if (!_wcsnicmp(dirInfo->Name.Buffer, L"Partition", 9)) {
  1400. UCHAR digits[3];
  1401. ULONG partitionNumber;
  1402. // Located a partition. This restricts the # of partitions
  1403. // to 99.
  1404. digits[0] = (UCHAR) dirInfo->Name.Buffer[9];
  1405. digits[1] = (UCHAR) dirInfo->Name.Buffer[10];
  1406. digits[2] = 0;
  1407. partitionNumber = atoi(digits);
  1408. if (partitionNumber <= 0) {
  1409. // less than zero is really an error...
  1410. // partition zero is always the same.
  1411. continue;
  1412. }
  1413. // Have a numbered partition -- match it to the drive layout
  1414. status = LowOpenPartition(deviceName, partitionNumber, &partitionHandle);
  1415. if (!NT_SUCCESS(status)) {
  1416. // If it cannot be opened perhaps it isn't really a partition
  1417. continue;
  1418. }
  1419. status = NtDeviceIoControlFile(partitionHandle,
  1420. 0,
  1421. NULL,
  1422. NULL,
  1423. &statusBlock,
  1424. IOCTL_DISK_GET_PARTITION_INFO,
  1425. NULL,
  1426. 0,
  1427. &partitionInfo,
  1428. sizeof(PARTITION_INFORMATION));
  1429. if (!NT_SUCCESS(status)) {
  1430. LowCloseDisk(partitionHandle);
  1431. continue;
  1432. }
  1433. // match partition information with drive layout.
  1434. for (index = 0; index < DriveLayout->PartitionCount; index++) {
  1435. partitionInfoPtr = &DriveLayout->PartitionEntry[index];
  1436. if ((partitionInfoPtr->StartingOffset.QuadPart == partitionInfo.StartingOffset.QuadPart) &&
  1437. (partitionInfoPtr->PartitionLength.QuadPart == partitionInfo.PartitionLength.QuadPart)) {
  1438. // This is a match.
  1439. partitionInfoPtr->PartitionNumber = partitionNumber;
  1440. break;
  1441. }
  1442. }
  1443. LowCloseDisk(partitionHandle);
  1444. }
  1445. }
  1446. }
  1447. // Now close the directory object
  1448. Free(deviceName);
  1449. Free(buffer);
  1450. (VOID) NtClose(directoryHandle);
  1451. return;
  1452. }
  1453. VOID
  1454. CheckForOldDrivers(
  1455. IN ULONG Disk
  1456. )
  1457. /*++
  1458. Routine Description:
  1459. This routine determines if an old release 3.1 drive is in the
  1460. system. If so, it calculates the partition number for each region
  1461. on a disk. For a used region, the partition number is the number
  1462. that the system will assign to the partition. All partitions
  1463. (except the extended partition) are numbered first starting at 1,
  1464. and then all logical volumes in the extended partition.
  1465. For a free region, the partition number is the number that the
  1466. system WOULD assign to the partition if the space were to be
  1467. converted to a partition and all other regions on the disk were
  1468. left as is.
  1469. The partition numbers are stored in the PARTITION elements.
  1470. Arguments:
  1471. Disk - index of disk whose partitions are to be renumbered.
  1472. Return Value:
  1473. None.
  1474. --*/
  1475. {
  1476. PPARTITION p = PrimaryPartitions[Disk];
  1477. ULONG n = 1;
  1478. while (p) {
  1479. if (p->SysID != SYSID_UNUSED) {
  1480. if ((!IsExtended(p->SysID)) && (IsRecognizedPartition(p->SysID))) {
  1481. // If there is already a partition number, nothing need be
  1482. // done here.
  1483. if (p->PartitionNumber) {
  1484. return;
  1485. } else {
  1486. RestartRequired = TRUE;
  1487. }
  1488. p->PartitionNumber = n;
  1489. if (p->SysID != SYSID_UNUSED) {
  1490. n++;
  1491. }
  1492. }
  1493. }
  1494. p = p->Next;
  1495. }
  1496. p = LogicalVolumes[Disk];
  1497. while (p) {
  1498. if (p->SysID != SYSID_UNUSED) {
  1499. if (p->PartitionNumber) {
  1500. return;
  1501. } else {
  1502. RestartRequired = TRUE;
  1503. }
  1504. p->PartitionNumber = n;
  1505. n++;
  1506. }
  1507. p = p->Next;
  1508. }
  1509. }
  1510. STATUS_CODE
  1511. InitializePartitionLists(
  1512. VOID
  1513. )
  1514. /*++
  1515. Routine Description:
  1516. This routine scans the PARTITION_INFO array returned for each disk
  1517. by the OS. A linked list of PARTITION structures is layered on top
  1518. of each array; the net result is a sorted list that covers an entire
  1519. disk, because free spaces are also factored in as 'dummy' partitions.
  1520. Arguments:
  1521. None.
  1522. Return Value:
  1523. OK_STATUS or error code.
  1524. --*/
  1525. {
  1526. STATUS_CODE status;
  1527. ULONG disk;
  1528. PDRIVE_LAYOUT_INFORMATION driveLayout;
  1529. for (disk = 0; disk < CountOfDisks; disk++) {
  1530. if (OffLine[disk]) {
  1531. continue;
  1532. }
  1533. if ((status = LowGetDiskLayout(DiskNames[disk], &driveLayout)) != OK_STATUS) {
  1534. return status;
  1535. }
  1536. // ReconcilePartitionNumbers(disk, driveLayout);
  1537. if ((status = InitializePrimaryPartitionList(disk, driveLayout)) == OK_STATUS) {
  1538. status = InitializeLogicalVolumeList(disk, driveLayout);
  1539. }
  1540. if (status != OK_STATUS) {
  1541. FreeMemory(driveLayout);
  1542. return status;
  1543. }
  1544. Signatures[disk] = driveLayout->Signature;
  1545. FreeMemory(driveLayout);
  1546. CheckForOldDrivers(disk);
  1547. }
  1548. return OK_STATUS;
  1549. }
  1550. LARGE_INTEGER
  1551. DiskLengthBytes(
  1552. IN ULONG Disk
  1553. )
  1554. /*++
  1555. Routine Description:
  1556. This routine determines the disk length in bytes. This value
  1557. is calculated from the disk geometry information.
  1558. Arguments:
  1559. Disk - index of disk whose size is desired
  1560. Return Value:
  1561. Size of Disk.
  1562. --*/
  1563. {
  1564. LARGE_INTEGER result;
  1565. result.QuadPart = DiskGeometryArray[Disk].Cylinders.QuadPart *
  1566. DiskGeometryArray[Disk].BytesPerCylinder;
  1567. return result;
  1568. }
  1569. ULONG
  1570. SIZEMB(
  1571. IN LARGE_INTEGER ByteCount
  1572. )
  1573. /*++
  1574. Routine Description:
  1575. Calculate the size in megabytes of a given byte count. The value is
  1576. properly rounded (ie, not merely truncated).
  1577. This function replaces a macro of the same name that was truncating
  1578. instead of rounding.
  1579. Arguments:
  1580. ByteCount - supplies number of bytes
  1581. Return Value:
  1582. Size in MB equivalent to ByteCount.
  1583. --*/
  1584. {
  1585. ULONG Remainder;
  1586. ULONG SizeMB;
  1587. SizeMB = RtlExtendedLargeIntegerDivide(ByteCount,
  1588. ONE_MEG,
  1589. &Remainder).LowPart;
  1590. if (Remainder >= ONE_MEG/2) {
  1591. SizeMB++;
  1592. }
  1593. return SizeMB;
  1594. }
  1595. ULONG
  1596. DiskSizeMB(
  1597. IN ULONG Disk
  1598. )
  1599. /*++
  1600. Routine Description:
  1601. This routine determines the disk length in megabytes. The returned
  1602. value is rounded down after division by 1024*1024.
  1603. Arguments:
  1604. Disk - index of disk whose size is desired
  1605. Return Value:
  1606. Size of Disk.
  1607. --*/
  1608. {
  1609. return SIZEMB(DiskLengthBytes(Disk));
  1610. }
  1611. LARGE_INTEGER
  1612. AlignTowardsDiskStart(
  1613. IN ULONG Disk,
  1614. IN LARGE_INTEGER Offset
  1615. )
  1616. /*++
  1617. Routine Description:
  1618. This routine snaps a byte offset to a cylinder boundary, towards
  1619. the start of the disk.
  1620. Arguments:
  1621. Disk - index of disk whose offset is to be snapped
  1622. Offset - byte offset to be aligned (snapped to cylinder boundary)
  1623. Return Value:
  1624. Aligned offset.
  1625. --*/
  1626. {
  1627. LARGE_INTEGER mod;
  1628. LARGE_INTEGER result;
  1629. mod.QuadPart = Offset.QuadPart % DiskGeometryArray[Disk].BytesPerCylinder;
  1630. result.QuadPart = Offset.QuadPart - mod.QuadPart;
  1631. return result;
  1632. }
  1633. LARGE_INTEGER
  1634. AlignTowardsDiskEnd(
  1635. IN ULONG Disk,
  1636. IN LARGE_INTEGER Offset
  1637. )
  1638. /*++
  1639. Routine Description:
  1640. This routine snaps a byte offset to a cylinder boundary, towards
  1641. the end of the disk.
  1642. Arguments:
  1643. Disk - index of disk whose offset is to be snapped
  1644. Offset - byte offset to be aligned (snapped to cylinder boundary)
  1645. Return Value:
  1646. Aligned offset.
  1647. --*/
  1648. {
  1649. LARGE_INTEGER mod,
  1650. temp;
  1651. mod.QuadPart = Offset.QuadPart % DiskGeometryArray[Disk].BytesPerCylinder;
  1652. if (mod.QuadPart) {
  1653. temp.QuadPart = Offset.QuadPart + DiskGeometryArray[Disk].BytesPerCylinder;
  1654. Offset = AlignTowardsDiskStart(Disk, temp);
  1655. }
  1656. return Offset;
  1657. }
  1658. BOOLEAN
  1659. IsExtended(
  1660. IN UCHAR SysID
  1661. )
  1662. /*++
  1663. Routine Description:
  1664. This routine determines whether a given system id is for an
  1665. extended type (ie, link) entry.
  1666. Arguments:
  1667. SysID - system id to be tested.
  1668. Return Value:
  1669. true/false based on whether SysID is for an extended type.
  1670. --*/
  1671. {
  1672. return (BOOLEAN)(SysID == SYSID_EXTENDED);
  1673. }
  1674. STATUS_CODE
  1675. IsAnyCreationAllowed(
  1676. IN ULONG Disk,
  1677. IN BOOLEAN AllowMultiplePrimaries,
  1678. OUT PBOOLEAN AnyAllowed,
  1679. OUT PBOOLEAN PrimaryAllowed,
  1680. OUT PBOOLEAN ExtendedAllowed,
  1681. OUT PBOOLEAN LogicalAllowed
  1682. )
  1683. /*++
  1684. Routine Description:
  1685. This routine determines whether any partition may be created on a
  1686. given disk, based on three sub-queries -- whether creation is allowed
  1687. of a primary partition, an extended partition, or a logical volume.
  1688. Arguments:
  1689. Disk - index of disk to check
  1690. AllowMultiplePrimaries - whether to allow multiple primary partitions
  1691. AnyAllowed - returns whether any creation is allowed
  1692. PrimaryAllowed - returns whether creation of a primary partition
  1693. is allowed
  1694. ExtendedAllowed - returns whether creation of an extended partition
  1695. is allowed
  1696. Logical Allowed - returns whether creation of a logical volume is allowed.
  1697. Return Value:
  1698. OK_STATUS or error code
  1699. --*/
  1700. {
  1701. STATUS_CODE status;
  1702. if ((status = IsCreationOfPrimaryAllowed(Disk,AllowMultiplePrimaries,PrimaryAllowed)) != OK_STATUS) {
  1703. return status;
  1704. }
  1705. if ((status = IsCreationOfExtendedAllowed(Disk,ExtendedAllowed)) != OK_STATUS) {
  1706. return status;
  1707. }
  1708. if ((status = IsCreationOfLogicalAllowed(Disk,LogicalAllowed)) != OK_STATUS) {
  1709. return status;
  1710. }
  1711. *AnyAllowed = (BOOLEAN)(*PrimaryAllowed || *ExtendedAllowed || *LogicalAllowed);
  1712. return OK_STATUS;
  1713. }
  1714. STATUS_CODE
  1715. IsCreationOfPrimaryAllowed(
  1716. IN ULONG Disk,
  1717. IN BOOLEAN AllowMultiplePrimaries,
  1718. OUT BOOLEAN *Allowed
  1719. )
  1720. /*++
  1721. Routine Description:
  1722. This routine determines whether creation of a primary partition is
  1723. allowed. This is true when there is a free entry in the MBR and
  1724. there is free primary space on the disk. If multiple primaries
  1725. are not allowed, then there must also not exist any primary partitions
  1726. in order for a primary creation to be allowed.
  1727. Arguments:
  1728. Disk - index of disk to check
  1729. AllowMultiplePrimaries - whether existnace of primary partition
  1730. disallows creation of a primary partition
  1731. Allowed - returns whether creation of a primary partition
  1732. is allowed
  1733. Return Value:
  1734. OK_STATUS or error code
  1735. --*/
  1736. {
  1737. PREGION_DESCRIPTOR Regions;
  1738. ULONG RegionCount;
  1739. ULONG UsedCount,
  1740. RecogCount,
  1741. i;
  1742. STATUS_CODE status;
  1743. BOOLEAN FreeSpace = FALSE;
  1744. status = GetPrimaryDiskRegions(Disk, &Regions, &RegionCount);
  1745. if (status != OK_STATUS) {
  1746. return status;
  1747. }
  1748. for (UsedCount = RecogCount = i = 0; i<RegionCount; i++) {
  1749. if (Regions[i].SysID == SYSID_UNUSED) {
  1750. FreeSpace = TRUE;
  1751. } else {
  1752. UsedCount++;
  1753. if (!IsExtended(Regions[i].SysID) && Regions[i].Recognized) {
  1754. RecogCount++;
  1755. }
  1756. }
  1757. }
  1758. if ((UsedCount < ENTRIES_PER_BOOTSECTOR)
  1759. && FreeSpace
  1760. && (!RecogCount || AllowMultiplePrimaries)) {
  1761. *Allowed = TRUE;
  1762. } else {
  1763. *Allowed = FALSE;
  1764. }
  1765. FreeRegionArray(Regions, RegionCount);
  1766. return OK_STATUS;
  1767. }
  1768. STATUS_CODE
  1769. IsCreationOfExtendedAllowed(
  1770. IN ULONG Disk,
  1771. OUT BOOLEAN *Allowed
  1772. )
  1773. /*++
  1774. Routine Description:
  1775. This routine determines whether creation of an extended partition is
  1776. allowed. This is true when there is a free entry in the MBR,
  1777. there is free primary space on the disk, and there is no existing
  1778. extended partition.
  1779. Arguments:
  1780. Disk - index of disk to check
  1781. Allowed - returns whether creation of an extended partition
  1782. is allowed
  1783. Return Value:
  1784. OK_STATUS or error code
  1785. --*/
  1786. {
  1787. PREGION_DESCRIPTOR Regions;
  1788. ULONG RegionCount;
  1789. ULONG UsedCount,
  1790. FreeCount,
  1791. i;
  1792. STATUS_CODE status;
  1793. status = GetPrimaryDiskRegions(Disk,&Regions,&RegionCount);
  1794. if (status != OK_STATUS) {
  1795. return status;
  1796. }
  1797. for (UsedCount = FreeCount = i = 0; i<RegionCount; i++) {
  1798. if (Regions[i].SysID == SYSID_UNUSED) {
  1799. // BUGBUG should adjust the size here and see if it's non0 first
  1800. // (ie, take into account that the extended partition can't
  1801. // start on cyl 0).
  1802. FreeCount++;
  1803. } else {
  1804. UsedCount++;
  1805. if (IsExtended(Regions[i].SysID)) {
  1806. FreeRegionArray(Regions,RegionCount);
  1807. *Allowed = FALSE;
  1808. return OK_STATUS;
  1809. }
  1810. }
  1811. }
  1812. *Allowed = (BOOLEAN)((UsedCount < ENTRIES_PER_BOOTSECTOR) && FreeCount);
  1813. FreeRegionArray(Regions,RegionCount);
  1814. return OK_STATUS;
  1815. }
  1816. STATUS_CODE
  1817. IsCreationOfLogicalAllowed(
  1818. IN ULONG Disk,
  1819. OUT BOOLEAN *Allowed
  1820. )
  1821. /*++
  1822. Routine Description:
  1823. This routine determines whether creation of a logical volume is
  1824. allowed. This is true when there is an extended partition and
  1825. free space within it.
  1826. Arguments:
  1827. Disk - index of disk to check
  1828. Allowed - returns whether creation of a logical volume is allowed
  1829. Return Value:
  1830. OK_STATUS or error code
  1831. --*/
  1832. {
  1833. PREGION_DESCRIPTOR Regions;
  1834. ULONG RegionCount;
  1835. ULONG i;
  1836. STATUS_CODE status;
  1837. BOOLEAN ExtendedExists;
  1838. *Allowed = FALSE;
  1839. status = DoesExtendedExist(Disk,&ExtendedExists);
  1840. if (status != OK_STATUS) {
  1841. return status;
  1842. }
  1843. if (!ExtendedExists) {
  1844. return OK_STATUS;
  1845. }
  1846. status = GetLogicalDiskRegions(Disk,&Regions,&RegionCount);
  1847. if (status != OK_STATUS) {
  1848. return status;
  1849. }
  1850. for (i = 0; i<RegionCount; i++) {
  1851. if (Regions[i].SysID == SYSID_UNUSED) {
  1852. *Allowed = TRUE;
  1853. break;
  1854. }
  1855. }
  1856. FreeRegionArray(Regions,RegionCount);
  1857. return OK_STATUS;
  1858. }
  1859. STATUS_CODE
  1860. DoesAnyPartitionExist(
  1861. IN ULONG Disk,
  1862. OUT PBOOLEAN AnyExists,
  1863. OUT PBOOLEAN PrimaryExists,
  1864. OUT PBOOLEAN ExtendedExists,
  1865. OUT PBOOLEAN LogicalExists
  1866. )
  1867. /*++
  1868. Routine Description:
  1869. This routine determines whether any partition exists on a given disk.
  1870. This is based on three sub queries: whether there are any primary or
  1871. extended partitions, or logical volumes on the disk.
  1872. Arguments:
  1873. Disk - index of disk to check
  1874. AnyExists - returns whether any partitions exist on Disk
  1875. PrimaryExists - returns whether any primary partitions exist on Disk
  1876. ExtendedExists - returns whether there is an extended partition on Disk
  1877. LogicalExists - returns whether any logical volumes exist on Disk
  1878. Return Value:
  1879. OK_STATUS or error code
  1880. --*/
  1881. {
  1882. STATUS_CODE status;
  1883. if ((status = DoesAnyPrimaryExist(Disk,PrimaryExists )) != OK_STATUS) {
  1884. return status;
  1885. }
  1886. if ((status = DoesExtendedExist (Disk,ExtendedExists)) != OK_STATUS) {
  1887. return status;
  1888. }
  1889. if ((status = DoesAnyLogicalExist(Disk,LogicalExists )) != OK_STATUS) {
  1890. return status;
  1891. }
  1892. *AnyExists = (BOOLEAN)(*PrimaryExists || *ExtendedExists || *LogicalExists);
  1893. return OK_STATUS;
  1894. }
  1895. STATUS_CODE
  1896. DoesAnyPrimaryExist(
  1897. IN ULONG Disk,
  1898. OUT BOOLEAN *Exists
  1899. )
  1900. /*++
  1901. Routine Description:
  1902. This routine determines whether any non-extended primary partition exists
  1903. on a given disk.
  1904. Arguments:
  1905. Disk - index of disk to check
  1906. Exists - returns whether any primary partitions exist on Disk
  1907. Return Value:
  1908. OK_STATUS or error code
  1909. --*/
  1910. {
  1911. PREGION_DESCRIPTOR Regions;
  1912. ULONG RegionCount,
  1913. i;
  1914. STATUS_CODE status;
  1915. status = GetUsedPrimaryDiskRegions(Disk,&Regions,&RegionCount);
  1916. if (status != OK_STATUS) {
  1917. return status;
  1918. }
  1919. *Exists = FALSE;
  1920. for (i=0; i<RegionCount; i++) {
  1921. if (!IsExtended(Regions[i].SysID)) {
  1922. *Exists = TRUE;
  1923. break;
  1924. }
  1925. }
  1926. FreeRegionArray(Regions,RegionCount);
  1927. return OK_STATUS;
  1928. }
  1929. STATUS_CODE
  1930. DoesExtendedExist(
  1931. IN ULONG Disk,
  1932. OUT BOOLEAN *Exists
  1933. )
  1934. /*++
  1935. Routine Description:
  1936. This routine determines whether an extended partition exists
  1937. on a given disk.
  1938. Arguments:
  1939. Disk - index of disk to check
  1940. Exists - returns whether an extended partition exists on Disk
  1941. Return Value:
  1942. OK_STATUS or error code
  1943. --*/
  1944. {
  1945. PREGION_DESCRIPTOR Regions;
  1946. ULONG RegionCount,
  1947. i;
  1948. STATUS_CODE status;
  1949. status = GetUsedPrimaryDiskRegions(Disk,&Regions,&RegionCount);
  1950. if (status != OK_STATUS) {
  1951. return status;
  1952. }
  1953. *Exists = FALSE;
  1954. for (i=0; i<RegionCount; i++) {
  1955. if (IsExtended(Regions[i].SysID)) {
  1956. *Exists = TRUE;
  1957. break;
  1958. }
  1959. }
  1960. FreeRegionArray(Regions,RegionCount);
  1961. return OK_STATUS;
  1962. }
  1963. STATUS_CODE
  1964. DoesAnyLogicalExist(
  1965. IN ULONG Disk,
  1966. OUT BOOLEAN *Exists
  1967. )
  1968. /*++
  1969. Routine Description:
  1970. This routine determines whether any logical volumes exist
  1971. on a given disk.
  1972. Arguments:
  1973. Disk - index of disk to check
  1974. Exists - returns whether any logical volumes exist on Disk
  1975. Return Value:
  1976. OK_STATUS or error code
  1977. --*/
  1978. {
  1979. PREGION_DESCRIPTOR Regions;
  1980. ULONG RegionCount;
  1981. STATUS_CODE status;
  1982. status = GetUsedLogicalDiskRegions(Disk,&Regions,&RegionCount);
  1983. if (status != OK_STATUS) {
  1984. return status;
  1985. }
  1986. *Exists = (BOOLEAN)(RegionCount != 0);
  1987. FreeRegionArray(Regions,RegionCount);
  1988. return OK_STATUS;
  1989. }
  1990. ULONG
  1991. GetDiskCount(
  1992. VOID
  1993. )
  1994. /*++
  1995. Routine Description:
  1996. This routine returns the number of attached partitionable disk
  1997. devices. The returned value is one greater than the maximum index
  1998. allowed for Disk parameters to partitioning engine routines.
  1999. Arguments:
  2000. None.
  2001. Return Value:
  2002. Count of disks.
  2003. --*/
  2004. {
  2005. return CountOfDisks;
  2006. }
  2007. PCHAR
  2008. GetDiskName(
  2009. ULONG Disk
  2010. )
  2011. /*++
  2012. Routine Description:
  2013. This routine returns the system name for the disk device whose
  2014. index is given.
  2015. Arguments:
  2016. Disk - index of disk whose name is desired.
  2017. Return Value:
  2018. System name for the disk device. The caller must not attempt to
  2019. free this buffer or modify it.
  2020. --*/
  2021. {
  2022. return DiskNames[Disk];
  2023. }
  2024. // worker routines for WriteDriveLayout
  2025. VOID
  2026. UnusedEntryFill(
  2027. IN PPARTITION_INFORMATION pinfo,
  2028. IN ULONG EntryCount
  2029. )
  2030. /*++
  2031. Routine Description:
  2032. Initialize a partition information structure.
  2033. Arguments:
  2034. pinfo - the partition information structure to fill in.
  2035. EntryCount - the number of entries in the structure to fill.
  2036. Return Value:
  2037. None
  2038. --*/
  2039. {
  2040. ULONG i;
  2041. LARGE_INTEGER zero;
  2042. zero.QuadPart = 0;
  2043. for (i = 0; i < EntryCount; i++) {
  2044. pinfo[i].StartingOffset = zero;
  2045. pinfo[i].PartitionLength = zero;
  2046. pinfo[i].HiddenSectors = 0;
  2047. pinfo[i].PartitionType = SYSID_UNUSED;
  2048. pinfo[i].BootIndicator = FALSE;
  2049. pinfo[i].RewritePartition = TRUE;
  2050. }
  2051. }
  2052. LARGE_INTEGER
  2053. MakeBootRec(
  2054. ULONG Disk,
  2055. PPARTITION_INFORMATION pInfo,
  2056. PPARTITION pLogical,
  2057. PPARTITION pNextLogical
  2058. )
  2059. /*++
  2060. Routine Description:
  2061. Arguments:
  2062. Disk - the disk number
  2063. pinfo - the partition information for the disk.
  2064. pLogical
  2065. pNextLogical
  2066. Return Value:
  2067. The starting offset.
  2068. --*/
  2069. {
  2070. ULONG entry = 0;
  2071. LARGE_INTEGER bytesPerTrack;
  2072. LARGE_INTEGER sectorsPerTrack;
  2073. LARGE_INTEGER startingOffset;
  2074. bytesPerTrack.QuadPart = DiskGeometryArray[Disk].BytesPerTrack;
  2075. sectorsPerTrack.QuadPart = DiskGeometryArray[Disk].SectorsPerTrack;
  2076. startingOffset.QuadPart = 0;
  2077. if (pLogical) {
  2078. pInfo[entry].StartingOffset.QuadPart = pLogical->Offset.QuadPart + bytesPerTrack.QuadPart;
  2079. pInfo[entry].PartitionLength.QuadPart = pLogical->Length.QuadPart - bytesPerTrack.QuadPart;
  2080. pInfo[entry].HiddenSectors = sectorsPerTrack.LowPart;
  2081. pInfo[entry].RewritePartition = pLogical->Update;
  2082. pInfo[entry].BootIndicator = pLogical->Active;
  2083. pInfo[entry].PartitionType = pLogical->SysID;
  2084. if(pInfo[entry].RewritePartition) {
  2085. startingOffset = pInfo[entry].StartingOffset;
  2086. }
  2087. entry++;
  2088. }
  2089. if (pNextLogical) {
  2090. pInfo[entry].StartingOffset = pNextLogical->Offset;
  2091. pInfo[entry].PartitionLength = pNextLogical->Length;
  2092. pInfo[entry].HiddenSectors = 0;
  2093. pInfo[entry].RewritePartition = TRUE;
  2094. pInfo[entry].BootIndicator = FALSE;
  2095. pInfo[entry].PartitionType = SYSID_EXTENDED;
  2096. entry++;
  2097. }
  2098. UnusedEntryFill(pInfo + entry, ENTRIES_PER_BOOTSECTOR - entry);
  2099. return startingOffset;
  2100. }
  2101. STATUS_CODE
  2102. ZapSector(
  2103. ULONG Disk,
  2104. LARGE_INTEGER Offset
  2105. )
  2106. /*++
  2107. Routine Description:
  2108. This routine writes zeros into a sector at a given offset. This is
  2109. used to clear out a new partition's filesystem boot record, so that
  2110. no previous filesystem appears in a new partition; or to clear out the
  2111. first EBR in the extended partition if there are to be no logical vols.
  2112. Arguments:
  2113. Disk - disk to write to
  2114. Offset - byte offset to a newly created partition on Disk
  2115. Return Value:
  2116. OK_STATUS or error code.
  2117. --*/
  2118. {
  2119. ULONG sectorSize = DiskGeometryArray[Disk].BytesPerSector;
  2120. ULONG i;
  2121. PCHAR sectorBuffer,
  2122. alignedSectorBuffer;
  2123. STATUS_CODE status;
  2124. HANDLE_T handle;
  2125. LARGE_INTEGER temp;
  2126. if ((sectorBuffer = AllocateMemory(2*sectorSize)) == NULL) {
  2127. RETURN_OUT_OF_MEMORY;
  2128. }
  2129. alignedSectorBuffer = (PCHAR)(((ULONG)sectorBuffer+sectorSize) & ~(sectorSize-1));
  2130. for (i=0; i<sectorSize; alignedSectorBuffer[i++] = 0);
  2131. if ((status = LowOpenDisk(GetDiskName(Disk),&handle)) != OK_STATUS) {
  2132. FreeMemory(sectorBuffer);
  2133. return status;
  2134. }
  2135. temp.QuadPart = Offset.QuadPart / sectorSize;
  2136. status = LowWriteSectors(handle,
  2137. sectorSize,
  2138. temp.LowPart,
  2139. 1,
  2140. alignedSectorBuffer);
  2141. LowCloseDisk(handle);
  2142. // Now to make sure the file system really did a dismount,
  2143. // force a mount/verify of the partition. This avoids a
  2144. // problem where HPFS doesn't dismount when asked, but instead
  2145. // marks the volume for verify.
  2146. if ((status = LowOpenDisk(GetDiskName(Disk), &handle)) == OK_STATUS) {
  2147. LowCloseDisk(handle);
  2148. }
  2149. FreeMemory(sectorBuffer);
  2150. return status;
  2151. }
  2152. STATUS_CODE
  2153. WriteDriveLayout(
  2154. IN ULONG Disk
  2155. )
  2156. /*++
  2157. Routine Description:
  2158. This routine writes the current partition layout for a given disk
  2159. out to disk. The high-level PARTITION lists are transformed into
  2160. a DRIVE_LAYOUT_INFORMATION structure before being passed down
  2161. to the low-level partition table writing routine.
  2162. Arguments:
  2163. Disk - index of disk whose on-disk partition structure is to be updated.
  2164. Return Value:
  2165. OK_STATUS or error code.
  2166. --*/
  2167. {
  2168. #define MAX_DISKS 250
  2169. PDRIVE_LAYOUT_INFORMATION driveLayout;
  2170. PPARTITION_INFORMATION pinfo;
  2171. ULONG entryCount;
  2172. ULONG sectorSize;
  2173. STATUS_CODE status;
  2174. LARGE_INTEGER startingOffset,
  2175. extendedStartingOffset;
  2176. PPARTITION nextPartition,
  2177. partition,
  2178. partitionHash[MAX_DISKS];
  2179. extendedStartingOffset.QuadPart = 0;
  2180. memset(partitionHash, 0, sizeof(partitionHash));
  2181. // allocate a huge buffer now to avoid complicated dynamic
  2182. // reallocation schemes later.
  2183. if (!(driveLayout = AllocateMemory((MAX_DISKS + 1) * sizeof(PARTITION_INFORMATION)))) {
  2184. RETURN_OUT_OF_MEMORY;
  2185. }
  2186. pinfo = &driveLayout->PartitionEntry[0];
  2187. // first do the mbr.
  2188. entryCount = 0;
  2189. partition = PrimaryPartitions[Disk];
  2190. sectorSize = DiskGeometryArray[Disk].BytesPerSector;
  2191. while (partition) {
  2192. if (partition->SysID != SYSID_UNUSED) {
  2193. if (IsExtended(partition->SysID)) {
  2194. extendedStartingOffset = partition->Offset;
  2195. } else {
  2196. partitionHash[entryCount] = partition;
  2197. }
  2198. pinfo[entryCount].StartingOffset = partition->Offset;
  2199. pinfo[entryCount].PartitionLength = partition->Length;
  2200. pinfo[entryCount].PartitionType = partition->SysID;
  2201. pinfo[entryCount].BootIndicator = partition->Active;
  2202. pinfo[entryCount].RewritePartition = partition->Update;
  2203. pinfo[entryCount].HiddenSectors = (ULONG) (partition->Offset.QuadPart / sectorSize);
  2204. // if we're creating this partition, clear out the
  2205. // filesystem boot sector.
  2206. if (pinfo[entryCount].RewritePartition
  2207. && (partition->Update != CHANGED_DONT_ZAP)
  2208. && !IsExtended(pinfo[entryCount].PartitionType)) {
  2209. status = ZapSector(Disk,pinfo[entryCount].StartingOffset);
  2210. if (status != OK_STATUS) {
  2211. FreeMemory(driveLayout);
  2212. return status;
  2213. }
  2214. }
  2215. entryCount++;
  2216. }
  2217. partition = partition->Next;
  2218. }
  2219. // fill the remainder of the MBR with unused entries.
  2220. // NOTE that there will thus always be an MBR even if there
  2221. // are no partitions defined.
  2222. UnusedEntryFill(pinfo+entryCount, ENTRIES_PER_BOOTSECTOR - entryCount);
  2223. entryCount = ENTRIES_PER_BOOTSECTOR;
  2224. // now handle the logical volumes.
  2225. // first check to see whether we need a dummy EBR at the beginning
  2226. // of the extended partition. This is the case when there is
  2227. // free space at the beginning of the extended partition.
  2228. #if 0
  2229. // Also handle the case where we are creating an empty extended
  2230. // partition -- need to zap the first sector to eliminate any residue
  2231. // that might start an EBR chain.
  2232. #else
  2233. // BUGBUG 4/24/92 tedm: Currently the io subsystem returns an error
  2234. // status (status_bad_master_boot_record) if any mbr or ebr is bad.
  2235. // Zeroing the first sector of the extended partition therefore causes
  2236. // the whole disk to be seen as empty. So create a blank, but valid,
  2237. // EBR in the 'empty extended partition' case. Code is in the 'else'
  2238. // part of the #if 0, below.
  2239. #endif
  2240. if ((partition = LogicalVolumes[Disk]) && (partition->SysID == SYSID_UNUSED)) {
  2241. if (partition->Next) {
  2242. partitionHash[entryCount] = partition;
  2243. MakeBootRec(Disk, pinfo+entryCount, NULL, partition->Next);
  2244. entryCount += ENTRIES_PER_BOOTSECTOR;
  2245. partition = partition->Next;
  2246. } else {
  2247. #if 0
  2248. status = ZapSector(Disk, extendedStartingOffset);
  2249. if (status != OK_STATUS) {
  2250. FreeMemory(driveLayout);
  2251. return status;
  2252. }
  2253. #else
  2254. MakeBootRec(Disk, pinfo+entryCount, NULL, NULL);
  2255. entryCount += ENTRIES_PER_BOOTSECTOR;
  2256. #endif
  2257. }
  2258. }
  2259. while (partition) {
  2260. if (partition->SysID != SYSID_UNUSED) {
  2261. // find the next logical volume.
  2262. nextPartition = partition->Next;
  2263. while (nextPartition) {
  2264. if (nextPartition->SysID != SYSID_UNUSED) {
  2265. break;
  2266. }
  2267. nextPartition = nextPartition->Next;
  2268. }
  2269. partitionHash[entryCount] = partition;
  2270. startingOffset = MakeBootRec(Disk, pinfo+entryCount, partition, nextPartition);
  2271. // if we're creating a volume, clear out its filesystem
  2272. // boot sector so it starts out fresh.
  2273. if ((startingOffset.QuadPart) && (partition->Update != CHANGED_DONT_ZAP)) {
  2274. status = ZapSector(Disk,startingOffset);
  2275. if (status != OK_STATUS) {
  2276. FreeMemory(driveLayout);
  2277. return status;
  2278. }
  2279. }
  2280. entryCount += ENTRIES_PER_BOOTSECTOR;
  2281. }
  2282. partition = partition->Next;
  2283. }
  2284. driveLayout->PartitionCount = entryCount;
  2285. driveLayout->Signature = Signatures[Disk];
  2286. status = LowSetDiskLayout(DiskNames[Disk], driveLayout);
  2287. if (NT_SUCCESS(status)) {
  2288. // Update the partition numbers in the region structures.
  2289. // ReconcilePartitionNumbers(Disk, driveLayout);
  2290. for (entryCount = 0; entryCount < MAX_DISKS; entryCount++) {
  2291. if (partition = partitionHash[entryCount]) {
  2292. if (partition->Update) {
  2293. pinfo = &driveLayout->PartitionEntry[entryCount];
  2294. partition->PartitionNumber = pinfo->PartitionNumber;
  2295. }
  2296. }
  2297. }
  2298. }
  2299. FreeMemory(driveLayout);
  2300. return status;
  2301. }
  2302. STATUS_CODE
  2303. CommitPartitionChanges(
  2304. IN ULONG Disk
  2305. )
  2306. /*++
  2307. Routine Description:
  2308. This routine is the entry point for updating the on-disk partition
  2309. structures of a disk. The disk is only written to if the partition
  2310. structure has been changed by adding or deleting partitions.
  2311. Arguments:
  2312. Disk - index of disk whose on-disk partition structure is to be updated.
  2313. Return Value:
  2314. OK_STATUS or error code.
  2315. --*/
  2316. {
  2317. PPARTITION p;
  2318. STATUS_CODE status;
  2319. if (!HavePartitionsBeenChanged(Disk)) {
  2320. return OK_STATUS;
  2321. }
  2322. if ((status = WriteDriveLayout(Disk)) != OK_STATUS) {
  2323. return status;
  2324. }
  2325. // BUGBUG for ARC and NT MIPS, update NVRAM vars so partitions are right.
  2326. // Do that here, before partition numbers are reassigned.
  2327. p = PrimaryPartitions[Disk];
  2328. while (p) {
  2329. p->Update = FALSE;
  2330. p->OriginalPartitionNumber = p->PartitionNumber;
  2331. p = p->Next;
  2332. }
  2333. p = LogicalVolumes[Disk];
  2334. while (p) {
  2335. p->Update = FALSE;
  2336. p->OriginalPartitionNumber = p->PartitionNumber;
  2337. p = p->Next;
  2338. }
  2339. ChangesRequested[Disk] = FALSE;
  2340. ChangesCommitted[Disk] = TRUE;
  2341. return OK_STATUS;
  2342. }
  2343. BOOLEAN
  2344. IsRegionCommitted(
  2345. PREGION_DESCRIPTOR RegionDescriptor
  2346. )
  2347. /*++
  2348. Routine Description:
  2349. Given a region descriptor, return TRUE if it actually exists on disk,
  2350. FALSE otherwise.
  2351. Arguments:
  2352. RegionDescriptor - the region to check
  2353. Return Value:
  2354. TRUE - if the region actually exists on disk
  2355. FALSE otherwise.
  2356. --*/
  2357. {
  2358. PPERSISTENT_REGION_DATA regionData;
  2359. regionData = PERSISTENT_DATA(RegionDescriptor);
  2360. if (!regionData) {
  2361. return FALSE;
  2362. }
  2363. return regionData->VolumeExists;
  2364. }
  2365. BOOLEAN
  2366. HavePartitionsBeenChanged(
  2367. IN ULONG Disk
  2368. )
  2369. /*++
  2370. Routine Description:
  2371. This routine returns TRUE if the given disk's partition structures
  2372. have been modified by adding or deleting partitions, since the
  2373. on-disk structures were last written by a call to CommitPartitionChanges
  2374. (or first read).
  2375. Arguments:
  2376. Disk - index of disk to check
  2377. Return Value:
  2378. true if Disk's partition structure has changed.
  2379. --*/
  2380. {
  2381. return ChangesRequested[Disk];
  2382. }
  2383. BOOLEAN
  2384. ChangeCommittedOnDisk(
  2385. IN ULONG Disk
  2386. )
  2387. /*++
  2388. Routine Description:
  2389. This routine will inform the caller if a change was actually committed
  2390. to the disk given.
  2391. Arguments:
  2392. Disk - index of disk to check
  2393. Return Value:
  2394. TRUE if disk was changed
  2395. FALSE otherwise.
  2396. --*/
  2397. {
  2398. return ChangesCommitted[Disk];
  2399. }
  2400. VOID
  2401. ClearCommittedDiskInformation(
  2402. )
  2403. /*++
  2404. Routine Description:
  2405. Clear all knowledge about any changes that have occurred to the
  2406. disks.
  2407. Arguments:
  2408. None
  2409. Return Value:
  2410. None
  2411. --*/
  2412. {
  2413. ULONG i;
  2414. for (i=0; i<CountOfDisks; i++) {
  2415. ChangesCommitted[i] = FALSE;
  2416. }
  2417. }
  2418. VOID
  2419. FdMarkDiskDirty(
  2420. IN ULONG Disk
  2421. )
  2422. /*++
  2423. Routine Description:
  2424. Remember that this disk has had some partitioning changes.
  2425. Arguments:
  2426. Disk - the disk number
  2427. Return Value:
  2428. None
  2429. --*/
  2430. {
  2431. ChangesRequested[Disk] = TRUE;
  2432. }
  2433. VOID
  2434. FdSetPersistentData(
  2435. IN PREGION_DESCRIPTOR Region,
  2436. IN ULONG Data
  2437. )
  2438. /*++
  2439. Routine Description:
  2440. Set the persistent data area for the specified region.
  2441. Arguments:
  2442. Region - the region for which the persistent data is to be set
  2443. Data - the persistent data for the region.
  2444. Return Value:
  2445. None
  2446. --*/
  2447. {
  2448. ((PREGION_DATA)(Region->Reserved))->Partition->PersistentData =
  2449. (PPERSISTENT_REGION_DATA) Data;
  2450. }
  2451. ULONG
  2452. FdGetMinimumSizeMB(
  2453. IN ULONG Disk
  2454. )
  2455. /*++
  2456. Routine Description:
  2457. Return the minimum size for a partition on a given disk.
  2458. This is the rounded size of one cylinder or 1, whichever is greater.
  2459. Arguments:
  2460. Region - region describing the partition to check.
  2461. Return Value:
  2462. Actual offset
  2463. --*/
  2464. {
  2465. LARGE_INTEGER temp;
  2466. temp.QuadPart = DiskGeometryArray[Disk].BytesPerCylinder;
  2467. return max(SIZEMB(temp), 1);
  2468. }
  2469. ULONG
  2470. FdGetMaximumSizeMB(
  2471. IN PREGION_DESCRIPTOR Region,
  2472. IN REGION_TYPE CreationType
  2473. )
  2474. /*++
  2475. Routine Description:
  2476. Given a region of disk determine how much of it may be used to
  2477. create the specified partition type. This code take into consideration
  2478. the many alignment restrictions imposed by early DOS software versions.
  2479. Arguments:
  2480. Region - The affected region
  2481. CreationType - What is being created
  2482. (extended partition/primary partition)
  2483. Return Value:
  2484. The maximum size that a partition of the specified type can be
  2485. to fit within the space available in the region.
  2486. --*/
  2487. {
  2488. PREGION_DATA createData = Region->Reserved;
  2489. LARGE_INTEGER maxSize;
  2490. maxSize = createData->AlignedRegionSize;
  2491. if (!(createData->AlignedRegionOffset.QuadPart)) {
  2492. ULONG delta;
  2493. delta = (CreationType == REGION_EXTENDED)
  2494. ? DiskGeometryArray[Region->Disk].BytesPerCylinder
  2495. : DiskGeometryArray[Region->Disk].BytesPerTrack;
  2496. maxSize.QuadPart -= delta;
  2497. }
  2498. return SIZEMB(maxSize);
  2499. }
  2500. LARGE_INTEGER
  2501. FdGetExactSize(
  2502. IN PREGION_DESCRIPTOR Region,
  2503. IN BOOLEAN ForExtended
  2504. )
  2505. /*++
  2506. Routine Description:
  2507. Arguments:
  2508. Return Value:
  2509. --*/
  2510. {
  2511. PREGION_DATA regionData = Region->Reserved;
  2512. LARGE_INTEGER largeSize = regionData->AlignedRegionSize;
  2513. LARGE_INTEGER bytesPerTrack;
  2514. LARGE_INTEGER bytesPerCylinder;
  2515. bytesPerTrack.QuadPart = DiskGeometryArray[Region->Disk].BytesPerTrack;
  2516. bytesPerCylinder.QuadPart = DiskGeometryArray[Region->Disk].BytesPerCylinder;
  2517. if (Region->RegionType == REGION_LOGICAL) {
  2518. //
  2519. // The region is within the extended partition. It doesn't matter
  2520. // whether it's free space or used -- in either case, we need to
  2521. // account for the reserved EBR track.
  2522. //
  2523. largeSize.QuadPart -= bytesPerTrack.QuadPart;
  2524. } else if (Region->SysID == SYSID_UNUSED) {
  2525. //
  2526. // The region is unused space not inside the extended partition.
  2527. // We must know whether the caller will put a primary or extended
  2528. // partition there -- a primary partition can use all the space, but
  2529. // a logical volume in the extended partition won't include the first
  2530. // track. If the free space starts at offset 0 on the disk, a special
  2531. // calculation must be used to move the start of the partition to
  2532. // skip a track for a primary or a cylinder and a track for an
  2533. // extended+logical.
  2534. //
  2535. if ((!regionData->AlignedRegionOffset.QuadPart) || ForExtended) {
  2536. largeSize.QuadPart -= bytesPerTrack.QuadPart;
  2537. }
  2538. if ((!regionData->AlignedRegionOffset.QuadPart) && ForExtended) {
  2539. largeSize.QuadPart -= bytesPerCylinder.QuadPart;
  2540. }
  2541. }
  2542. return largeSize;
  2543. }
  2544. LARGE_INTEGER
  2545. FdGetExactOffset(
  2546. IN PREGION_DESCRIPTOR Region
  2547. )
  2548. /*++
  2549. Routine Description:
  2550. Determine where a given partition _actually_ starts, which may be
  2551. different than where is appears because of EBR reserved tracks, etc.
  2552. NOTE: This routine is not meant to operate on unused regions or
  2553. extended partitions. In these cases, it just returns the apparant offset.
  2554. Arguments:
  2555. Region - region describing the partition to check.
  2556. Return Value:
  2557. Actual offset
  2558. --*/
  2559. {
  2560. LARGE_INTEGER offset = ((PREGION_DATA)(Region->Reserved))->Partition->Offset;
  2561. if ((Region->SysID != SYSID_UNUSED) && (Region->RegionType == REGION_LOGICAL)) {
  2562. //
  2563. // The region is a logical volume.
  2564. // Account for the reserved EBR track.
  2565. //
  2566. offset.QuadPart += DiskGeometryArray[Region->Disk].BytesPerTrack;
  2567. }
  2568. return offset;
  2569. }
  2570. BOOLEAN
  2571. FdCrosses1024Cylinder(
  2572. IN PREGION_DESCRIPTOR Region,
  2573. IN ULONG CreationSizeMB,
  2574. IN REGION_TYPE RegionType
  2575. )
  2576. /*++
  2577. Routine Description:
  2578. Determine whether a used region corsses the 1024th cylinder, or whether
  2579. a partition created within a free space will cross the 1024th cylinder.
  2580. Arguments:
  2581. Region - region describing the partition to check.
  2582. CreationSizeMB - if the Region is for a free space, this is the size of
  2583. the partition to be checked.
  2584. RegionType - one of REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL
  2585. Return Value:
  2586. TRUE if the end cylinder >= 1024.
  2587. --*/
  2588. {
  2589. LARGE_INTEGER start,
  2590. size,
  2591. end,
  2592. zero;
  2593. if (Region->SysID == SYSID_UNUSED) {
  2594. // Determine the exact size and offset of the partition, according
  2595. // to how CreatePartitionEx() will do it.
  2596. zero.QuadPart = 0;
  2597. DetermineCreateSizeAndOffset(Region,
  2598. zero,
  2599. CreationSizeMB,
  2600. RegionType,
  2601. &start,
  2602. &size);
  2603. } else {
  2604. start = ((PREGION_DATA)(Region->Reserved))->Partition->Offset;
  2605. size = ((PREGION_DATA)(Region->Reserved))->Partition->Length;
  2606. }
  2607. end.QuadPart = (start.QuadPart + size.QuadPart) - 1;
  2608. // End is the last byte in the partition. Divide by the number of
  2609. // bytes in a cylinder and see whether the result is > 1023.
  2610. end.QuadPart = end.QuadPart / DiskGeometryArray[Region->Disk].BytesPerCylinder;
  2611. return (end.QuadPart > 1023);
  2612. }
  2613. BOOLEAN
  2614. IsDiskOffLine(
  2615. IN ULONG Disk
  2616. )
  2617. /*++
  2618. Routine Description:
  2619. Arguments:
  2620. Return Value:
  2621. --*/
  2622. {
  2623. return OffLine[Disk];
  2624. }
  2625. ULONG
  2626. FdGetDiskSignature(
  2627. IN ULONG Disk
  2628. )
  2629. /*++
  2630. Routine Description:
  2631. Arguments:
  2632. Return Value:
  2633. --*/
  2634. {
  2635. return Signatures[Disk];
  2636. }
  2637. VOID
  2638. FdSetDiskSignature(
  2639. IN ULONG Disk,
  2640. IN ULONG Signature
  2641. )
  2642. /*++
  2643. Routine Description:
  2644. Arguments:
  2645. Return Value:
  2646. --*/
  2647. {
  2648. Signatures[Disk] = Signature;
  2649. }
  2650. BOOLEAN
  2651. SignatureIsUniqueToSystem(
  2652. IN ULONG Disk,
  2653. IN ULONG Signature
  2654. )
  2655. /*++
  2656. Routine Description:
  2657. Arguments:
  2658. Return Value:
  2659. --*/
  2660. {
  2661. ULONG index;
  2662. for (index = 0; index < Disk; index++) {
  2663. if (Signatures[index] == Signature) {
  2664. return FALSE;
  2665. }
  2666. }
  2667. return TRUE;
  2668. }