Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4425 lines
125 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. ondisk.cxx
  5. Abstract:
  6. This file contains the implementation for the classes defined in
  7. ondisk.hxx
  8. Author:
  9. Norbert Kusters 15-July-1996
  10. Notes:
  11. Revision History:
  12. --*/
  13. extern "C" {
  14. #include <ntddk.h>
  15. }
  16. #include <ftdisk.h>
  17. #ifdef ALLOC_PRAGMA
  18. #pragma code_seg("PAGE")
  19. #endif
  20. NTSTATUS
  21. IsFormatMediaTypeNEC_98(
  22. IN PDEVICE_OBJECT WholeDisk,
  23. IN ULONG SectorSize,
  24. OUT PBOOLEAN FormatMediaTypeIsNEC_98
  25. )
  26. /*++
  27. Routine Description:
  28. Determine format media type, PC-9800 architecture or PC/AT architecture
  29. Logic of determination:
  30. [removable] - PC/AT architecture
  31. [fixed] and [0x55AA exist] and [non "IPL1"] - PC/AT architecture
  32. [fixed] and [0x55AA exist] and ["IPL1" exist] - PC-9800 architecture
  33. [fixed] and [non 0x55AA ] - PC-9800 architecture
  34. Arguments:
  35. WholeDisk - Supplies the device object.
  36. SectorSize - Supplies the sector size.
  37. FormatMediaTypeIsNEC_98 - Return format type
  38. TRUE - The media was formated by PC-9800 architecture
  39. FALSE - The media was formated by PC/AT architecture
  40. or it was not formated
  41. Return Value:
  42. --*/
  43. {
  44. KEVENT event;
  45. IO_STATUS_BLOCK ioStatus;
  46. PIRP irp;
  47. NTSTATUS status;
  48. ULONG readSize;
  49. PVOID readBuffer;
  50. LARGE_INTEGER byteOffset;
  51. #define IPL1_OFFSET 4
  52. #define BOOT_SIGNATURE_OFFSET ((0x200 / 2) -1)
  53. #define BOOT_RECORD_SIGNATURE (0xAA55)
  54. *FormatMediaTypeIsNEC_98 = FALSE;
  55. // Is this removable?
  56. if (WholeDisk->Characteristics&FILE_REMOVABLE_MEDIA) {
  57. // Removable media is PC/AT architecture.
  58. return STATUS_SUCCESS;
  59. }
  60. // Start at sector 0 of the device.
  61. readSize = SectorSize;
  62. byteOffset.QuadPart = 0;
  63. if (readSize < 512) {
  64. readSize = 512;
  65. }
  66. readBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
  67. readSize < PAGE_SIZE ? PAGE_SIZE : readSize);
  68. if (!readBuffer) {
  69. return STATUS_INSUFFICIENT_RESOURCES;
  70. }
  71. KeInitializeEvent(&event, NotificationEvent, FALSE);
  72. irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, WholeDisk,
  73. readBuffer, readSize, &byteOffset,
  74. &event, &ioStatus);
  75. if (!irp) {
  76. return STATUS_INSUFFICIENT_RESOURCES;
  77. }
  78. status = IoCallDriver(WholeDisk, irp);
  79. if (status == STATUS_PENDING) {
  80. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  81. status = ioStatus.Status;
  82. }
  83. if (!NT_SUCCESS(status)) {
  84. ExFreePool(readBuffer);
  85. return status;
  86. }
  87. if (((PUSHORT) readBuffer)[BOOT_SIGNATURE_OFFSET] ==
  88. BOOT_RECORD_SIGNATURE) {
  89. if (!strncmp((PCHAR) readBuffer + IPL1_OFFSET, "IPL1",
  90. sizeof("IPL1") - 1)) {
  91. // It's PC-9800 Architecture.
  92. *FormatMediaTypeIsNEC_98 = TRUE;
  93. }
  94. } else {
  95. // It's PC-9800 Architecture.
  96. *FormatMediaTypeIsNEC_98 = TRUE;
  97. }
  98. ExFreePool(readBuffer);
  99. return STATUS_SUCCESS;
  100. }
  101. NTSTATUS
  102. FT_LOGICAL_DISK_INFORMATION::Initialize(
  103. IN PROOT_EXTENSION RootExtension,
  104. IN OUT PDEVICE_OBJECT WholeDiskPdo
  105. )
  106. /*++
  107. Routine Description:
  108. This routine reads in the on disk information on the given device
  109. into memory.
  110. Arguments:
  111. RootExtension - Supplies the root extension.
  112. WholeDiskPdo - Supplies the device object for the whole physical disk PDO.
  113. Return Value:
  114. NTSTATUS
  115. --*/
  116. {
  117. KEVENT event;
  118. PIRP irp;
  119. STORAGE_DEVICE_NUMBER deviceNumber;
  120. IO_STATUS_BLOCK ioStatus;
  121. NTSTATUS status;
  122. DISK_GEOMETRY geometry;
  123. PDRIVE_LAYOUT_INFORMATION_EX layout;
  124. ULONG i;
  125. LONGLONG offset, minStartingOffset;
  126. PVOID buffer;
  127. BOOLEAN formatMediaTypeIsNEC_98;
  128. _rootExtension = RootExtension;
  129. _wholeDisk = IoGetAttachedDeviceReference(WholeDiskPdo);
  130. _wholeDiskPdo = WholeDiskPdo;
  131. _diskBuffer = NULL;
  132. _isDiskSuitableForFtOnDisk = TRUE;
  133. status = FtpQueryPartitionInformation(RootExtension, _wholeDisk,
  134. &_diskNumber, NULL, NULL, NULL,
  135. NULL, NULL, NULL, NULL, NULL);
  136. if (!NT_SUCCESS(status)) {
  137. return status;
  138. }
  139. KeInitializeEvent(&event, NotificationEvent, FALSE);
  140. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
  141. _wholeDisk, NULL, 0, &geometry,
  142. sizeof(geometry), FALSE, &event,
  143. &ioStatus);
  144. if (!irp) {
  145. return STATUS_INSUFFICIENT_RESOURCES;
  146. }
  147. status = IoCallDriver(_wholeDisk, irp);
  148. if (status == STATUS_PENDING) {
  149. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  150. status = ioStatus.Status;
  151. }
  152. if (!NT_SUCCESS(status)) {
  153. return status;
  154. }
  155. _sectorSize = geometry.BytesPerSector;
  156. _byteOffset.QuadPart = 1024;
  157. HalExamineMBR(_wholeDisk, _sectorSize, 0x55, &buffer);
  158. if (buffer) {
  159. _byteOffset.QuadPart = 0x3000;
  160. ExFreePool(buffer);
  161. }
  162. if (IsNEC_98) {
  163. status = IsFormatMediaTypeNEC_98(_wholeDisk, _sectorSize,
  164. &formatMediaTypeIsNEC_98);
  165. if (!NT_SUCCESS(status)) {
  166. FtpLogError(_rootExtension, _diskNumber, FT_CANT_READ_ON_DISK,
  167. status, 0);
  168. _isDiskSuitableForFtOnDisk = FALSE;
  169. return status;
  170. }
  171. if (formatMediaTypeIsNEC_98) {
  172. _byteOffset.QuadPart = 17*_sectorSize;
  173. }
  174. }
  175. if (_byteOffset.QuadPart < _sectorSize) {
  176. _byteOffset.QuadPart = _sectorSize;
  177. }
  178. status = FtpReadPartitionTableEx(_wholeDisk, &layout);
  179. if (!NT_SUCCESS(status)) {
  180. return status;
  181. }
  182. minStartingOffset = 0x4000;
  183. for (i = 0; i < layout->PartitionCount; i++) {
  184. offset = layout->PartitionEntry[i].StartingOffset.QuadPart;
  185. if (!offset) {
  186. continue;
  187. }
  188. if (offset < minStartingOffset) {
  189. minStartingOffset = offset;
  190. }
  191. }
  192. ExFreePool(layout);
  193. _length = (4095/_sectorSize + 1)*_sectorSize;
  194. if (_byteOffset.QuadPart + _length > minStartingOffset) {
  195. if (_byteOffset.QuadPart < minStartingOffset) {
  196. _length = (ULONG) (minStartingOffset - _byteOffset.QuadPart);
  197. } else {
  198. _length = 0;
  199. }
  200. }
  201. if (_length) {
  202. _diskBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
  203. _length < PAGE_SIZE ? PAGE_SIZE : _length);
  204. if (!_diskBuffer) {
  205. return STATUS_INSUFFICIENT_RESOURCES;
  206. }
  207. KeInitializeEvent(&event, NotificationEvent, FALSE);
  208. irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, _wholeDisk,
  209. _diskBuffer, _length, &_byteOffset,
  210. &event, &ioStatus);
  211. if (!irp) {
  212. return STATUS_INSUFFICIENT_RESOURCES;
  213. }
  214. status = IoCallDriver(_wholeDisk, irp);
  215. if (status == STATUS_PENDING) {
  216. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  217. status = ioStatus.Status;
  218. }
  219. if (!NT_SUCCESS(status)) {
  220. if (status != STATUS_DEVICE_OFF_LINE) {
  221. FtpLogError(_rootExtension, _diskNumber,
  222. FT_CANT_READ_ON_DISK, status, 0);
  223. }
  224. _isDiskSuitableForFtOnDisk = FALSE;
  225. RtlZeroMemory(_diskBuffer, _length);
  226. status = STATUS_SUCCESS;
  227. }
  228. } else {
  229. _diskBuffer = NULL;
  230. }
  231. return status;
  232. }
  233. NTSTATUS
  234. FT_LOGICAL_DISK_INFORMATION::Write(
  235. )
  236. /*++
  237. Routine Description:
  238. This routine writes out the changes in the disk buffer
  239. back out to disk.
  240. Arguments:
  241. None.
  242. Return Value:
  243. NTSTATUS
  244. --*/
  245. {
  246. KEVENT event;
  247. PIRP irp;
  248. IO_STATUS_BLOCK ioStatus;
  249. NTSTATUS status;
  250. if (!_length) {
  251. return STATUS_SUCCESS;
  252. }
  253. if (!_isDiskSuitableForFtOnDisk) {
  254. ASSERT(FALSE);
  255. return STATUS_SUCCESS;
  256. }
  257. KeInitializeEvent(&event, NotificationEvent, FALSE);
  258. irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, _wholeDisk,
  259. _diskBuffer, _length, &_byteOffset,
  260. &event, &ioStatus);
  261. if (!irp) {
  262. return STATUS_INSUFFICIENT_RESOURCES;
  263. }
  264. status = IoCallDriver(_wholeDisk, irp);
  265. if (status == STATUS_PENDING) {
  266. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  267. status = ioStatus.Status;
  268. }
  269. if (!NT_SUCCESS(status)) {
  270. FtpLogError(GetRootExtension(), QueryDiskNumber(),
  271. FT_CANT_WRITE_ON_DISK, status, 0);
  272. }
  273. return status;
  274. }
  275. PFT_LOGICAL_DISK_DESCRIPTION
  276. FT_LOGICAL_DISK_INFORMATION::AddLogicalDiskDescription(
  277. IN PFT_LOGICAL_DISK_DESCRIPTION LogicalDiskDescription
  278. )
  279. /*++
  280. Routine Description:
  281. This routine adds a new logical disk description at the end of the
  282. list of logical disk descriptions.
  283. Arguments:
  284. LogicalDiskDescription - Supplies a new logical disk description.
  285. Return Value:
  286. A pointer into the on disk buffer where the new logical disk
  287. description was added or NULL.
  288. --*/
  289. {
  290. PFT_LOGICAL_DISK_DESCRIPTION p, last;
  291. PFT_ON_DISK_PREAMBLE preamble;
  292. if (!_length) {
  293. return NULL;
  294. }
  295. if (!_isDiskSuitableForFtOnDisk) {
  296. FtpLogError(GetRootExtension(), QueryDiskNumber(), FT_NOT_FT_CAPABLE,
  297. STATUS_SUCCESS, 0);
  298. return NULL;
  299. }
  300. last = NULL;
  301. for (p = GetFirstLogicalDiskDescription(); p;
  302. p = GetNextLogicalDiskDescription(p)) {
  303. last = p;
  304. }
  305. preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
  306. if (preamble->FtOnDiskSignature == FT_ON_DISK_SIGNATURE &&
  307. preamble->DiskDescriptionVersionNumber !=
  308. FT_ON_DISK_DESCRIPTION_VERSION_NUMBER) {
  309. FtpLogError(GetRootExtension(), QueryDiskNumber(), FT_WRONG_VERSION,
  310. STATUS_SUCCESS, 0);
  311. return NULL;
  312. }
  313. if (last) {
  314. p = (PFT_LOGICAL_DISK_DESCRIPTION)
  315. ((PCHAR) last + last->DiskDescriptionSize);
  316. } else {
  317. preamble->FtOnDiskSignature = FT_ON_DISK_SIGNATURE;
  318. preamble->DiskDescriptionVersionNumber =
  319. FT_ON_DISK_DESCRIPTION_VERSION_NUMBER;
  320. preamble->ByteOffsetToFirstFtLogicalDiskDescription =
  321. sizeof(FT_ON_DISK_PREAMBLE);
  322. preamble->ByteOffsetToReplaceLog = 0;
  323. p = (PFT_LOGICAL_DISK_DESCRIPTION)
  324. ((PCHAR) preamble +
  325. preamble->ByteOffsetToFirstFtLogicalDiskDescription);
  326. }
  327. if ((PCHAR) p - (PCHAR) preamble +
  328. LogicalDiskDescription->DiskDescriptionSize + sizeof(USHORT) >
  329. _length) {
  330. return NULL;
  331. }
  332. ClearReplaceLog();
  333. RtlMoveMemory(p, LogicalDiskDescription,
  334. LogicalDiskDescription->DiskDescriptionSize);
  335. last = (PFT_LOGICAL_DISK_DESCRIPTION) ((PCHAR) p + p->DiskDescriptionSize);
  336. last->DiskDescriptionSize = 0;
  337. return p;
  338. }
  339. ULONG
  340. FT_LOGICAL_DISK_INFORMATION::QueryDiskDescriptionFreeSpace(
  341. )
  342. /*++
  343. Routine Description:
  344. This routine returns the free space for new disk
  345. descriptions.
  346. Arguments:
  347. None.
  348. Return Value:
  349. The free space for new disk descriptions.
  350. --*/
  351. {
  352. PFT_LOGICAL_DISK_DESCRIPTION p, last;
  353. if (!_length) {
  354. return 0;
  355. }
  356. if (!_isDiskSuitableForFtOnDisk) {
  357. FtpLogError(GetRootExtension(), QueryDiskNumber(), FT_NOT_FT_CAPABLE,
  358. STATUS_SUCCESS, 0);
  359. return 0;
  360. }
  361. last = NULL;
  362. for (p = GetFirstLogicalDiskDescription(); p;
  363. p = GetNextLogicalDiskDescription(p)) {
  364. last = p;
  365. }
  366. if (last) {
  367. return _length - ((ULONG)((PCHAR) last - (PCHAR) _diskBuffer) +
  368. last->DiskDescriptionSize + sizeof(USHORT));
  369. } else {
  370. return _length - sizeof(USHORT) - sizeof(FT_ON_DISK_PREAMBLE);
  371. }
  372. }
  373. VOID
  374. FT_LOGICAL_DISK_INFORMATION::DeleteLogicalDiskDescription(
  375. IN PFT_LOGICAL_DISK_DESCRIPTION LogicalDiskDescription
  376. )
  377. /*++
  378. Routine Description:
  379. This routine deletes the given logical disk description from the
  380. logical disk description list.
  381. Arguments:
  382. LogicalDiskDescription - Supplies the logical disk description to
  383. delete.
  384. Return Value:
  385. None.
  386. --*/
  387. {
  388. PFT_LOGICAL_DISK_DESCRIPTION p, last;
  389. BOOLEAN exists;
  390. ULONG moveLength;
  391. PFT_ON_DISK_PREAMBLE preamble;
  392. exists = FALSE;
  393. last = NULL;
  394. for (p = GetFirstLogicalDiskDescription(); p;
  395. p = GetNextLogicalDiskDescription(p)) {
  396. if (p == LogicalDiskDescription) {
  397. exists = TRUE;
  398. }
  399. last = p;
  400. }
  401. if (!exists) {
  402. ASSERT(FALSE);
  403. return;
  404. }
  405. moveLength = (ULONG)((PCHAR) last - (PCHAR) LogicalDiskDescription) +
  406. last->DiskDescriptionSize + sizeof(USHORT) -
  407. LogicalDiskDescription->DiskDescriptionSize;
  408. RtlMoveMemory(LogicalDiskDescription,
  409. (PCHAR) LogicalDiskDescription +
  410. LogicalDiskDescription->DiskDescriptionSize,
  411. moveLength);
  412. if (!GetFirstLogicalDiskDescription()) {
  413. preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
  414. preamble->FtOnDiskSignature = 0;
  415. }
  416. }
  417. BOOLEAN
  418. FT_LOGICAL_DISK_INFORMATION::AddReplaceLog(
  419. IN FT_LOGICAL_DISK_ID ReplacedMemberLogicalDiskId,
  420. IN FT_LOGICAL_DISK_ID NewMemberLogicalDiskId,
  421. IN ULONG NumberOfChangedDiskIds,
  422. IN PFT_LOGICAL_DISK_ID OldLogicalDiskIds,
  423. IN PFT_LOGICAL_DISK_ID NewLogicalDiskIds
  424. )
  425. /*++
  426. Routine Description:
  427. This routine adds the given replace log to the on disk structure.
  428. Arguments:
  429. NumberOfChangedDiskIds - Supplies the number of replaced disk ids.
  430. OldLogicalDiskIds - Supplies the old logical disk ids.
  431. NewLogicalDiskIds - Supplies the new logical disk ids.
  432. Return Value:
  433. FALSE - Insufficient disk space.
  434. TRUE - Success.
  435. --*/
  436. {
  437. PFT_LOGICAL_DISK_DESCRIPTION p, last = NULL;
  438. PFT_LOGICAL_DISK_ID diskId;
  439. ULONG offset, freeSpace, i;
  440. PFT_ON_DISK_PREAMBLE preamble;
  441. for (p = GetFirstLogicalDiskDescription(); p;
  442. p = GetNextLogicalDiskDescription(p)) {
  443. last = p;
  444. }
  445. if (!last) {
  446. return TRUE;
  447. }
  448. diskId = (PFT_LOGICAL_DISK_ID)
  449. ((ULONG_PTR) ((PCHAR) last + last->DiskDescriptionSize +
  450. 2*sizeof(FT_LOGICAL_DISK_ID))/
  451. (2*sizeof(FT_LOGICAL_DISK_ID))*
  452. (2*sizeof(FT_LOGICAL_DISK_ID)));
  453. offset = (ULONG) ((PCHAR) diskId - (PCHAR) _diskBuffer);
  454. freeSpace = _length - offset;
  455. if (freeSpace <
  456. 2*(NumberOfChangedDiskIds + 2)*sizeof(FT_LOGICAL_DISK_ID)) {
  457. return FALSE;
  458. }
  459. preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
  460. preamble->ByteOffsetToReplaceLog = offset;
  461. diskId[0] = ReplacedMemberLogicalDiskId;
  462. diskId[1] = NewMemberLogicalDiskId;
  463. for (i = 0; i < NumberOfChangedDiskIds; i++) {
  464. diskId[2*(i + 1)] = OldLogicalDiskIds[i];
  465. diskId[2*(i + 1) + 1] = NewLogicalDiskIds[i];
  466. }
  467. diskId[2*(i + 1)] = 0;
  468. return TRUE;
  469. }
  470. BOOLEAN
  471. FT_LOGICAL_DISK_INFORMATION::ClearReplaceLog(
  472. )
  473. /*++
  474. Routine Description:
  475. This routine clears the replace log.
  476. Arguments:
  477. None.
  478. Return Value:
  479. None.
  480. --*/
  481. {
  482. PFT_ON_DISK_PREAMBLE preamble;
  483. preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
  484. if (preamble->FtOnDiskSignature != FT_ON_DISK_SIGNATURE ||
  485. preamble->DiskDescriptionVersionNumber !=
  486. FT_ON_DISK_DESCRIPTION_VERSION_NUMBER ||
  487. !preamble->ByteOffsetToReplaceLog) {
  488. return FALSE;
  489. }
  490. preamble->ByteOffsetToReplaceLog = 0;
  491. return TRUE;
  492. }
  493. BOOLEAN
  494. FT_LOGICAL_DISK_INFORMATION::BackOutReplaceOperation(
  495. )
  496. /*++
  497. Routine Description:
  498. This routine backs out the given replace operation.
  499. Arguments:
  500. None.
  501. Return Value:
  502. FALSE - No change was made to the on disk structures.
  503. TRUE - A change was made to the on disk structures.
  504. --*/
  505. {
  506. PFT_ON_DISK_PREAMBLE preamble;
  507. PFT_LOGICAL_DISK_ID diskId;
  508. PFT_LOGICAL_DISK_DESCRIPTION partition;
  509. FT_LOGICAL_DISK_ID child;
  510. BOOLEAN needsBackout;
  511. PFT_LOGICAL_DISK_DESCRIPTION other;
  512. ULONG i;
  513. preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
  514. if (preamble->FtOnDiskSignature != FT_ON_DISK_SIGNATURE ||
  515. preamble->DiskDescriptionVersionNumber !=
  516. FT_ON_DISK_DESCRIPTION_VERSION_NUMBER ||
  517. !preamble->ByteOffsetToReplaceLog) {
  518. return FALSE;
  519. }
  520. diskId = (PFT_LOGICAL_DISK_ID)
  521. ((PCHAR) _diskBuffer + preamble->ByteOffsetToReplaceLog);
  522. for (partition = GetFirstLogicalDiskDescription(); partition;
  523. partition = GetNextLogicalDiskDescription(partition)) {
  524. if (partition->LogicalDiskType != FtPartition) {
  525. continue;
  526. }
  527. child = partition->LogicalDiskId;
  528. needsBackout = TRUE;
  529. for (other = GetNextLogicalDiskDescription(partition); other;
  530. other = GetNextLogicalDiskDescription(other)) {
  531. if (other->LogicalDiskType == FtPartition ||
  532. other->u.Other.ThisMemberLogicalDiskId != child) {
  533. continue;
  534. }
  535. if (child == diskId[1]) {
  536. needsBackout = FALSE;
  537. break;
  538. }
  539. child = other->LogicalDiskId;
  540. }
  541. if (!needsBackout) {
  542. continue;
  543. }
  544. child = partition->LogicalDiskId;
  545. for (other = GetNextLogicalDiskDescription(partition); other;
  546. other = GetNextLogicalDiskDescription(other)) {
  547. if (other->LogicalDiskType == FtPartition ||
  548. other->u.Other.ThisMemberLogicalDiskId != child) {
  549. continue;
  550. }
  551. child = other->LogicalDiskId;
  552. for (i = 2; diskId[i]; i += 2) {
  553. if (other->LogicalDiskId == diskId[i + 1]) {
  554. other->LogicalDiskId = diskId[i];
  555. } else if (other->u.Other.ThisMemberLogicalDiskId ==
  556. diskId[i + 1]) {
  557. other->u.Other.ThisMemberLogicalDiskId = diskId[i];
  558. }
  559. }
  560. }
  561. }
  562. preamble->ByteOffsetToReplaceLog = 0;
  563. return TRUE;
  564. }
  565. BOOLEAN
  566. FT_LOGICAL_DISK_INFORMATION::BackOutReplaceOperationIf(
  567. IN PFT_LOGICAL_DISK_INFORMATION LogicalDiskInformation
  568. )
  569. /*++
  570. Routine Description:
  571. This routine backs out the given replace operation on this
  572. logical disk information if there is evidence from the given
  573. logical disk information that this logical disk information is
  574. invalid.
  575. Arguments:
  576. LogicalDiskInformation - Supplies the logical disk information.
  577. Return Value:
  578. FALSE - No change was made to the on disk structures.
  579. TRUE - A change was made to the on disk structures.
  580. --*/
  581. {
  582. PFT_ON_DISK_PREAMBLE preamble;
  583. PFT_LOGICAL_DISK_ID diskId;
  584. ULONG i;
  585. FT_LOGICAL_DISK_ID oldRootDiskId, replacedDiskId;
  586. PFT_LOGICAL_DISK_DESCRIPTION partition;
  587. FT_LOGICAL_DISK_ID child;
  588. PFT_LOGICAL_DISK_DESCRIPTION other;
  589. preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
  590. if (!preamble ||
  591. preamble->FtOnDiskSignature != FT_ON_DISK_SIGNATURE ||
  592. preamble->DiskDescriptionVersionNumber !=
  593. FT_ON_DISK_DESCRIPTION_VERSION_NUMBER ||
  594. !preamble->ByteOffsetToReplaceLog) {
  595. return FALSE;
  596. }
  597. diskId = (PFT_LOGICAL_DISK_ID)
  598. ((PCHAR) _diskBuffer + preamble->ByteOffsetToReplaceLog);
  599. for (i = 0; ; i++) {
  600. if (!diskId[i]) {
  601. break;
  602. }
  603. }
  604. oldRootDiskId = diskId[i - 2];
  605. replacedDiskId = diskId[0];
  606. for (partition = LogicalDiskInformation->GetFirstLogicalDiskDescription();
  607. partition; partition =
  608. LogicalDiskInformation->GetNextLogicalDiskDescription(partition)) {
  609. if (partition->LogicalDiskType != FtPartition) {
  610. continue;
  611. }
  612. child = partition->LogicalDiskId;
  613. for (other =
  614. LogicalDiskInformation->GetNextLogicalDiskDescription(partition);
  615. other; other =
  616. LogicalDiskInformation->GetNextLogicalDiskDescription(other)) {
  617. if (other->LogicalDiskType == FtPartition ||
  618. other->u.Other.ThisMemberLogicalDiskId != child) {
  619. continue;
  620. }
  621. if (child == replacedDiskId) {
  622. break;
  623. }
  624. child = other->LogicalDiskId;
  625. }
  626. if (child == oldRootDiskId) {
  627. return BackOutReplaceOperation();
  628. }
  629. }
  630. return FALSE;
  631. }
  632. ULONGLONG
  633. FT_LOGICAL_DISK_INFORMATION::GetGptAttributes(
  634. )
  635. /*++
  636. Routine Description:
  637. This routine returns the simulated GPT attribute bits on sector 2 if
  638. present, otherwise it returns 0.
  639. Arguments:
  640. None.
  641. Return Value:
  642. GPT attribute bits.
  643. --*/
  644. {
  645. GUID* pguid;
  646. PULONGLONG p;
  647. pguid = (GUID*) _diskBuffer;
  648. if (!pguid) {
  649. return 0;
  650. }
  651. if (!IsEqualGUID(*pguid, PARTITION_BASIC_DATA_GUID)) {
  652. return 0;
  653. }
  654. p = (PULONGLONG) ((PCHAR) _diskBuffer + sizeof(GUID));
  655. return *p;
  656. }
  657. NTSTATUS
  658. FT_LOGICAL_DISK_INFORMATION::SetGptAttributes(
  659. IN ULONGLONG GptAttributes
  660. )
  661. /*++
  662. Routine Description:
  663. This routine sets the GPT simulated attributes bits on sector 2 of this
  664. MBR disk.
  665. Arguments:
  666. GptAttributes - Supplies the GPT attributes.
  667. Return Value:
  668. NTSTATUS
  669. --*/
  670. {
  671. LONGLONG offset;
  672. PFT_ON_DISK_PREAMBLE preamble;
  673. GUID* pguid;
  674. PULONGLONG p;
  675. offset = 1024;
  676. if (offset < _sectorSize) {
  677. offset = _sectorSize;
  678. }
  679. preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
  680. if (!_diskBuffer || !_isDiskSuitableForFtOnDisk ||
  681. _byteOffset.QuadPart != offset ||
  682. preamble->FtOnDiskSignature == FT_ON_DISK_SIGNATURE) {
  683. return STATUS_INVALID_PARAMETER;
  684. }
  685. pguid = (GUID*) _diskBuffer;
  686. *pguid = PARTITION_BASIC_DATA_GUID;
  687. p = (PULONGLONG) ((PCHAR) _diskBuffer + sizeof(GUID));
  688. *p = GptAttributes;
  689. return Write();
  690. }
  691. FT_LOGICAL_DISK_INFORMATION::~FT_LOGICAL_DISK_INFORMATION(
  692. )
  693. /*++
  694. Routine Description:
  695. This routine is the destructor for this class.
  696. Arguments:
  697. None.
  698. Return Value:
  699. None.
  700. --*/
  701. {
  702. if (_wholeDisk != _wholeDiskPdo) {
  703. ObDereferenceObject(_wholeDisk);
  704. }
  705. if (_diskBuffer) {
  706. ExFreePool(_diskBuffer);
  707. }
  708. }
  709. NTSTATUS
  710. FT_LOGICAL_DISK_INFORMATION_SET::Initialize(
  711. )
  712. /*++
  713. Routine Description:
  714. This routine initializes the class for use.
  715. Arguments:
  716. None.
  717. Return Value:
  718. NTSTATUS
  719. --*/
  720. {
  721. _numberOfLogicalDiskInformations = 0;
  722. _arrayOfLogicalDiskInformations = NULL;
  723. _numberOfRootLogicalDisksIds = 0;
  724. _arrayOfRootLogicalDiskIds = NULL;
  725. return STATUS_SUCCESS;
  726. }
  727. NTSTATUS
  728. FT_LOGICAL_DISK_INFORMATION_SET::AddLogicalDiskInformation(
  729. IN PFT_LOGICAL_DISK_INFORMATION LogicalDiskInformation,
  730. OUT PBOOLEAN ChangedLogicalDiskIds
  731. )
  732. /*++
  733. Routine Description:
  734. This routine adds a logical disk information structure to this
  735. set of logical disk information structures.
  736. Arguments:
  737. LogicalDiskInformation - Supplies the disk information to add.
  738. ChangedLogicalDiskIds - Returns whether or not any existing logical
  739. disk ids have changed.
  740. Return Value:
  741. NTSTATUS
  742. --*/
  743. {
  744. NTSTATUS status;
  745. PDRIVE_LAYOUT_INFORMATION_EX layout;
  746. PFT_LOGICAL_DISK_DESCRIPTION p, q, r;
  747. ULONG numEntries, i, j;
  748. PFT_LOGICAL_DISK_INFORMATION* n;
  749. BOOLEAN error;
  750. PPARTITION_INFORMATION_EX partInfo;
  751. ULONG configLength, stateLength;
  752. PCHAR pc, qc;
  753. ULONG uniqueError;
  754. if (ChangedLogicalDiskIds) {
  755. *ChangedLogicalDiskIds = FALSE;
  756. }
  757. // Check for any partial replace operations that need to be backed out.
  758. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  759. if (_arrayOfLogicalDiskInformations[i]->BackOutReplaceOperationIf(
  760. LogicalDiskInformation)) {
  761. _arrayOfLogicalDiskInformations[i]->Write();
  762. if (ChangedLogicalDiskIds) {
  763. *ChangedLogicalDiskIds = TRUE;
  764. }
  765. }
  766. if (LogicalDiskInformation->BackOutReplaceOperationIf(
  767. _arrayOfLogicalDiskInformations[i])) {
  768. LogicalDiskInformation->Write();
  769. }
  770. }
  771. // Read in the partition table for future reference.
  772. status = FtpReadPartitionTableEx(LogicalDiskInformation->GetWholeDisk(),
  773. &layout);
  774. if (!NT_SUCCESS(status)) {
  775. return status;
  776. }
  777. // First count how many entries are in the given list and also perform
  778. // a sanity check on these entries.
  779. numEntries = 0;
  780. for (p = LogicalDiskInformation->GetFirstLogicalDiskDescription(); p; ) {
  781. if (!p->DiskDescriptionSize) {
  782. break;
  783. }
  784. error = FALSE;
  785. if (p->DiskDescriptionSize < sizeof(FT_LOGICAL_DISK_DESCRIPTION) ||
  786. p->LogicalDiskId == 0) {
  787. DbgPrint("Disk Description too small, %x, or no logical disk id %I64x\n",
  788. p->DiskDescriptionSize, p->LogicalDiskId);
  789. error = TRUE;
  790. uniqueError = 1;
  791. }
  792. if (!error && p->LogicalDiskType == FtPartition) {
  793. for (i = 0; i < layout->PartitionCount; i++) {
  794. partInfo = &layout->PartitionEntry[i];
  795. if (partInfo->StartingOffset.QuadPart ==
  796. p->u.FtPartition.ByteOffset &&
  797. (partInfo->Mbr.PartitionType&0x80)) {
  798. break;
  799. }
  800. }
  801. if (i == layout->PartitionCount) {
  802. error = TRUE;
  803. uniqueError = 2;
  804. DbgPrint("Partition not found in partition table.\n");
  805. DbgPrint("Partition start = %I64x\n", p->u.FtPartition.ByteOffset);
  806. DbgPrint("Drive layout partition count = %d\n", layout->PartitionCount);
  807. } else if (GetLogicalDiskDescription(p->LogicalDiskId, 0)) {
  808. error = TRUE;
  809. uniqueError = 3;
  810. DbgPrint("Duplicate logical disk description on other disk: %I64x\n",
  811. p->LogicalDiskId);
  812. } else {
  813. for (q = LogicalDiskInformation->GetFirstLogicalDiskDescription();
  814. q != p;
  815. q = LogicalDiskInformation->GetNextLogicalDiskDescription(q)) {
  816. if (p->LogicalDiskId == q->LogicalDiskId) {
  817. error = TRUE;
  818. uniqueError = 4;
  819. DbgPrint("Duplicate logical disk description on same disk: %I64x\n",
  820. p->LogicalDiskId);
  821. } else if (q->LogicalDiskType == FtPartition &&
  822. p->u.FtPartition.ByteOffset ==
  823. q->u.FtPartition.ByteOffset) {
  824. error = TRUE;
  825. uniqueError = 100;
  826. DbgPrint("%I64x and %I64x are FtPartitions pointing to offset %x\n",
  827. p->LogicalDiskId, q->LogicalDiskId,
  828. p->u.FtPartition.ByteOffset);
  829. }
  830. }
  831. }
  832. } else if (!error) {
  833. for (q = LogicalDiskInformation->GetFirstLogicalDiskDescription();
  834. q != p;
  835. q = LogicalDiskInformation->GetNextLogicalDiskDescription(q)) {
  836. if (p->u.Other.ThisMemberLogicalDiskId == q->LogicalDiskId) {
  837. break;
  838. }
  839. }
  840. if (p == q) {
  841. error = TRUE;
  842. uniqueError = 5;
  843. DbgPrint("This member logical disk id not found %I64x\n",
  844. p->u.Other.ThisMemberLogicalDiskId);
  845. }
  846. if (p->u.Other.ThisMemberNumber >= p->u.Other.NumberOfMembers) {
  847. error = TRUE;
  848. uniqueError = 6;
  849. DbgPrint("This member number %d >= number of members %d\n",
  850. p->u.Other.ThisMemberNumber, p->u.Other.NumberOfMembers);
  851. }
  852. if (p->u.Other.ThisMemberLogicalDiskId == p->LogicalDiskId) {
  853. error = TRUE;
  854. uniqueError = 7;
  855. DbgPrint("This member logical disk == logical disk == %I64x\n",
  856. p->LogicalDiskId);
  857. }
  858. if (p->u.Other.ByteOffsetToConfigurationInformation &&
  859. p->u.Other.ByteOffsetToConfigurationInformation <
  860. sizeof(FT_LOGICAL_DISK_DESCRIPTION)) {
  861. error = TRUE;
  862. uniqueError = 8;
  863. DbgPrint("Byte offset to config info too small: %d\n",
  864. p->u.Other.ByteOffsetToConfigurationInformation);
  865. }
  866. if (p->u.Other.ByteOffsetToStateInformation &&
  867. p->u.Other.ByteOffsetToStateInformation <
  868. sizeof(FT_LOGICAL_DISK_DESCRIPTION)) {
  869. error = TRUE;
  870. uniqueError = 9;
  871. DbgPrint("Byte offset to state info too small: %d\n",
  872. p->u.Other.ByteOffsetToStateInformation);
  873. }
  874. if (p->u.Other.ByteOffsetToConfigurationInformation &&
  875. p->u.Other.ByteOffsetToStateInformation &&
  876. p->u.Other.ByteOffsetToConfigurationInformation >=
  877. p->u.Other.ByteOffsetToStateInformation) {
  878. error = TRUE;
  879. uniqueError = 10;
  880. DbgPrint("Config info %d past state info %d\n",
  881. p->u.Other.ByteOffsetToConfigurationInformation,
  882. p->u.Other.ByteOffsetToStateInformation);
  883. }
  884. if (p->u.Other.ByteOffsetToConfigurationInformation >=
  885. p->DiskDescriptionSize) {
  886. error = TRUE;
  887. uniqueError = 11;
  888. DbgPrint("Byte offset to config info too large: %d vs. %d\n",
  889. p->u.Other.ByteOffsetToConfigurationInformation,
  890. p->DiskDescriptionSize);
  891. }
  892. if (p->u.Other.ByteOffsetToStateInformation >=
  893. p->DiskDescriptionSize) {
  894. error = TRUE;
  895. uniqueError = 12;
  896. DbgPrint("Byte offset to state info too large: %d vs. %d\n",
  897. p->u.Other.ByteOffsetToStateInformation,
  898. p->DiskDescriptionSize);
  899. }
  900. if (!error && p->u.Other.ByteOffsetToConfigurationInformation) {
  901. if (p->u.Other.ByteOffsetToStateInformation) {
  902. configLength = p->u.Other.ByteOffsetToStateInformation -
  903. p->u.Other.ByteOffsetToConfigurationInformation;
  904. } else {
  905. configLength = p->DiskDescriptionSize -
  906. p->u.Other.ByteOffsetToConfigurationInformation;
  907. }
  908. switch (p->LogicalDiskType) {
  909. case FtStripeSet:
  910. if (configLength <
  911. sizeof(FT_STRIPE_SET_CONFIGURATION_INFORMATION)) {
  912. error = TRUE;
  913. uniqueError = 13;
  914. DbgPrint("Stripe config too small: %d\n",
  915. configLength);
  916. }
  917. break;
  918. case FtMirrorSet:
  919. if (configLength <
  920. sizeof(FT_MIRROR_SET_CONFIGURATION_INFORMATION)) {
  921. error = TRUE;
  922. uniqueError = 14;
  923. DbgPrint("Mirror config too small: %d\n",
  924. configLength);
  925. }
  926. break;
  927. case FtStripeSetWithParity:
  928. if (configLength <
  929. sizeof(FT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION)) {
  930. error = TRUE;
  931. uniqueError = 15;
  932. DbgPrint("SWP config too small: %d\n",
  933. configLength);
  934. }
  935. break;
  936. case FtRedistribution:
  937. if (configLength <
  938. sizeof(FT_REDISTRIBUTION_CONFIGURATION_INFORMATION)) {
  939. error = TRUE;
  940. uniqueError = 16;
  941. DbgPrint("Redistrubution config too small: %d\n",
  942. configLength);
  943. }
  944. break;
  945. }
  946. }
  947. if (!error && p->u.Other.ByteOffsetToStateInformation) {
  948. stateLength = p->DiskDescriptionSize -
  949. p->u.Other.ByteOffsetToStateInformation;
  950. switch (p->LogicalDiskType) {
  951. case FtMirrorSet:
  952. case FtStripeSetWithParity:
  953. if (stateLength <
  954. sizeof(FT_MIRROR_AND_SWP_STATE_INFORMATION)) {
  955. error = TRUE;
  956. uniqueError = 17;
  957. DbgPrint("State too small: %d\n", stateLength);
  958. }
  959. break;
  960. case FtRedistribution:
  961. if (stateLength <
  962. sizeof(FT_REDISTRIBUTION_STATE_INFORMATION)) {
  963. error = TRUE;
  964. uniqueError = 18;
  965. DbgPrint("Redist State too small: %d\n", stateLength);
  966. }
  967. break;
  968. }
  969. }
  970. if (error) {
  971. q = NULL;
  972. } else {
  973. if (!(q = GetLogicalDiskDescription(p->LogicalDiskId, 0))) {
  974. for (q = LogicalDiskInformation->GetFirstLogicalDiskDescription();
  975. q != p;
  976. q = LogicalDiskInformation->GetNextLogicalDiskDescription(q)) {
  977. if (q->LogicalDiskId == p->LogicalDiskId) {
  978. break;
  979. }
  980. }
  981. if (q == p) {
  982. q = NULL;
  983. }
  984. if (q) {
  985. for (r = q; r != p;
  986. r = LogicalDiskInformation->
  987. GetNextLogicalDiskDescription(r)) {
  988. if (r->LogicalDiskId == p->LogicalDiskId) {
  989. if (p->u.Other.ThisMemberNumber ==
  990. r->u.Other.ThisMemberNumber ||
  991. p->u.Other.ThisMemberLogicalDiskId ==
  992. r->u.Other.ThisMemberLogicalDiskId) {
  993. error = TRUE;
  994. uniqueError = 19;
  995. DbgPrint("Matching logical disks %I64x\n",
  996. p->LogicalDiskId);
  997. DbgPrint("have same member number %d, %d\n",
  998. p->u.Other.ThisMemberNumber,
  999. r->u.Other.ThisMemberNumber);
  1000. DbgPrint("or same member disk id %I64x, %I64x\n",
  1001. p->u.Other.ThisMemberLogicalDiskId,
  1002. r->u.Other.ThisMemberLogicalDiskId);
  1003. break;
  1004. }
  1005. }
  1006. }
  1007. }
  1008. }
  1009. }
  1010. if (q) {
  1011. if (p->DiskDescriptionSize != q->DiskDescriptionSize ||
  1012. p->LogicalDiskType != q->LogicalDiskType ||
  1013. p->u.Other.NumberOfMembers !=
  1014. q->u.Other.NumberOfMembers ||
  1015. p->u.Other.ByteOffsetToConfigurationInformation !=
  1016. q->u.Other.ByteOffsetToConfigurationInformation ||
  1017. p->u.Other.ByteOffsetToStateInformation !=
  1018. q->u.Other.ByteOffsetToStateInformation) {
  1019. error = TRUE;
  1020. uniqueError = 20;
  1021. DbgPrint("Matching logical disks %I64x\n", p->LogicalDiskId);
  1022. DbgPrint("have different description size %d, %d\n",
  1023. p->DiskDescriptionSize, q->DiskDescriptionSize);
  1024. DbgPrint("or different logical disk type %d, %d\n",
  1025. p->LogicalDiskType, q->LogicalDiskType);
  1026. DbgPrint("or different number of members %d, %d\n",
  1027. p->u.Other.NumberOfMembers, q->u.Other.NumberOfMembers);
  1028. DbgPrint("or different offsets to config %d, %d\n",
  1029. p->u.Other.ByteOffsetToConfigurationInformation,
  1030. q->u.Other.ByteOffsetToConfigurationInformation);
  1031. DbgPrint("or different offsets to state %d, %d\n",
  1032. p->u.Other.ByteOffsetToStateInformation,
  1033. q->u.Other.ByteOffsetToStateInformation);
  1034. }
  1035. if (!error &&
  1036. p->u.Other.ByteOffsetToConfigurationInformation) {
  1037. pc = (PCHAR) p +
  1038. p->u.Other.ByteOffsetToConfigurationInformation;
  1039. qc = (PCHAR) q +
  1040. q->u.Other.ByteOffsetToConfigurationInformation;
  1041. if (RtlCompareMemory(pc, qc, configLength) !=
  1042. configLength) {
  1043. error = TRUE;
  1044. uniqueError = 21;
  1045. DbgPrint("Matching logical disks %I64x\n",
  1046. p->LogicalDiskId);
  1047. DbgPrint("have different configuration information\n");
  1048. }
  1049. }
  1050. }
  1051. if (!error) {
  1052. for (i = 0; q = GetLogicalDiskDescription(p->LogicalDiskId, i);
  1053. i++) {
  1054. if (q->u.Other.ThisMemberLogicalDiskId ==
  1055. p->u.Other.ThisMemberLogicalDiskId &&
  1056. q->u.Other.ThisMemberNumber !=
  1057. p->u.Other.ThisMemberNumber) {
  1058. error = TRUE;
  1059. uniqueError = 22;
  1060. DbgPrint("Different members map to the same disk\n");
  1061. DbgPrint("--- %I64x, member %d and member %d\n",
  1062. p->u.Other.ThisMemberLogicalDiskId,
  1063. q->u.Other.ThisMemberNumber,
  1064. p->u.Other.ThisMemberNumber);
  1065. }
  1066. if (q->u.Other.ThisMemberNumber ==
  1067. p->u.Other.ThisMemberNumber &&
  1068. q->u.Other.ThisMemberLogicalDiskId !=
  1069. p->u.Other.ThisMemberLogicalDiskId) {
  1070. error = TRUE;
  1071. uniqueError = 23;
  1072. DbgPrint("Member %d of %I64x is defined twice.\n",
  1073. q->u.Other.ThisMemberNumber,
  1074. p->LogicalDiskId);
  1075. DbgPrint("---- once as %I64x and then as %I64x.\n",
  1076. q->u.Other.ThisMemberLogicalDiskId,
  1077. p->u.Other.ThisMemberLogicalDiskId);
  1078. }
  1079. }
  1080. }
  1081. }
  1082. if (!error) {
  1083. q = GetParentLogicalDiskDescription(p->LogicalDiskId);
  1084. for (r = LogicalDiskInformation->
  1085. GetNextLogicalDiskDescription(p); r;
  1086. r = LogicalDiskInformation->
  1087. GetNextLogicalDiskDescription(r)) {
  1088. if (r->LogicalDiskType != FtPartition &&
  1089. r->u.Other.ThisMemberLogicalDiskId ==
  1090. p->LogicalDiskId) {
  1091. break;
  1092. }
  1093. }
  1094. if (q) {
  1095. if (!r) {
  1096. // The set indicates that p->LogicalDiskId has a parent
  1097. // but this logical disk information does not have a
  1098. // parent. Therefore, add a parent to match.
  1099. LogicalDiskInformation->AddLogicalDiskDescription(q);
  1100. LogicalDiskInformation->Write();
  1101. } else if (q->LogicalDiskId != r->LogicalDiskId ||
  1102. q->u.Other.ThisMemberNumber !=
  1103. r->u.Other.ThisMemberNumber) {
  1104. error = TRUE;
  1105. uniqueError = 24;
  1106. DbgPrint("No parent on this disk info for %I64x\n",
  1107. p->LogicalDiskId);
  1108. }
  1109. } else if (r && GetLogicalDiskDescription(p->LogicalDiskId, 0)) {
  1110. error = TRUE;
  1111. uniqueError = 25;
  1112. DbgPrint("Parent on this disk info that doesn't exist\n");
  1113. DbgPrint("in the set. %I64x\n", p->LogicalDiskId,
  1114. r->LogicalDiskId);
  1115. }
  1116. }
  1117. if (error) {
  1118. FtpLogError(LogicalDiskInformation->GetRootExtension(),
  1119. LogicalDiskInformation->QueryDiskNumber(),
  1120. FT_CORRUPT_DISK_DESCRIPTION, STATUS_SUCCESS,
  1121. uniqueError);
  1122. DbgPrint("Deleting logical disk description %I64x\n",
  1123. p->LogicalDiskId);
  1124. DbgPrint("Description size = %d\n", p->DiskDescriptionSize);
  1125. DbgPrint("Disk type = %d\n", p->LogicalDiskType);
  1126. if (p->LogicalDiskType == FtPartition) {
  1127. DbgPrint("Byte offset = %I64x\n", p->u.FtPartition.ByteOffset);
  1128. } else {
  1129. DbgPrint("This member = %I64x\n", p->u.Other.ThisMemberLogicalDiskId);
  1130. DbgPrint("This member number = %d\n", p->u.Other.ThisMemberNumber);
  1131. DbgPrint("Number of members = %d\n", p->u.Other.NumberOfMembers);
  1132. DbgPrint("Offset to config = %d\n", p->u.Other.ByteOffsetToConfigurationInformation);
  1133. DbgPrint("Offset to state = %d\n", p->u.Other.ByteOffsetToStateInformation);
  1134. }
  1135. LogicalDiskInformation->DeleteLogicalDiskDescription(p);
  1136. LogicalDiskInformation->Write();
  1137. } else {
  1138. p = LogicalDiskInformation->GetNextLogicalDiskDescription(p);
  1139. numEntries++;
  1140. }
  1141. }
  1142. ExFreePool(layout);
  1143. // Realloc the logical disk informations array.
  1144. n = (PFT_LOGICAL_DISK_INFORMATION*)
  1145. ExAllocatePool(NonPagedPool, sizeof(PFT_LOGICAL_DISK_INFORMATION)*
  1146. (_numberOfLogicalDiskInformations + 1));
  1147. if (!n) {
  1148. return STATUS_INSUFFICIENT_RESOURCES;
  1149. }
  1150. if (_numberOfLogicalDiskInformations) {
  1151. RtlMoveMemory(n, _arrayOfLogicalDiskInformations,
  1152. sizeof(PFT_LOGICAL_DISK_INFORMATION)*
  1153. _numberOfLogicalDiskInformations);
  1154. ExFreePool(_arrayOfLogicalDiskInformations);
  1155. }
  1156. _arrayOfLogicalDiskInformations = n;
  1157. // Realloc the root array so that it is at least large enough.
  1158. if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + numEntries)) {
  1159. return STATUS_INSUFFICIENT_RESOURCES;
  1160. }
  1161. // Now add the logical disk information to this list.
  1162. _arrayOfLogicalDiskInformations[_numberOfLogicalDiskInformations++] =
  1163. LogicalDiskInformation;
  1164. // Recompute the list of root disk ids.
  1165. RecomputeArrayOfRootLogicalDiskIds();
  1166. return STATUS_SUCCESS;
  1167. }
  1168. NTSTATUS
  1169. FT_LOGICAL_DISK_INFORMATION_SET::RemoveLogicalDiskInformation(
  1170. IN OUT PDEVICE_OBJECT WholeDiskPdo
  1171. )
  1172. /*++
  1173. Routine Description:
  1174. This routine removes the logical disk information associated with the
  1175. given whole disk device object from the disk information set.
  1176. Arguments:
  1177. WholeDiskPdo - Supplies the device object.
  1178. Return Value:
  1179. NTSTATUS
  1180. --*/
  1181. {
  1182. ULONG i;
  1183. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1184. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1185. diskInfo = _arrayOfLogicalDiskInformations[i];
  1186. if (diskInfo->GetWholeDiskPdo() == WholeDiskPdo) {
  1187. break;
  1188. }
  1189. }
  1190. if (i == _numberOfLogicalDiskInformations) {
  1191. return STATUS_NOT_FOUND;
  1192. }
  1193. _numberOfLogicalDiskInformations--;
  1194. RtlMoveMemory(&_arrayOfLogicalDiskInformations[i],
  1195. &_arrayOfLogicalDiskInformations[i + 1],
  1196. (_numberOfLogicalDiskInformations - i)*
  1197. sizeof(PFT_LOGICAL_DISK_INFORMATION));
  1198. RecomputeArrayOfRootLogicalDiskIds();
  1199. delete diskInfo;
  1200. return STATUS_SUCCESS;
  1201. }
  1202. BOOLEAN
  1203. FT_LOGICAL_DISK_INFORMATION_SET::IsDiskInSet(
  1204. IN OUT PDEVICE_OBJECT WholeDiskPdo
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. This routine removes the logical disk information associated with the
  1209. given whole disk device object from the disk information set.
  1210. Arguments:
  1211. WholeDiskPdo - Supplies the device object.
  1212. Return Value:
  1213. FALSE - The PDO is not in the set.
  1214. TRUE - The PDO is in the set.
  1215. --*/
  1216. {
  1217. ULONG i;
  1218. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1219. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1220. diskInfo = _arrayOfLogicalDiskInformations[i];
  1221. if (diskInfo->GetWholeDiskPdo() == WholeDiskPdo) {
  1222. return TRUE;
  1223. }
  1224. }
  1225. return FALSE;
  1226. }
  1227. PFT_LOGICAL_DISK_DESCRIPTION
  1228. FT_LOGICAL_DISK_INFORMATION_SET::GetLogicalDiskDescription(
  1229. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  1230. IN ULONG InstanceNumber
  1231. )
  1232. /*++
  1233. Routine Description:
  1234. This routine returns the logical disk description for the given
  1235. instance number and logical disk id.
  1236. Arguments:
  1237. LogicalDiskId - Supplies the logical disk id.
  1238. InstanceNumber - Supplies the instance number.
  1239. Return Value:
  1240. A logical disk decription.
  1241. --*/
  1242. {
  1243. ULONG i, instanceNumber;
  1244. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1245. PFT_LOGICAL_DISK_DESCRIPTION p;
  1246. instanceNumber = 0;
  1247. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1248. diskInfo = _arrayOfLogicalDiskInformations[i];
  1249. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  1250. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  1251. if (p->LogicalDiskId == LogicalDiskId) {
  1252. if (InstanceNumber == instanceNumber) {
  1253. return p;
  1254. } else {
  1255. instanceNumber++;
  1256. }
  1257. }
  1258. }
  1259. }
  1260. return NULL;
  1261. }
  1262. ULONG
  1263. FT_LOGICAL_DISK_INFORMATION_SET::QueryNumberOfRootLogicalDiskIds(
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. This routine returns the number of root logical disk ids.
  1268. Arguments:
  1269. None.
  1270. Return Value:
  1271. The number of root logical disk ids.
  1272. --*/
  1273. {
  1274. return _numberOfRootLogicalDisksIds;
  1275. }
  1276. FT_LOGICAL_DISK_ID
  1277. FT_LOGICAL_DISK_INFORMATION_SET::QueryRootLogicalDiskId(
  1278. IN ULONG Index
  1279. )
  1280. /*++
  1281. Routine Description:
  1282. This routine returns the 'Index'th root logical disk id.
  1283. Arguments:
  1284. Index - Supplies the 0 based index.
  1285. Return Value:
  1286. The 'Index'th root logical disk id.
  1287. --*/
  1288. {
  1289. if (Index >= _numberOfRootLogicalDisksIds) {
  1290. return 0;
  1291. }
  1292. return _arrayOfRootLogicalDiskIds[Index];
  1293. }
  1294. FT_LOGICAL_DISK_ID
  1295. FT_LOGICAL_DISK_INFORMATION_SET::QueryRootLogicalDiskIdForContainedPartition(
  1296. IN ULONG DiskNumber,
  1297. IN LONGLONG Offset
  1298. )
  1299. /*++
  1300. Routine Description:
  1301. This routine returns the root logical disk id of the logical disk that
  1302. contains the given partition.
  1303. Arguments:
  1304. DiskNumber - Supplies the disk number of the whole disk
  1305. of the partition.
  1306. Offset - Supplies the offset of the partition.
  1307. Return Value:
  1308. The logical disk id of the root disk containing the given partition or 0.
  1309. --*/
  1310. {
  1311. ULONG i;
  1312. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1313. PFT_LOGICAL_DISK_DESCRIPTION p;
  1314. FT_LOGICAL_DISK_ID id;
  1315. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1316. diskInfo = _arrayOfLogicalDiskInformations[i];
  1317. if (diskInfo->QueryDiskNumber() == DiskNumber) {
  1318. break;
  1319. }
  1320. }
  1321. if (i == _numberOfLogicalDiskInformations) {
  1322. return 0;
  1323. }
  1324. id = 0;
  1325. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  1326. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  1327. if (id) {
  1328. if (p->LogicalDiskType != FtPartition &&
  1329. p->u.Other.ThisMemberLogicalDiskId == id) {
  1330. id = p->LogicalDiskId;
  1331. }
  1332. } else {
  1333. if (p->LogicalDiskType == FtPartition &&
  1334. p->u.FtPartition.ByteOffset == Offset) {
  1335. id = p->LogicalDiskId;
  1336. }
  1337. }
  1338. }
  1339. return id;
  1340. }
  1341. FT_LOGICAL_DISK_ID
  1342. FT_LOGICAL_DISK_INFORMATION_SET::QueryPartitionLogicalDiskId(
  1343. IN ULONG DiskNumber,
  1344. IN LONGLONG Offset
  1345. )
  1346. /*++
  1347. Routine Description:
  1348. This routine returns the logical disk id for the given partition.
  1349. Arguments:
  1350. DiskNumber - Supplies the disk number of the whole disk
  1351. of the partition.
  1352. Offset - Supplies the offset of the partition.
  1353. Return Value:
  1354. A logical disk id or 0.
  1355. --*/
  1356. {
  1357. ULONG i;
  1358. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1359. PFT_LOGICAL_DISK_DESCRIPTION p;
  1360. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1361. diskInfo = _arrayOfLogicalDiskInformations[i];
  1362. if (diskInfo->QueryDiskNumber() == DiskNumber) {
  1363. break;
  1364. }
  1365. }
  1366. if (i == _numberOfLogicalDiskInformations) {
  1367. return 0;
  1368. }
  1369. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  1370. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  1371. if (p->LogicalDiskType == FtPartition &&
  1372. p->u.FtPartition.ByteOffset == Offset) {
  1373. return p->LogicalDiskId;
  1374. }
  1375. }
  1376. return 0;
  1377. }
  1378. USHORT
  1379. FT_LOGICAL_DISK_INFORMATION_SET::QueryNumberOfMembersInLogicalDisk(
  1380. IN FT_LOGICAL_DISK_ID LogicalDiskId
  1381. )
  1382. /*++
  1383. Routine Description:
  1384. This routine returns the number of members in a logical disk.
  1385. Arguments:
  1386. LogicalDiskId - Supplies the logical disk id.
  1387. Return Value:
  1388. The number of members in a logical disk.
  1389. --*/
  1390. {
  1391. PFT_LOGICAL_DISK_DESCRIPTION p;
  1392. p = GetLogicalDiskDescription(LogicalDiskId, 0);
  1393. if (!p) {
  1394. ASSERT(FALSE);
  1395. return 0;
  1396. }
  1397. if (p->LogicalDiskType == FtPartition) {
  1398. return 0;
  1399. }
  1400. return p->u.Other.NumberOfMembers;
  1401. }
  1402. FT_LOGICAL_DISK_ID
  1403. FT_LOGICAL_DISK_INFORMATION_SET::QueryMemberLogicalDiskId(
  1404. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  1405. IN USHORT MemberNumber
  1406. )
  1407. /*++
  1408. Routine Description:
  1409. This routine returns the logical disk id for the given member number.
  1410. Arguments:
  1411. LogicalDiskId - Supplies the logical disk id.
  1412. MemberNumber - Supplies the requested member number.
  1413. Return Value:
  1414. The logical disk id of the given member number.
  1415. --*/
  1416. {
  1417. ULONG i;
  1418. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1419. PFT_LOGICAL_DISK_DESCRIPTION p;
  1420. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1421. diskInfo = _arrayOfLogicalDiskInformations[i];
  1422. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  1423. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  1424. if (p->LogicalDiskId == LogicalDiskId) {
  1425. ASSERT(p->LogicalDiskType != FtPartition);
  1426. if (p->u.Other.ThisMemberNumber == MemberNumber) {
  1427. return p->u.Other.ThisMemberLogicalDiskId;
  1428. }
  1429. }
  1430. }
  1431. }
  1432. return 0;
  1433. }
  1434. FT_LOGICAL_DISK_TYPE
  1435. FT_LOGICAL_DISK_INFORMATION_SET::QueryLogicalDiskType(
  1436. IN FT_LOGICAL_DISK_ID LogicalDiskId
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. This routine returns the logical disk type for the given logical disk
  1441. id.
  1442. Arguments:
  1443. LogicalDiskId - Supplies the logical disk id.
  1444. Return Value:
  1445. The logical disk type for the given logical disk id.
  1446. --*/
  1447. {
  1448. PFT_LOGICAL_DISK_DESCRIPTION p;
  1449. p = GetLogicalDiskDescription(LogicalDiskId, 0);
  1450. if (!p) {
  1451. ASSERT(FALSE);
  1452. return FtPartition;
  1453. }
  1454. return p->LogicalDiskType;
  1455. }
  1456. BOOLEAN
  1457. FT_LOGICAL_DISK_INFORMATION_SET::QueryFtPartitionInformation(
  1458. IN FT_LOGICAL_DISK_ID PartitionLogicalDiskId,
  1459. OUT PLONGLONG Offset,
  1460. OUT PDEVICE_OBJECT* WholeDisk,
  1461. OUT PULONG DiskNumber,
  1462. OUT PULONG SectorSize,
  1463. OUT PLONGLONG PartitionSize
  1464. )
  1465. /*++
  1466. Routine Description:
  1467. This routine returns information about the given partition.
  1468. Arguments:
  1469. PartitionLogicalDiskId - Supplies the logical disk id.
  1470. Offset - Returns the partition offset.
  1471. WholeDisk - Returns the whole disk device object.
  1472. DiskNumber - Returns the disk number.
  1473. SectorSize - Returns the sector size.
  1474. PartitionSize - Returns the partition size.
  1475. Return Value:
  1476. FALSE - Failure.
  1477. TRUE - Success.
  1478. --*/
  1479. {
  1480. ULONG i, instanceNumber;
  1481. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1482. PFT_LOGICAL_DISK_DESCRIPTION p;
  1483. instanceNumber = 0;
  1484. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1485. diskInfo = _arrayOfLogicalDiskInformations[i];
  1486. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  1487. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  1488. if (p->LogicalDiskId == PartitionLogicalDiskId) {
  1489. if (p->LogicalDiskType != FtPartition) {
  1490. return FALSE;
  1491. }
  1492. if (Offset) {
  1493. *Offset = p->u.FtPartition.ByteOffset;
  1494. }
  1495. if (WholeDisk) {
  1496. *WholeDisk = diskInfo->GetWholeDisk();
  1497. }
  1498. if (DiskNumber) {
  1499. *DiskNumber = diskInfo->QueryDiskNumber();
  1500. }
  1501. if (SectorSize) {
  1502. *SectorSize = diskInfo->QuerySectorSize();
  1503. }
  1504. if (PartitionSize) {
  1505. *PartitionSize = p->u.FtPartition.PartitionSize;
  1506. }
  1507. return TRUE;
  1508. }
  1509. }
  1510. }
  1511. return FALSE;
  1512. }
  1513. PVOID
  1514. FT_LOGICAL_DISK_INFORMATION_SET::GetConfigurationInformation(
  1515. IN FT_LOGICAL_DISK_ID LogicalDiskId
  1516. )
  1517. /*++
  1518. Routine Description:
  1519. This routine returns a pointer to the configuration information
  1520. for the given logical disk.
  1521. Arguments:
  1522. LogicalDiskId - Supplies the logical disk id.
  1523. Return Value:
  1524. A pointer to the configuration information for the given logical disk.
  1525. --*/
  1526. {
  1527. PFT_LOGICAL_DISK_DESCRIPTION p;
  1528. p = GetLogicalDiskDescription(LogicalDiskId, 0);
  1529. if (!p) {
  1530. ASSERT(FALSE);
  1531. return NULL;
  1532. }
  1533. if (p->LogicalDiskType == FtPartition) {
  1534. ASSERT(FALSE);
  1535. return NULL;
  1536. }
  1537. if (!p->u.Other.ByteOffsetToConfigurationInformation) {
  1538. return NULL;
  1539. }
  1540. return ((PCHAR) p + p->u.Other.ByteOffsetToConfigurationInformation);
  1541. }
  1542. PVOID
  1543. FT_LOGICAL_DISK_INFORMATION_SET::GetStateInformation(
  1544. IN FT_LOGICAL_DISK_ID LogicalDiskId
  1545. )
  1546. /*++
  1547. Routine Description:
  1548. This routine returns a pointer to the state information
  1549. for the given logical disk.
  1550. Arguments:
  1551. LogicalDiskId - Supplies the logical disk id.
  1552. Return Value:
  1553. A pointer to the state information for the given logical disk.
  1554. --*/
  1555. {
  1556. PFT_LOGICAL_DISK_DESCRIPTION p;
  1557. p = GetLogicalDiskDescription(LogicalDiskId, 0);
  1558. if (!p) {
  1559. ASSERT(FALSE);
  1560. return NULL;
  1561. }
  1562. if (p->LogicalDiskType == FtPartition ||
  1563. !p->u.Other.ByteOffsetToStateInformation) {
  1564. return NULL;
  1565. }
  1566. return ((PCHAR) p + p->u.Other.ByteOffsetToStateInformation);
  1567. }
  1568. BOOLEAN
  1569. FT_LOGICAL_DISK_INFORMATION_SET::IsLogicalDiskComplete(
  1570. IN FT_LOGICAL_DISK_ID LogicalDiskId
  1571. )
  1572. /*++
  1573. Routine Description:
  1574. This routine computes whether or not a given logical disk is
  1575. complete. In other words, whether or not it has all of its members
  1576. and its members' members etc...
  1577. Arguments:
  1578. LogicalDiskId - Supplies the logical disk id.
  1579. Return Value:
  1580. FALSE - This logical disk is not complete.
  1581. TRUE - This logical disk is complete.
  1582. --*/
  1583. {
  1584. USHORT numMembers, i;
  1585. FT_LOGICAL_DISK_ID memberDiskId;
  1586. numMembers = QueryNumberOfMembersInLogicalDisk(LogicalDiskId);
  1587. for (i = 0; i < numMembers; i++) {
  1588. memberDiskId = QueryMemberLogicalDiskId(LogicalDiskId, i);
  1589. if (!memberDiskId || !IsLogicalDiskComplete(memberDiskId)) {
  1590. return FALSE;
  1591. }
  1592. }
  1593. return TRUE;
  1594. }
  1595. UCHAR
  1596. FT_LOGICAL_DISK_INFORMATION_SET::QueryDriveLetter(
  1597. IN FT_LOGICAL_DISK_ID LogicalDiskId
  1598. )
  1599. /*++
  1600. Routine Description:
  1601. This routine returns the drive letter for the given logical disk.
  1602. Arguments:
  1603. LogicalDiskId - Supplies the logical disk id.
  1604. Return Value:
  1605. The drive letter or 0.
  1606. --*/
  1607. {
  1608. PFT_LOGICAL_DISK_DESCRIPTION p;
  1609. p = GetLogicalDiskDescription(LogicalDiskId, 0);
  1610. if (!p) {
  1611. return 0;
  1612. }
  1613. return p->DriveLetter;
  1614. }
  1615. NTSTATUS
  1616. FT_LOGICAL_DISK_INFORMATION_SET::SetDriveLetter(
  1617. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  1618. IN UCHAR DriveLetter
  1619. )
  1620. /*++
  1621. Routine Description:
  1622. This routine sets the drive letter for the given logical disk.
  1623. Arguments:
  1624. LogicalDiskId - Supplies the logical disk id.
  1625. DriveLetter - Supplies the drive letter.
  1626. Return Value:
  1627. NTSTATUS
  1628. --*/
  1629. {
  1630. ULONG i;
  1631. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1632. PFT_LOGICAL_DISK_DESCRIPTION p;
  1633. BOOLEAN found;
  1634. found = FALSE;
  1635. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1636. diskInfo = _arrayOfLogicalDiskInformations[i];
  1637. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  1638. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  1639. if (p->LogicalDiskId == LogicalDiskId) {
  1640. p->DriveLetter = DriveLetter;
  1641. diskInfo->Write();
  1642. found = TRUE;
  1643. }
  1644. }
  1645. }
  1646. return found ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
  1647. }
  1648. NTSTATUS
  1649. FT_LOGICAL_DISK_INFORMATION_SET::WriteStateInformation(
  1650. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  1651. IN PVOID LogicalDiskState,
  1652. IN USHORT LogicalDiskStateSize
  1653. )
  1654. /*++
  1655. Routine Description:
  1656. This routine writes out the given state information to all on
  1657. disk instances of the given logical disk. If one of the instances
  1658. fails to commit to disk, this routine will continue to write out
  1659. all that it can and then return the error that it received.
  1660. Arguments:
  1661. LogicalDiskId - Supplies the logical disk id.
  1662. LogicalDiskState - Supplies the logical disk state to write.
  1663. LogicalDiskStateSize - Supplies the number of bytes in the given
  1664. logical disk state.
  1665. Return Value:
  1666. NTSTATUS
  1667. --*/
  1668. {
  1669. ULONG i;
  1670. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1671. PFT_LOGICAL_DISK_DESCRIPTION p;
  1672. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1673. diskInfo = _arrayOfLogicalDiskInformations[i];
  1674. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  1675. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  1676. if (p->LogicalDiskId == LogicalDiskId) {
  1677. ASSERT(p->LogicalDiskType != FtPartition);
  1678. ASSERT(p->u.Other.ByteOffsetToStateInformation);
  1679. RtlMoveMemory((PCHAR) p +
  1680. p->u.Other.ByteOffsetToStateInformation,
  1681. LogicalDiskState,
  1682. LogicalDiskStateSize);
  1683. diskInfo->Write();
  1684. }
  1685. }
  1686. }
  1687. FtpCopyStateToRegistry(LogicalDiskId, LogicalDiskState,
  1688. LogicalDiskStateSize);
  1689. return STATUS_SUCCESS;
  1690. }
  1691. FT_LOGICAL_DISK_ID
  1692. GenerateNewLogicalDiskId(
  1693. )
  1694. /*++
  1695. Routine Description:
  1696. This routine computes a new, random, unique, logical disk id for
  1697. use to identify a new logical disk.
  1698. Arguments:
  1699. None.
  1700. Return Value:
  1701. A new logical disk id.
  1702. --*/
  1703. {
  1704. NTSTATUS status;
  1705. UUID uuid;
  1706. PUCHAR p;
  1707. FT_LOGICAL_DISK_ID diskId;
  1708. static LARGE_INTEGER lastSystemTime;
  1709. LARGE_INTEGER x;
  1710. ULONG i;
  1711. status = ExUuidCreate(&uuid);
  1712. if (NT_SUCCESS(status)) {
  1713. p = (PUCHAR) &uuid;
  1714. diskId = (*((PFT_LOGICAL_DISK_ID) p)) ^
  1715. (*((PFT_LOGICAL_DISK_ID) (p + sizeof(FT_LOGICAL_DISK_ID))));
  1716. return diskId;
  1717. }
  1718. x.QuadPart = 0;
  1719. while (x.QuadPart == 0) {
  1720. for (;;) {
  1721. KeQuerySystemTime(&x);
  1722. if (x.QuadPart != lastSystemTime.QuadPart) {
  1723. break;
  1724. }
  1725. }
  1726. lastSystemTime.QuadPart = x.QuadPart;
  1727. p = (PUCHAR) &x.QuadPart;
  1728. for (i = 0; i < sizeof(LONGLONG); i++) {
  1729. x.QuadPart += *p++;
  1730. x.QuadPart = (x.QuadPart >> 2) + (x.QuadPart << 62);
  1731. }
  1732. }
  1733. return x.QuadPart;
  1734. }
  1735. NTSTATUS
  1736. FT_LOGICAL_DISK_INFORMATION_SET::CreatePartitionLogicalDisk(
  1737. IN ULONG DiskNumber,
  1738. IN LONGLONG PartitionOffset,
  1739. IN LONGLONG PartitionSize,
  1740. OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
  1741. )
  1742. /*++
  1743. Routine Description:
  1744. This routine takes a DOS partition and assigns it a logical disk id.
  1745. Arguments:
  1746. DiskNumber - Supplies the disk number where the partition
  1747. resides.
  1748. PartitionOffset - Supplies the partition offset.
  1749. PartitionSize - Supplies the partition size.
  1750. NewLogicalDiskId - Returns the logical disk id.
  1751. Return Value:
  1752. NTSTATUS
  1753. --*/
  1754. {
  1755. ULONG i;
  1756. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1757. PFT_LOGICAL_DISK_DESCRIPTION newLogicalDiskDescription, p;
  1758. NTSTATUS status;
  1759. // Find the disk information for the given device object.
  1760. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1761. diskInfo = _arrayOfLogicalDiskInformations[i];
  1762. if (diskInfo->QueryDiskNumber() == DiskNumber) {
  1763. break;
  1764. }
  1765. }
  1766. if (i == _numberOfLogicalDiskInformations) {
  1767. return STATUS_INVALID_PARAMETER;
  1768. }
  1769. // Generate a new logical disk id for this one.
  1770. *NewLogicalDiskId = GenerateNewLogicalDiskId();
  1771. // Allocate and set up a new logical disk description.
  1772. newLogicalDiskDescription = (PFT_LOGICAL_DISK_DESCRIPTION)
  1773. ExAllocatePool(PagedPool, sizeof(FT_LOGICAL_DISK_DESCRIPTION));
  1774. if (!newLogicalDiskDescription) {
  1775. return STATUS_INSUFFICIENT_RESOURCES;
  1776. }
  1777. newLogicalDiskDescription->DiskDescriptionSize =
  1778. sizeof(FT_LOGICAL_DISK_DESCRIPTION);
  1779. newLogicalDiskDescription->DriveLetter = 0;
  1780. newLogicalDiskDescription->Reserved = 0;
  1781. newLogicalDiskDescription->LogicalDiskType = FtPartition;
  1782. newLogicalDiskDescription->LogicalDiskId = *NewLogicalDiskId;
  1783. newLogicalDiskDescription->u.FtPartition.ByteOffset = PartitionOffset;
  1784. newLogicalDiskDescription->u.FtPartition.PartitionSize = PartitionSize;
  1785. // Check for enough free disk space.
  1786. if (newLogicalDiskDescription->DiskDescriptionSize >
  1787. diskInfo->QueryDiskDescriptionFreeSpace()) {
  1788. FtpLogError(diskInfo->GetRootExtension(),
  1789. diskInfo->QueryDiskNumber(),
  1790. FT_NOT_ENOUGH_ON_DISK_SPACE, STATUS_DISK_FULL, 0);
  1791. ExFreePool(newLogicalDiskDescription);
  1792. return STATUS_DISK_FULL;
  1793. }
  1794. // Now allocate the memory that we need to store this new logical
  1795. // disk.
  1796. if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + 1)) {
  1797. ExFreePool(newLogicalDiskDescription);
  1798. return STATUS_INSUFFICIENT_RESOURCES;
  1799. }
  1800. // Write out the disk description.
  1801. p = diskInfo->AddLogicalDiskDescription(newLogicalDiskDescription);
  1802. ASSERT(p);
  1803. ExFreePool(newLogicalDiskDescription);
  1804. status = diskInfo->Write();
  1805. if (!NT_SUCCESS(status)) {
  1806. BreakLogicalDisk(*NewLogicalDiskId);
  1807. return status;
  1808. }
  1809. // Fix up the list of root entries.
  1810. RecomputeArrayOfRootLogicalDiskIds();
  1811. return status;
  1812. }
  1813. NTSTATUS
  1814. FT_LOGICAL_DISK_INFORMATION_SET::AddNewLogicalDisk(
  1815. IN FT_LOGICAL_DISK_TYPE NewLogicalDiskType,
  1816. IN USHORT NumberOfMembers,
  1817. IN PFT_LOGICAL_DISK_ID ArrayOfMembers,
  1818. IN USHORT ConfigurationInformationSize,
  1819. IN PVOID ConfigurationInformation,
  1820. IN USHORT StateInformationSize,
  1821. IN PVOID StateInformation,
  1822. OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
  1823. )
  1824. /*++
  1825. Routine Description:
  1826. This routine adds the given logical disk to the system.
  1827. Arguments:
  1828. NewLogicalDiskType - Supplies the logical disk type of the
  1829. new logical disk.
  1830. NumberOfMembers - Supplies the number of members contained
  1831. in the new logical disk.
  1832. ArrayOfMembers - Supplies the array of members.
  1833. ConfigurationInformationSize - Supplies the configuration information
  1834. size.
  1835. ConfigurationInformation - Supplies the configuration information.
  1836. StateInformationSize - Supplies the state information size.
  1837. StateInformation - Supplies the state information.
  1838. NewLogicalDiskId - Returns the new logical disk id.
  1839. Return Value:
  1840. NTSTATUS
  1841. --*/
  1842. {
  1843. ULONG i, j;
  1844. USHORT size;
  1845. UCHAR driveLetter;
  1846. PFT_LOGICAL_DISK_DESCRIPTION newLogicalDiskDescription;
  1847. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  1848. PFT_LOGICAL_DISK_DESCRIPTION p, q;
  1849. NTSTATUS status;
  1850. ULONG numInstancesInThisInfo;
  1851. WCHAR name[3];
  1852. if (NewLogicalDiskType == FtPartition) {
  1853. return STATUS_INVALID_PARAMETER;
  1854. }
  1855. // First make sure that the members are all root logical disks and
  1856. // are complete.
  1857. for (i = 0; i < NumberOfMembers; i++) {
  1858. if (!ArrayOfMembers[i]) {
  1859. continue;
  1860. }
  1861. for (j = 0; j < _numberOfRootLogicalDisksIds; j++) {
  1862. if (ArrayOfMembers[i] == _arrayOfRootLogicalDiskIds[j]) {
  1863. break;
  1864. }
  1865. }
  1866. if (j == _numberOfRootLogicalDisksIds) {
  1867. return STATUS_INVALID_PARAMETER;
  1868. }
  1869. if (!IsLogicalDiskComplete(ArrayOfMembers[i])) {
  1870. return STATUS_INVALID_PARAMETER;
  1871. }
  1872. }
  1873. // In the mirror, volume set, and redist cases. Save the
  1874. // drive letter of the first member.
  1875. if (NewLogicalDiskType == FtVolumeSet ||
  1876. NewLogicalDiskType == FtMirrorSet ||
  1877. NewLogicalDiskType == FtRedistribution) {
  1878. driveLetter = QueryDriveLetter(ArrayOfMembers[0]);
  1879. } else {
  1880. driveLetter = 0;
  1881. }
  1882. for (i = 0; i < NumberOfMembers; i++) {
  1883. SetDriveLetter(ArrayOfMembers[i], 0);
  1884. }
  1885. *NewLogicalDiskId = GenerateNewLogicalDiskId();
  1886. // Construct the disk description record.
  1887. size = sizeof(FT_LOGICAL_DISK_DESCRIPTION) +
  1888. ConfigurationInformationSize + StateInformationSize;
  1889. size = (size + FILE_QUAD_ALIGNMENT)&(~FILE_QUAD_ALIGNMENT);
  1890. newLogicalDiskDescription = (PFT_LOGICAL_DISK_DESCRIPTION)
  1891. ExAllocatePool(PagedPool, size);
  1892. if (!newLogicalDiskDescription) {
  1893. return STATUS_INSUFFICIENT_RESOURCES;
  1894. }
  1895. newLogicalDiskDescription->DiskDescriptionSize = size;
  1896. newLogicalDiskDescription->DriveLetter = driveLetter;
  1897. newLogicalDiskDescription->Reserved = 0;
  1898. newLogicalDiskDescription->LogicalDiskType = NewLogicalDiskType;
  1899. newLogicalDiskDescription->LogicalDiskId = *NewLogicalDiskId;
  1900. newLogicalDiskDescription->u.Other.ThisMemberLogicalDiskId = 0;
  1901. newLogicalDiskDescription->u.Other.ThisMemberNumber = 0;
  1902. newLogicalDiskDescription->u.Other.NumberOfMembers = NumberOfMembers;
  1903. if (ConfigurationInformationSize) {
  1904. newLogicalDiskDescription->u.Other.
  1905. ByteOffsetToConfigurationInformation =
  1906. sizeof(FT_LOGICAL_DISK_DESCRIPTION);
  1907. RtlMoveMemory((PCHAR) newLogicalDiskDescription +
  1908. newLogicalDiskDescription->u.Other.
  1909. ByteOffsetToConfigurationInformation,
  1910. ConfigurationInformation,
  1911. ConfigurationInformationSize);
  1912. } else {
  1913. newLogicalDiskDescription->u.Other.
  1914. ByteOffsetToConfigurationInformation = 0;
  1915. }
  1916. if (StateInformationSize) {
  1917. newLogicalDiskDescription->u.Other.ByteOffsetToStateInformation =
  1918. sizeof(FT_LOGICAL_DISK_DESCRIPTION) +
  1919. ConfigurationInformationSize;
  1920. RtlMoveMemory((PCHAR) newLogicalDiskDescription +
  1921. newLogicalDiskDescription->u.Other.
  1922. ByteOffsetToStateInformation,
  1923. StateInformation,
  1924. StateInformationSize);
  1925. } else {
  1926. newLogicalDiskDescription->u.Other.ByteOffsetToStateInformation = 0;
  1927. }
  1928. // Figure out how many instances we're going to need and check to make
  1929. // sure that there is enough disk space for all of the instances.
  1930. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1931. diskInfo = _arrayOfLogicalDiskInformations[i];
  1932. numInstancesInThisInfo = 0;
  1933. for (j = 0; j < NumberOfMembers; j++) {
  1934. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  1935. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  1936. if (p->LogicalDiskId == ArrayOfMembers[j]) {
  1937. break;
  1938. }
  1939. }
  1940. if (p) {
  1941. numInstancesInThisInfo++;
  1942. }
  1943. }
  1944. if (numInstancesInThisInfo) {
  1945. if (numInstancesInThisInfo*
  1946. newLogicalDiskDescription->DiskDescriptionSize >
  1947. diskInfo->QueryDiskDescriptionFreeSpace()) {
  1948. FtpLogError(diskInfo->GetRootExtension(),
  1949. diskInfo->QueryDiskNumber(),
  1950. FT_NOT_ENOUGH_ON_DISK_SPACE, STATUS_DISK_FULL, 0);
  1951. ExFreePool(newLogicalDiskDescription);
  1952. return STATUS_DISK_FULL;
  1953. }
  1954. }
  1955. }
  1956. // Now allocate the memory that we need to store this new logical
  1957. // disk.
  1958. if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + 1)) {
  1959. ExFreePool(newLogicalDiskDescription);
  1960. return STATUS_INSUFFICIENT_RESOURCES;
  1961. }
  1962. // Now that we have the memory and disk space we can proceed with
  1963. // the changes. First fix up the logical disk entries and write out
  1964. // the structures to disk.
  1965. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  1966. diskInfo = _arrayOfLogicalDiskInformations[i];
  1967. for (j = 0; j < NumberOfMembers; j++) {
  1968. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  1969. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  1970. if (p->LogicalDiskId == ArrayOfMembers[j]) {
  1971. break;
  1972. }
  1973. }
  1974. if (p) {
  1975. newLogicalDiskDescription->u.Other.
  1976. ThisMemberLogicalDiskId = ArrayOfMembers[j];
  1977. newLogicalDiskDescription->u.Other.ThisMemberNumber =
  1978. (USHORT) j;
  1979. q = diskInfo->AddLogicalDiskDescription(
  1980. newLogicalDiskDescription);
  1981. ASSERT(q);
  1982. status = diskInfo->Write();
  1983. if (!NT_SUCCESS(status)) {
  1984. BreakLogicalDisk(*NewLogicalDiskId);
  1985. ExFreePool(newLogicalDiskDescription);
  1986. return status;
  1987. }
  1988. }
  1989. }
  1990. }
  1991. ExFreePool(newLogicalDiskDescription);
  1992. // Fix up the list of root entries.
  1993. RecomputeArrayOfRootLogicalDiskIds();
  1994. return STATUS_SUCCESS;
  1995. }
  1996. NTSTATUS
  1997. FT_LOGICAL_DISK_INFORMATION_SET::BreakLogicalDisk(
  1998. IN FT_LOGICAL_DISK_ID LogicalDiskId
  1999. )
  2000. /*++
  2001. Routine Description:
  2002. This routine breaks the given logical disk into its members.
  2003. Arguments:
  2004. LogicalDiskId - Supplies the root logical disk id to break.
  2005. Return Value:
  2006. NTSTATUS
  2007. --*/
  2008. {
  2009. ULONG i, j, numMembers;
  2010. PFT_LOGICAL_DISK_DESCRIPTION p;
  2011. FT_LOGICAL_DISK_TYPE diskType;
  2012. UCHAR driveLetter;
  2013. PFT_MIRROR_AND_SWP_STATE_INFORMATION state;
  2014. FT_LOGICAL_DISK_ID mainMember;
  2015. NTSTATUS status;
  2016. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  2017. // First make sure that the given logical disk id is a root.
  2018. for (i = 0; i < _numberOfRootLogicalDisksIds; i++) {
  2019. if (LogicalDiskId == _arrayOfRootLogicalDiskIds[i]) {
  2020. break;
  2021. }
  2022. }
  2023. if (i == _numberOfRootLogicalDisksIds) {
  2024. return STATUS_INVALID_PARAMETER;
  2025. }
  2026. // Allocate the memory needed to grow the list of roots.
  2027. p = GetLogicalDiskDescription(LogicalDiskId, 0);
  2028. ASSERT(p);
  2029. diskType = p->LogicalDiskType;
  2030. driveLetter = p->DriveLetter;
  2031. if (diskType == FtPartition) {
  2032. numMembers = 0;
  2033. } else {
  2034. numMembers = p->u.Other.NumberOfMembers;
  2035. }
  2036. if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + numMembers)) {
  2037. return STATUS_INSUFFICIENT_RESOURCES;
  2038. }
  2039. DeleteFtRegistryInfo(LogicalDiskId);
  2040. if (diskType == FtMirrorSet) {
  2041. state = (PFT_MIRROR_AND_SWP_STATE_INFORMATION)
  2042. GetStateInformation(LogicalDiskId);
  2043. ASSERT(state);
  2044. if (state->UnhealthyMemberState == FtMemberHealthy ||
  2045. state->UnhealthyMemberNumber == 1) {
  2046. mainMember = QueryMemberLogicalDiskId(LogicalDiskId, 0);
  2047. } else {
  2048. mainMember = QueryMemberLogicalDiskId(LogicalDiskId, 1);
  2049. }
  2050. SetDriveLetter(mainMember, driveLetter);
  2051. }
  2052. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  2053. diskInfo = _arrayOfLogicalDiskInformations[i];
  2054. p = diskInfo->GetFirstLogicalDiskDescription();
  2055. while (p) {
  2056. if (p->LogicalDiskId == LogicalDiskId) {
  2057. diskInfo->DeleteLogicalDiskDescription(p);
  2058. if (!p->DiskDescriptionSize) {
  2059. p = NULL;
  2060. }
  2061. diskInfo->Write();
  2062. } else {
  2063. p = diskInfo->GetNextLogicalDiskDescription(p);
  2064. }
  2065. }
  2066. }
  2067. FtpDeleteStateInRegistry(LogicalDiskId);
  2068. // Recompute the list of roots.
  2069. RecomputeArrayOfRootLogicalDiskIds();
  2070. return STATUS_SUCCESS;
  2071. }
  2072. NTSTATUS
  2073. FT_LOGICAL_DISK_INFORMATION_SET::ReplaceLogicalDiskMember(
  2074. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  2075. IN USHORT MemberNumberToReplace,
  2076. IN FT_LOGICAL_DISK_ID NewMemberLogicalDiskId,
  2077. OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
  2078. )
  2079. /*++
  2080. Routine Description:
  2081. This routine replaces the given member with the new given member.
  2082. Arguments:
  2083. LogicalDiskId - Supplies the logical disk whose member we are
  2084. going to replace.
  2085. MemberNumberToReplace - Supplies the member number to replace.
  2086. NewMemberLogicalDiskId - Supplies the new member.
  2087. NewLogicalDiskId - Returns the new logical disk id for the set
  2088. containing the new member.
  2089. Return Value:
  2090. NTSTATUS
  2091. --*/
  2092. {
  2093. ULONG i, j, numInstances, n;
  2094. PFT_LOGICAL_DISK_ID oldLogicalDiskIds;
  2095. PFT_LOGICAL_DISK_ID newLogicalDiskIds;
  2096. PFT_LOGICAL_DISK_DESCRIPTION p, q, newDiskDescription;
  2097. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  2098. NTSTATUS status;
  2099. BOOLEAN wroteLog;
  2100. FT_LOGICAL_DISK_ID replacedMemberDiskId, child;
  2101. UCHAR state[100];
  2102. USHORT stateSize;
  2103. // Make sure that the replacement is a root and is complete.
  2104. for (i = 0; i < _numberOfRootLogicalDisksIds; i++) {
  2105. if (NewMemberLogicalDiskId == _arrayOfRootLogicalDiskIds[i]) {
  2106. break;
  2107. }
  2108. }
  2109. if (i == _numberOfRootLogicalDisksIds ||
  2110. !IsLogicalDiskComplete(NewMemberLogicalDiskId)) {
  2111. return STATUS_INVALID_PARAMETER;
  2112. }
  2113. if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + 1)) {
  2114. return STATUS_INSUFFICIENT_RESOURCES;
  2115. }
  2116. DeleteFtRegistryInfo(LogicalDiskId);
  2117. // Figure out 'n' where n is how many new logical disk ids we need.
  2118. if (!ComputeNewParentLogicalDiskIds(LogicalDiskId, &n,
  2119. &oldLogicalDiskIds,
  2120. &newLogicalDiskIds)) {
  2121. return STATUS_INSUFFICIENT_RESOURCES;
  2122. }
  2123. // Copy back the new logical disk id.
  2124. *NewLogicalDiskId = newLogicalDiskIds[0];
  2125. // Figure out the logical disk id of the member to replace.
  2126. replacedMemberDiskId = QueryMemberLogicalDiskId(LogicalDiskId,
  2127. MemberNumberToReplace);
  2128. // Build up the new member into a new tree that will eventually
  2129. // replace the old tree of which this logical disk is a member.
  2130. for (i = 0; i < n; i++) {
  2131. if (i == 0) {
  2132. p = GetLogicalDiskDescription(oldLogicalDiskIds[i], 0);
  2133. } else {
  2134. p = GetParentLogicalDiskDescription(oldLogicalDiskIds[i - 1]);
  2135. }
  2136. if (!p || p->LogicalDiskType == FtPartition) {
  2137. ExFreePool(oldLogicalDiskIds);
  2138. ExFreePool(newLogicalDiskIds);
  2139. return STATUS_INVALID_PARAMETER;
  2140. }
  2141. newDiskDescription = (PFT_LOGICAL_DISK_DESCRIPTION)
  2142. ExAllocatePool(PagedPool, p->DiskDescriptionSize);
  2143. if (!newDiskDescription) {
  2144. ExFreePool(oldLogicalDiskIds);
  2145. ExFreePool(newLogicalDiskIds);
  2146. return STATUS_INSUFFICIENT_RESOURCES;
  2147. }
  2148. RtlMoveMemory(newDiskDescription, p, p->DiskDescriptionSize);
  2149. newDiskDescription->LogicalDiskId = newLogicalDiskIds[i];
  2150. if (i == 0) {
  2151. newDiskDescription->u.Other.ThisMemberLogicalDiskId =
  2152. NewMemberLogicalDiskId;
  2153. newDiskDescription->u.Other.ThisMemberNumber =
  2154. MemberNumberToReplace;
  2155. } else {
  2156. newDiskDescription->u.Other.ThisMemberLogicalDiskId =
  2157. newLogicalDiskIds[i - 1];
  2158. }
  2159. for (j = 0; j < _numberOfLogicalDiskInformations; j++) {
  2160. diskInfo = _arrayOfLogicalDiskInformations[j];
  2161. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  2162. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  2163. if (p->LogicalDiskId !=
  2164. newDiskDescription->u.Other.ThisMemberLogicalDiskId) {
  2165. continue;
  2166. }
  2167. if (!diskInfo->AddLogicalDiskDescription(newDiskDescription)) {
  2168. FtpLogError(diskInfo->GetRootExtension(),
  2169. diskInfo->QueryDiskNumber(),
  2170. FT_NOT_ENOUGH_ON_DISK_SPACE, STATUS_DISK_FULL,
  2171. 0);
  2172. ExFreePool(newDiskDescription);
  2173. ExFreePool(oldLogicalDiskIds);
  2174. ExFreePool(newLogicalDiskIds);
  2175. return STATUS_DISK_FULL;
  2176. }
  2177. status = diskInfo->Write();
  2178. if (!NT_SUCCESS(status)) {
  2179. ExFreePool(newDiskDescription);
  2180. ExFreePool(oldLogicalDiskIds);
  2181. ExFreePool(newLogicalDiskIds);
  2182. return status;
  2183. }
  2184. break;
  2185. }
  2186. }
  2187. ExFreePool(newDiskDescription);
  2188. }
  2189. // Substitute new logical disk ids for old ones, logging the operation
  2190. // for a safe backout in the event of a crash.
  2191. status = STATUS_SUCCESS;
  2192. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  2193. diskInfo = _arrayOfLogicalDiskInformations[i];
  2194. wroteLog = FALSE;
  2195. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  2196. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  2197. if (p->LogicalDiskType != FtPartition) {
  2198. continue;
  2199. }
  2200. child = p->LogicalDiskId;
  2201. for (q = diskInfo->GetNextLogicalDiskDescription(p); q;
  2202. q = diskInfo->GetNextLogicalDiskDescription(q)) {
  2203. if (q->LogicalDiskType == FtPartition ||
  2204. q->u.Other.ThisMemberLogicalDiskId != child) {
  2205. continue;
  2206. }
  2207. if (q->LogicalDiskId == LogicalDiskId &&
  2208. q->u.Other.ThisMemberNumber == MemberNumberToReplace) {
  2209. break;
  2210. }
  2211. child = q->LogicalDiskId;
  2212. }
  2213. if (q) {
  2214. continue;
  2215. }
  2216. child = p->LogicalDiskId;
  2217. for (q = diskInfo->GetNextLogicalDiskDescription(p); q;
  2218. q = diskInfo->GetNextLogicalDiskDescription(q)) {
  2219. if (q->LogicalDiskType == FtPartition ||
  2220. q->u.Other.ThisMemberLogicalDiskId != child) {
  2221. continue;
  2222. }
  2223. child = q->LogicalDiskId;
  2224. for (j = 0; j < n; j++) {
  2225. if (q->LogicalDiskId == oldLogicalDiskIds[j]) {
  2226. if (!wroteLog) {
  2227. diskInfo->AddReplaceLog(replacedMemberDiskId,
  2228. NewMemberLogicalDiskId,
  2229. n, oldLogicalDiskIds,
  2230. newLogicalDiskIds);
  2231. wroteLog = TRUE;
  2232. }
  2233. q->LogicalDiskId = newLogicalDiskIds[j];
  2234. } else if (q->u.Other.ThisMemberLogicalDiskId ==
  2235. oldLogicalDiskIds[j]) {
  2236. if (!wroteLog) {
  2237. diskInfo->AddReplaceLog(replacedMemberDiskId,
  2238. NewMemberLogicalDiskId,
  2239. n, oldLogicalDiskIds,
  2240. newLogicalDiskIds);
  2241. wroteLog = TRUE;
  2242. }
  2243. q->u.Other.ThisMemberLogicalDiskId =
  2244. newLogicalDiskIds[j];
  2245. }
  2246. }
  2247. }
  2248. }
  2249. if (wroteLog) {
  2250. status = diskInfo->Write();
  2251. if (!NT_SUCCESS(status)) {
  2252. break;
  2253. }
  2254. }
  2255. }
  2256. if (NT_SUCCESS(status)) {
  2257. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  2258. diskInfo = _arrayOfLogicalDiskInformations[i];
  2259. if (diskInfo->ClearReplaceLog()) {
  2260. diskInfo->Write();
  2261. }
  2262. }
  2263. // Erase all logical disk descriptions that contain the old
  2264. // logical disk ids.
  2265. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  2266. diskInfo = _arrayOfLogicalDiskInformations[i];
  2267. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  2268. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  2269. for (j = 0; j < n; j++) {
  2270. if (p->LogicalDiskId == oldLogicalDiskIds[j]) {
  2271. diskInfo->DeleteLogicalDiskDescription(p);
  2272. diskInfo->Write();
  2273. }
  2274. }
  2275. }
  2276. }
  2277. for (i = 0; i < n; i++) {
  2278. if (FtpQueryStateFromRegistry(oldLogicalDiskIds[i], state, 100,
  2279. &stateSize)) {
  2280. FtpDeleteStateInRegistry(oldLogicalDiskIds[i]);
  2281. FtpCopyStateToRegistry(newLogicalDiskIds[i], state, stateSize);
  2282. }
  2283. }
  2284. } else {
  2285. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  2286. diskInfo = _arrayOfLogicalDiskInformations[i];
  2287. if (diskInfo->BackOutReplaceOperation()) {
  2288. diskInfo->Write();
  2289. }
  2290. }
  2291. RecomputeArrayOfRootLogicalDiskIds();
  2292. for (i = n; i > 0; i--) {
  2293. BreakLogicalDisk(newLogicalDiskIds[i - 1]);
  2294. }
  2295. }
  2296. ExFreePool(oldLogicalDiskIds);
  2297. ExFreePool(newLogicalDiskIds);
  2298. // Recompute list of root entries.
  2299. RecomputeArrayOfRootLogicalDiskIds();
  2300. return status;
  2301. }
  2302. FT_LOGICAL_DISK_TYPE
  2303. TranslateFtDiskType(
  2304. IN FT_TYPE FtType
  2305. )
  2306. {
  2307. switch (FtType) {
  2308. case Mirror:
  2309. return FtMirrorSet;
  2310. case Stripe:
  2311. return FtStripeSet;
  2312. case StripeWithParity:
  2313. return FtStripeSetWithParity;
  2314. case VolumeSet:
  2315. return FtVolumeSet;
  2316. }
  2317. return FtPartition;
  2318. }
  2319. PFT_DESCRIPTION
  2320. GetFtDescription(
  2321. IN PDISK_CONFIG_HEADER Registry,
  2322. IN PDISK_PARTITION DiskPartition
  2323. )
  2324. {
  2325. ULONG diskPartitionOffset;
  2326. PFT_REGISTRY ftRegistry;
  2327. PFT_DESCRIPTION ftDescription;
  2328. USHORT i, j;
  2329. PFT_MEMBER_DESCRIPTION ftMember;
  2330. diskPartitionOffset = (ULONG) ((PUCHAR) DiskPartition - (PUCHAR) Registry);
  2331. ftRegistry = (PFT_REGISTRY) ((PUCHAR) Registry +
  2332. Registry->FtInformationOffset);
  2333. ftDescription = &ftRegistry->FtDescription[0];
  2334. for (i = 0; i < ftRegistry->NumberOfComponents; i++) {
  2335. for (j = 0; j < ftDescription->NumberOfMembers; j++) {
  2336. ftMember = &ftDescription->FtMemberDescription[j];
  2337. if (ftMember->OffsetToPartitionInfo == diskPartitionOffset) {
  2338. return ftDescription;
  2339. }
  2340. }
  2341. ftDescription = (PFT_DESCRIPTION) &ftDescription->FtMemberDescription[
  2342. ftDescription->NumberOfMembers];
  2343. }
  2344. return NULL;
  2345. }
  2346. USHORT
  2347. GetRegistryNumberOfMembers(
  2348. IN PDISK_CONFIG_HEADER Registry,
  2349. IN PDISK_PARTITION DiskPartition
  2350. )
  2351. {
  2352. PFT_DESCRIPTION ftDescription;
  2353. ftDescription = GetFtDescription(Registry, DiskPartition);
  2354. if (!ftDescription) {
  2355. return 0;
  2356. }
  2357. return ftDescription->NumberOfMembers;
  2358. }
  2359. ULONG
  2360. FT_LOGICAL_DISK_INFORMATION_SET::DiskNumberFromSignature(
  2361. IN ULONG Signature
  2362. )
  2363. {
  2364. ULONG i;
  2365. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  2366. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  2367. diskInfo = _arrayOfLogicalDiskInformations[i];
  2368. if (Signature == FtpQueryDiskSignature(diskInfo->GetWholeDiskPdo())) {
  2369. return diskInfo->QueryDiskNumber();
  2370. }
  2371. }
  2372. return 0xFFFFFFFF;
  2373. }
  2374. VOID
  2375. DeleteFtRegistryInformation(
  2376. IN PDISK_CONFIG_HEADER Registry,
  2377. IN PDISK_PARTITION DiskPartition
  2378. )
  2379. {
  2380. PFT_DESCRIPTION ftDescription, next;
  2381. USHORT i;
  2382. PFT_MEMBER_DESCRIPTION ftMember;
  2383. PDISK_PARTITION diskPartition;
  2384. PFT_REGISTRY ftRegistry;
  2385. ftDescription = GetFtDescription(Registry, DiskPartition);
  2386. if (!ftDescription) {
  2387. return;
  2388. }
  2389. for (i = 0; i < ftDescription->NumberOfMembers; i++) {
  2390. ftMember = &ftDescription->FtMemberDescription[i];
  2391. diskPartition = (PDISK_PARTITION) ((PUCHAR) Registry +
  2392. ftMember->OffsetToPartitionInfo);
  2393. diskPartition->FtType = NotAnFtMember;
  2394. diskPartition->FtState = Healthy;
  2395. RtlZeroMemory(&diskPartition->FtLength.QuadPart, sizeof(LONGLONG));
  2396. diskPartition->FtGroup = (USHORT) -1;
  2397. diskPartition->FtMember = 0;
  2398. diskPartition->DriveLetter = 0;
  2399. }
  2400. next = (PFT_DESCRIPTION) &ftDescription->FtMemberDescription[
  2401. ftDescription->NumberOfMembers];
  2402. ftRegistry = (PFT_REGISTRY) ((PUCHAR) Registry +
  2403. Registry->FtInformationOffset);
  2404. RtlMoveMemory(ftDescription, next,
  2405. (PCHAR) ftRegistry + Registry->FtInformationSize -
  2406. (PCHAR) next);
  2407. ftRegistry->NumberOfComponents--;
  2408. }
  2409. VOID
  2410. FT_LOGICAL_DISK_INFORMATION_SET::DeleteFtRegistryInfo(
  2411. IN FT_LOGICAL_DISK_ID LogicalDiskId
  2412. )
  2413. {
  2414. USHORT n, i, j;
  2415. FT_LOGICAL_DISK_ID diskId;
  2416. LONGLONG offset;
  2417. PDEVICE_OBJECT wholeDisk;
  2418. ULONG diskNumber, signature;
  2419. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  2420. ULONG registrySize;
  2421. NTSTATUS status;
  2422. PDISK_CONFIG_HEADER registry;
  2423. PFT_REGISTRY ftRegistry;
  2424. PFT_DESCRIPTION ftDescription;
  2425. PFT_MEMBER_DESCRIPTION ftMember;
  2426. PDISK_PARTITION diskPartition;
  2427. LONGLONG tmp;
  2428. n = QueryNumberOfMembersInLogicalDisk(LogicalDiskId);
  2429. if (!n) {
  2430. return;
  2431. }
  2432. for (i = 0; i < n; i++) {
  2433. diskId = QueryMemberLogicalDiskId(LogicalDiskId, i);
  2434. if (diskId) {
  2435. break;
  2436. }
  2437. }
  2438. if (!diskId) {
  2439. return;
  2440. }
  2441. if (!QueryFtPartitionInformation(diskId, &offset, &wholeDisk, NULL, NULL,
  2442. NULL)) {
  2443. return;
  2444. }
  2445. signature = FtpQueryDiskSignature(wholeDisk);
  2446. if (!signature) {
  2447. return;
  2448. }
  2449. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  2450. queryTable[0].QueryRoutine = FtpDiskRegistryQueryRoutine;
  2451. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  2452. queryTable[0].Name = L"Information";
  2453. queryTable[0].EntryContext = &registrySize;
  2454. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, DISK_REGISTRY_KEY_W,
  2455. queryTable, &registry, NULL);
  2456. if (!NT_SUCCESS(status)) {
  2457. return;
  2458. }
  2459. if (!registry->FtInformationSize) {
  2460. ExFreePool(registry);
  2461. return;
  2462. }
  2463. ftRegistry = (PFT_REGISTRY) ((PUCHAR) registry +
  2464. registry->FtInformationOffset);
  2465. ftDescription = &ftRegistry->FtDescription[0];
  2466. for (i = 0; i < ftRegistry->NumberOfComponents; i++) {
  2467. for (j = 0; j < ftDescription->NumberOfMembers; j++) {
  2468. ftMember = &ftDescription->FtMemberDescription[j];
  2469. diskPartition = (PDISK_PARTITION) ((PUCHAR) registry +
  2470. ftMember->OffsetToPartitionInfo);
  2471. tmp = *((LONGLONG UNALIGNED*)
  2472. &diskPartition->StartingOffset.QuadPart);
  2473. if (ftMember->Signature == signature && tmp == offset) {
  2474. DeleteFtRegistryInformation(registry, diskPartition);
  2475. goto Finish;
  2476. }
  2477. }
  2478. ftDescription = (PFT_DESCRIPTION) &ftDescription->FtMemberDescription[
  2479. ftDescription->NumberOfMembers];
  2480. }
  2481. Finish:
  2482. RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, DISK_REGISTRY_KEY_W,
  2483. L"Information", REG_BINARY, registry,
  2484. registrySize);
  2485. ExFreePool(registry);
  2486. }
  2487. PFT_LOGICAL_DISK_INFORMATION
  2488. FT_LOGICAL_DISK_INFORMATION_SET::FindLogicalDiskInformation(
  2489. IN PDEVICE_OBJECT WholeDiskPdo
  2490. )
  2491. {
  2492. ULONG i;
  2493. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  2494. if (_arrayOfLogicalDiskInformations[i]->GetWholeDiskPdo() ==
  2495. WholeDiskPdo) {
  2496. return _arrayOfLogicalDiskInformations[i];
  2497. }
  2498. }
  2499. return NULL;
  2500. }
  2501. LONGLONG
  2502. GetMemberSize(
  2503. IN PDISK_CONFIG_HEADER Registry,
  2504. IN PDISK_PARTITION DiskPartition
  2505. )
  2506. {
  2507. PFT_DESCRIPTION ftDescription;
  2508. LONGLONG memberSize;
  2509. USHORT i;
  2510. PFT_MEMBER_DESCRIPTION ftMember;
  2511. PDISK_PARTITION diskPartition;
  2512. LONGLONG tmp;
  2513. ftDescription = GetFtDescription(Registry, DiskPartition);
  2514. if (!ftDescription) {
  2515. return 0;
  2516. }
  2517. memberSize = 0;
  2518. for (i = 0; i < ftDescription->NumberOfMembers; i++) {
  2519. ftMember = &ftDescription->FtMemberDescription[i];
  2520. diskPartition = (PDISK_PARTITION) ((PUCHAR) Registry +
  2521. ftMember->OffsetToPartitionInfo);
  2522. tmp = *((LONGLONG UNALIGNED*) &diskPartition->Length.QuadPart);
  2523. if (!memberSize || memberSize > tmp) {
  2524. memberSize = *((LONGLONG UNALIGNED*)
  2525. &diskPartition->Length.QuadPart);
  2526. }
  2527. }
  2528. return memberSize;
  2529. }
  2530. VOID
  2531. SetStateInfo(
  2532. IN PDISK_CONFIG_HEADER Registry,
  2533. IN PDISK_PARTITION DiskPartition,
  2534. OUT PFT_MIRROR_AND_SWP_STATE_INFORMATION State
  2535. )
  2536. {
  2537. PFT_DESCRIPTION ftDescription;
  2538. USHORT i;
  2539. PFT_MEMBER_DESCRIPTION ftMember;
  2540. PDISK_PARTITION diskPartition;
  2541. RtlZeroMemory(State, sizeof(FT_MIRROR_AND_SWP_STATE_INFORMATION));
  2542. if (Registry->DirtyShutdown) {
  2543. State->IsDirty = TRUE;
  2544. }
  2545. ftDescription = GetFtDescription(Registry, DiskPartition);
  2546. if (!ftDescription) {
  2547. return;
  2548. }
  2549. for (i = 0; i < ftDescription->NumberOfMembers; i++) {
  2550. ftMember = &ftDescription->FtMemberDescription[i];
  2551. diskPartition = (PDISK_PARTITION) ((PUCHAR) Registry +
  2552. ftMember->OffsetToPartitionInfo);
  2553. switch (diskPartition->FtState) {
  2554. case Orphaned:
  2555. State->UnhealthyMemberNumber = i;
  2556. State->UnhealthyMemberState = FtMemberOrphaned;
  2557. break;
  2558. case Regenerating:
  2559. State->UnhealthyMemberNumber = i;
  2560. State->UnhealthyMemberState = FtMemberRegenerating;
  2561. break;
  2562. case Initializing:
  2563. State->IsInitializing = TRUE;
  2564. break;
  2565. }
  2566. }
  2567. }
  2568. BOOLEAN
  2569. FT_LOGICAL_DISK_INFORMATION_SET::GetDiskDescription(
  2570. IN PDISK_CONFIG_HEADER Registry,
  2571. IN PDISK_PARTITION DiskPartition,
  2572. IN PFT_LOGICAL_DISK_DESCRIPTION CheckDiskDescription,
  2573. OUT PFT_LOGICAL_DISK_DESCRIPTION* DiskDescription
  2574. )
  2575. {
  2576. PFT_DESCRIPTION ftDescription;
  2577. USHORT i;
  2578. PFT_MEMBER_DESCRIPTION ftMember;
  2579. PDISK_PARTITION diskPartition;
  2580. FT_LOGICAL_DISK_ID partitionDiskId;
  2581. PFT_LOGICAL_DISK_DESCRIPTION diskDesc;
  2582. LONGLONG tmp;
  2583. ftDescription = GetFtDescription(Registry, DiskPartition);
  2584. if (!ftDescription) {
  2585. return FALSE;
  2586. }
  2587. for (i = 0; i < ftDescription->NumberOfMembers; i++) {
  2588. ftMember = &ftDescription->FtMemberDescription[i];
  2589. diskPartition = (PDISK_PARTITION) ((PUCHAR) Registry +
  2590. ftMember->OffsetToPartitionInfo);
  2591. tmp = *((LONGLONG UNALIGNED*) &diskPartition->StartingOffset.QuadPart);
  2592. partitionDiskId = QueryPartitionLogicalDiskId(
  2593. DiskNumberFromSignature(ftMember->Signature), tmp);
  2594. if (!partitionDiskId) {
  2595. continue;
  2596. }
  2597. diskDesc = GetParentLogicalDiskDescription(partitionDiskId);
  2598. if (!diskDesc) {
  2599. continue;
  2600. }
  2601. if (GetParentLogicalDiskDescription(diskDesc->LogicalDiskId)) {
  2602. continue;
  2603. }
  2604. if (diskDesc != CheckDiskDescription) {
  2605. *DiskDescription = diskDesc;
  2606. return TRUE;
  2607. }
  2608. }
  2609. return FALSE;
  2610. }
  2611. UCHAR
  2612. GetDriveLetter(
  2613. IN PDISK_CONFIG_HEADER Registry,
  2614. IN PDISK_PARTITION DiskPartition
  2615. )
  2616. {
  2617. PFT_DESCRIPTION ftDescription;
  2618. USHORT i;
  2619. PFT_MEMBER_DESCRIPTION ftMember;
  2620. PDISK_PARTITION diskPartition;
  2621. ftDescription = GetFtDescription(Registry, DiskPartition);
  2622. if (!ftDescription) {
  2623. return 0;
  2624. }
  2625. for (i = 0; i < ftDescription->NumberOfMembers; i++) {
  2626. ftMember = &ftDescription->FtMemberDescription[i];
  2627. diskPartition = (PDISK_PARTITION) ((PUCHAR) Registry +
  2628. ftMember->OffsetToPartitionInfo);
  2629. if (diskPartition->AssignDriveLetter) {
  2630. if (diskPartition->DriveLetter >= 'A' &&
  2631. diskPartition->DriveLetter <= 'Z') {
  2632. return diskPartition->DriveLetter;
  2633. } else if (!diskPartition->DriveLetter) {
  2634. if (IsNEC_98) return 0; //For fresh assigning drive letter on NEC98.
  2635. }
  2636. }
  2637. }
  2638. return 0xFF;
  2639. }
  2640. PFT_LOGICAL_DISK_DESCRIPTION
  2641. CreateDiskDescription(
  2642. IN PDISK_CONFIG_HEADER Registry,
  2643. IN PDISK_PARTITION DiskPartition,
  2644. IN FT_LOGICAL_DISK_ID PartitionDiskId
  2645. )
  2646. {
  2647. FT_LOGICAL_DISK_TYPE diskType;
  2648. USHORT configInfoSize, stateInfoSize, size;
  2649. PVOID configInfo, stateInfo;
  2650. FT_STRIPE_SET_CONFIGURATION_INFORMATION stripeConfig;
  2651. FT_MIRROR_SET_CONFIGURATION_INFORMATION mirrorConfig;
  2652. FT_MIRROR_AND_SWP_STATE_INFORMATION state;
  2653. FT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION swpConfig;
  2654. PFT_LOGICAL_DISK_DESCRIPTION diskDesc;
  2655. diskType = TranslateFtDiskType(DiskPartition->FtType);
  2656. switch (diskType) {
  2657. case FtVolumeSet:
  2658. configInfoSize = 0;
  2659. configInfo = NULL;
  2660. stateInfoSize = 0;
  2661. stateInfo = NULL;
  2662. break;
  2663. case FtStripeSet:
  2664. RtlZeroMemory(&stripeConfig, sizeof(stripeConfig));
  2665. stripeConfig.StripeSize = STRIPE_SIZE;
  2666. configInfoSize = sizeof(stripeConfig);
  2667. configInfo = &stripeConfig;
  2668. stateInfoSize = 0;
  2669. stateInfo = NULL;
  2670. break;
  2671. case FtMirrorSet:
  2672. RtlZeroMemory(&mirrorConfig, sizeof(mirrorConfig));
  2673. mirrorConfig.MemberSize = GetMemberSize(Registry, DiskPartition);
  2674. configInfoSize = sizeof(mirrorConfig);
  2675. configInfo = &mirrorConfig;
  2676. stateInfoSize = sizeof(state);
  2677. stateInfo = &state;
  2678. SetStateInfo(Registry, DiskPartition, &state);
  2679. break;
  2680. case FtStripeSetWithParity:
  2681. RtlZeroMemory(&swpConfig, sizeof(swpConfig));
  2682. swpConfig.MemberSize = GetMemberSize(Registry, DiskPartition);
  2683. swpConfig.StripeSize = STRIPE_SIZE;
  2684. configInfoSize = sizeof(swpConfig);
  2685. configInfo = &swpConfig;
  2686. stateInfoSize = sizeof(state);
  2687. stateInfo = &state;
  2688. SetStateInfo(Registry, DiskPartition, &state);
  2689. break;
  2690. default:
  2691. return NULL;
  2692. }
  2693. size = sizeof(FT_LOGICAL_DISK_DESCRIPTION) + configInfoSize +
  2694. stateInfoSize;
  2695. size = (size + FILE_QUAD_ALIGNMENT)&(~FILE_QUAD_ALIGNMENT);
  2696. diskDesc = (PFT_LOGICAL_DISK_DESCRIPTION) ExAllocatePool(PagedPool, size);
  2697. if (!diskDesc) {
  2698. return NULL;
  2699. }
  2700. RtlZeroMemory(diskDesc, size);
  2701. diskDesc->DiskDescriptionSize = size;
  2702. diskDesc->DriveLetter = GetDriveLetter(Registry, DiskPartition);
  2703. diskDesc->LogicalDiskType = diskType;
  2704. diskDesc->LogicalDiskId = GenerateNewLogicalDiskId();
  2705. diskDesc->u.Other.ThisMemberLogicalDiskId = PartitionDiskId;
  2706. diskDesc->u.Other.ThisMemberNumber = DiskPartition->FtMember;
  2707. diskDesc->u.Other.NumberOfMembers = GetRegistryNumberOfMembers(Registry,
  2708. DiskPartition);
  2709. if (diskDesc->u.Other.ThisMemberNumber >=
  2710. diskDesc->u.Other.NumberOfMembers) {
  2711. return NULL;
  2712. }
  2713. if (configInfo) {
  2714. diskDesc->u.Other.ByteOffsetToConfigurationInformation =
  2715. sizeof(FT_LOGICAL_DISK_DESCRIPTION);
  2716. RtlMoveMemory((PCHAR) diskDesc +
  2717. diskDesc->u.Other.ByteOffsetToConfigurationInformation,
  2718. configInfo, configInfoSize);
  2719. } else {
  2720. diskDesc->u.Other.ByteOffsetToConfigurationInformation = 0;
  2721. }
  2722. if (stateInfo) {
  2723. diskDesc->u.Other.ByteOffsetToStateInformation =
  2724. diskDesc->u.Other.ByteOffsetToConfigurationInformation +
  2725. configInfoSize;
  2726. RtlMoveMemory((PCHAR) diskDesc +
  2727. diskDesc->u.Other.ByteOffsetToStateInformation,
  2728. stateInfo, stateInfoSize);
  2729. } else {
  2730. diskDesc->u.Other.ByteOffsetToStateInformation = 0;
  2731. }
  2732. return diskDesc;
  2733. }
  2734. VOID
  2735. SetPartitionType(
  2736. IN PDEVICE_OBJECT Partition
  2737. )
  2738. {
  2739. KEVENT event;
  2740. PIRP irp;
  2741. PARTITION_INFORMATION partInfo;
  2742. IO_STATUS_BLOCK ioStatus;
  2743. NTSTATUS status;
  2744. SET_PARTITION_INFORMATION setPartInfo;
  2745. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2746. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
  2747. Partition, NULL, 0, &partInfo,
  2748. sizeof(partInfo), FALSE, &event,
  2749. &ioStatus);
  2750. if (!irp) {
  2751. return;
  2752. }
  2753. status = IoCallDriver(Partition, irp);
  2754. if (status == STATUS_PENDING) {
  2755. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2756. status = ioStatus.Status;
  2757. }
  2758. if (!NT_SUCCESS(status)) {
  2759. return;
  2760. }
  2761. setPartInfo.PartitionType = (partInfo.PartitionType | (0x80));
  2762. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2763. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_SET_PARTITION_INFO,
  2764. Partition, &setPartInfo,
  2765. sizeof(setPartInfo), NULL, 0, FALSE,
  2766. &event, &ioStatus);
  2767. if (!irp) {
  2768. return;
  2769. }
  2770. status = IoCallDriver(Partition, irp);
  2771. if (status == STATUS_PENDING) {
  2772. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2773. }
  2774. }
  2775. VOID
  2776. DeleteAncestors(
  2777. IN PFT_LOGICAL_DISK_INFORMATION LogicalDiskInformation,
  2778. IN FT_LOGICAL_DISK_ID PartitionLogicalDiskId
  2779. )
  2780. /*++
  2781. Routine Description:
  2782. This routine deletes the disk descriptions which are ancestors
  2783. to the given partition disk description on the given logical
  2784. disk information.
  2785. Arguments:
  2786. LogicalDiskInformation - Supplies the logical disk information.
  2787. PartitionLogicalDiskId - Supplies the partition logical disk id.
  2788. Return Value:
  2789. None.
  2790. --*/
  2791. {
  2792. PFT_LOGICAL_DISK_INFORMATION diskInfo = LogicalDiskInformation;
  2793. FT_LOGICAL_DISK_ID diskId = PartitionLogicalDiskId;
  2794. PFT_LOGICAL_DISK_DESCRIPTION diskDesc;
  2795. diskDesc = diskInfo->GetFirstLogicalDiskDescription();
  2796. while (diskDesc && diskDesc->DiskDescriptionSize) {
  2797. if (diskDesc->LogicalDiskType == FtPartition ||
  2798. diskDesc->u.Other.ThisMemberLogicalDiskId != diskId) {
  2799. diskDesc = diskInfo->GetNextLogicalDiskDescription(diskDesc);
  2800. continue;
  2801. }
  2802. diskId = diskDesc->LogicalDiskId;
  2803. diskInfo->DeleteLogicalDiskDescription(diskDesc);
  2804. }
  2805. FtpLogError(diskInfo->GetRootExtension(), diskInfo->QueryDiskNumber(),
  2806. FT_STALE_ONDISK, STATUS_SUCCESS, 0);
  2807. }
  2808. NTSTATUS
  2809. FT_LOGICAL_DISK_INFORMATION_SET::MigrateRegistryInformation(
  2810. IN PDEVICE_OBJECT Partition,
  2811. IN ULONG DiskNumber,
  2812. IN LONGLONG Offset
  2813. )
  2814. /*++
  2815. Routine Description:
  2816. This routine migrates the registry information for the given partition to
  2817. on disk structures. If all members of the FT set being migrated are on
  2818. disk then the registry information pertaining to the FT set is deleted.
  2819. Arguments:
  2820. DiskNumber - Supplies the disk number of the partition.
  2821. Offset - Supplies the partition offset.
  2822. Return Value:
  2823. NTSTATUS
  2824. --*/
  2825. {
  2826. ULONG i, signature, registrySize, length;
  2827. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  2828. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  2829. NTSTATUS status;
  2830. PDISK_CONFIG_HEADER registry;
  2831. PDISK_REGISTRY diskRegistry;
  2832. PDISK_PARTITION diskPartition;
  2833. FT_LOGICAL_DISK_ID partitionDiskId;
  2834. PFT_LOGICAL_DISK_DESCRIPTION diskDesc, newDesc, otherDesc;
  2835. PVOID config, newConfig;
  2836. PVOID state, newState;
  2837. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  2838. diskInfo = _arrayOfLogicalDiskInformations[i];
  2839. if (diskInfo->QueryDiskNumber() == DiskNumber) {
  2840. break;
  2841. }
  2842. }
  2843. if (i == _numberOfLogicalDiskInformations) {
  2844. return STATUS_INVALID_PARAMETER;
  2845. }
  2846. signature = FtpQueryDiskSignature(diskInfo->GetWholeDiskPdo());
  2847. if (!signature) {
  2848. return STATUS_SUCCESS;
  2849. }
  2850. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  2851. queryTable[0].QueryRoutine = FtpDiskRegistryQueryRoutine;
  2852. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  2853. queryTable[0].Name = L"Information";
  2854. queryTable[0].EntryContext = &registrySize;
  2855. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, DISK_REGISTRY_KEY_W,
  2856. queryTable, &registry, NULL);
  2857. if (!NT_SUCCESS(status)) {
  2858. return STATUS_SUCCESS;
  2859. }
  2860. if (!registry->FtInformationSize) {
  2861. ExFreePool(registry);
  2862. return STATUS_SUCCESS;
  2863. }
  2864. diskRegistry = (PDISK_REGISTRY)
  2865. ((PUCHAR) registry + registry->DiskInformationOffset);
  2866. diskPartition = FtpFindDiskPartition(diskRegistry, signature, Offset);
  2867. if (!diskPartition || diskPartition->FtType == NotAnFtMember) {
  2868. ExFreePool(registry);
  2869. return STATUS_SUCCESS;
  2870. }
  2871. if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + 1)) {
  2872. return STATUS_INSUFFICIENT_RESOURCES;
  2873. }
  2874. partitionDiskId = QueryPartitionLogicalDiskId(DiskNumber, Offset);
  2875. if (!partitionDiskId) {
  2876. status = CreatePartitionLogicalDisk(DiskNumber, Offset, 0,
  2877. &partitionDiskId);
  2878. if (!NT_SUCCESS(status)) {
  2879. ExFreePool(registry);
  2880. return status;
  2881. }
  2882. SetPartitionType(Partition);
  2883. }
  2884. diskDesc = GetParentLogicalDiskDescription(partitionDiskId);
  2885. newDesc = CreateDiskDescription(registry, diskPartition, partitionDiskId);
  2886. if (!newDesc) {
  2887. ExFreePool(registry);
  2888. return STATUS_INSUFFICIENT_RESOURCES;
  2889. }
  2890. if (diskDesc && GetParentLogicalDiskDescription(diskDesc->LogicalDiskId)) {
  2891. DeleteAncestors(diskInfo, partitionDiskId);
  2892. diskDesc = NULL;
  2893. }
  2894. if (diskDesc) {
  2895. if (diskDesc->DiskDescriptionSize != newDesc->DiskDescriptionSize ||
  2896. diskDesc->LogicalDiskType != newDesc->LogicalDiskType ||
  2897. diskDesc->u.Other.ThisMemberNumber !=
  2898. newDesc->u.Other.ThisMemberNumber ||
  2899. diskDesc->u.Other.NumberOfMembers !=
  2900. newDesc->u.Other.NumberOfMembers ||
  2901. diskDesc->u.Other.ByteOffsetToConfigurationInformation !=
  2902. newDesc->u.Other.ByteOffsetToConfigurationInformation ||
  2903. diskDesc->u.Other.ByteOffsetToStateInformation !=
  2904. newDesc->u.Other.ByteOffsetToStateInformation) {
  2905. DeleteAncestors(diskInfo, partitionDiskId);
  2906. diskDesc = NULL;
  2907. } else {
  2908. diskDesc->DriveLetter = newDesc->DriveLetter;
  2909. }
  2910. }
  2911. if (diskDesc && diskDesc->u.Other.ByteOffsetToConfigurationInformation) {
  2912. if (diskDesc->u.Other.ByteOffsetToStateInformation) {
  2913. length = diskDesc->u.Other.ByteOffsetToStateInformation -
  2914. diskDesc->u.Other.ByteOffsetToConfigurationInformation;
  2915. } else {
  2916. length = diskDesc->DiskDescriptionSize -
  2917. diskDesc->u.Other.ByteOffsetToConfigurationInformation;
  2918. }
  2919. config = (PCHAR) diskDesc +
  2920. diskDesc->u.Other.ByteOffsetToConfigurationInformation;
  2921. newConfig = (PCHAR) newDesc +
  2922. newDesc->u.Other.ByteOffsetToConfigurationInformation;
  2923. if (RtlCompareMemory(config, newConfig, length) != length) {
  2924. DeleteAncestors(diskInfo, partitionDiskId);
  2925. diskDesc = NULL;
  2926. }
  2927. }
  2928. if (diskDesc && diskDesc->u.Other.ByteOffsetToStateInformation) {
  2929. length = diskDesc->DiskDescriptionSize -
  2930. diskDesc->u.Other.ByteOffsetToStateInformation;
  2931. state = (PCHAR) diskDesc +
  2932. diskDesc->u.Other.ByteOffsetToStateInformation;
  2933. newState = (PCHAR) newDesc +
  2934. newDesc->u.Other.ByteOffsetToStateInformation;
  2935. RtlCopyMemory(state, newState, length);
  2936. }
  2937. if (!GetDiskDescription(registry, diskPartition, diskDesc, &otherDesc)) {
  2938. otherDesc = NULL;
  2939. }
  2940. if (diskDesc) {
  2941. diskDesc->DriveLetter = newDesc->DriveLetter;
  2942. } else {
  2943. diskDesc = diskInfo->AddLogicalDiskDescription(newDesc);
  2944. }
  2945. if (otherDesc &&
  2946. !QueryMemberLogicalDiskId(otherDesc->LogicalDiskId,
  2947. diskPartition->FtMember)) {
  2948. diskDesc->LogicalDiskId = otherDesc->LogicalDiskId;
  2949. }
  2950. if (IsLogicalDiskComplete(diskDesc->LogicalDiskId)) {
  2951. DeleteFtRegistryInformation(registry, diskPartition);
  2952. }
  2953. RecomputeArrayOfRootLogicalDiskIds();
  2954. diskInfo->Write();
  2955. RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, DISK_REGISTRY_KEY_W,
  2956. L"Information", REG_BINARY, registry,
  2957. registrySize);
  2958. ExFreePool(newDesc);
  2959. ExFreePool(registry);
  2960. return STATUS_SUCCESS;
  2961. }
  2962. FT_LOGICAL_DISK_INFORMATION_SET::~FT_LOGICAL_DISK_INFORMATION_SET(
  2963. )
  2964. {
  2965. ULONG i;
  2966. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  2967. delete _arrayOfLogicalDiskInformations[i];
  2968. }
  2969. if (_arrayOfLogicalDiskInformations) {
  2970. ExFreePool(_arrayOfLogicalDiskInformations);
  2971. }
  2972. if (_arrayOfRootLogicalDiskIds) {
  2973. ExFreePool(_arrayOfRootLogicalDiskIds);
  2974. }
  2975. }
  2976. BOOLEAN
  2977. FT_LOGICAL_DISK_INFORMATION_SET::ReallocRootLogicalDiskIds(
  2978. IN ULONG NewNumberOfEntries
  2979. )
  2980. /*++
  2981. Routine Description;
  2982. This routine reallocs the root logical disk ids buffer to contain
  2983. the given number of entries. It does not change the number of
  2984. disk ids private member, it just enlarges the buffer.
  2985. Arguments:
  2986. NewNumberOfEntries - Supplies the new size of the buffer.
  2987. Return Value:
  2988. FALSE - Failure.
  2989. TRUE - Success.
  2990. --*/
  2991. {
  2992. PFT_LOGICAL_DISK_ID newLogicalDiskIdArray;
  2993. if (NewNumberOfEntries <= _numberOfRootLogicalDisksIds) {
  2994. return TRUE;
  2995. }
  2996. newLogicalDiskIdArray = (PFT_LOGICAL_DISK_ID)
  2997. ExAllocatePool(NonPagedPool, NewNumberOfEntries*
  2998. sizeof(FT_LOGICAL_DISK_ID));
  2999. if (!newLogicalDiskIdArray) {
  3000. return FALSE;
  3001. }
  3002. if (_arrayOfRootLogicalDiskIds) {
  3003. RtlMoveMemory(newLogicalDiskIdArray, _arrayOfRootLogicalDiskIds,
  3004. _numberOfRootLogicalDisksIds*sizeof(FT_LOGICAL_DISK_ID));
  3005. ExFreePool(_arrayOfRootLogicalDiskIds);
  3006. }
  3007. _arrayOfRootLogicalDiskIds = newLogicalDiskIdArray;
  3008. return TRUE;
  3009. }
  3010. VOID
  3011. FT_LOGICAL_DISK_INFORMATION_SET::RecomputeArrayOfRootLogicalDiskIds(
  3012. )
  3013. /*++
  3014. Routine Description:
  3015. This routine computes the array of root logical disk ids.
  3016. Arguments:
  3017. None.
  3018. Return Value:
  3019. None.
  3020. --*/
  3021. {
  3022. ULONG i, j;
  3023. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  3024. PFT_LOGICAL_DISK_DESCRIPTION p, q;
  3025. _numberOfRootLogicalDisksIds = 0;
  3026. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  3027. diskInfo = _arrayOfLogicalDiskInformations[i];
  3028. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  3029. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  3030. for (q = diskInfo->GetFirstLogicalDiskDescription(); q;
  3031. q = diskInfo->GetNextLogicalDiskDescription(q)) {
  3032. if (q->LogicalDiskType != FtPartition &&
  3033. q->u.Other.ThisMemberLogicalDiskId == p->LogicalDiskId) {
  3034. break;
  3035. }
  3036. }
  3037. if (!q) {
  3038. for (j = 0; j < _numberOfRootLogicalDisksIds; j++) {
  3039. if (_arrayOfRootLogicalDiskIds[j] == p->LogicalDiskId) {
  3040. break;
  3041. }
  3042. }
  3043. if (j == _numberOfRootLogicalDisksIds) {
  3044. _arrayOfRootLogicalDiskIds[j] = p->LogicalDiskId;
  3045. _numberOfRootLogicalDisksIds++;
  3046. }
  3047. }
  3048. }
  3049. }
  3050. }
  3051. BOOLEAN
  3052. FT_LOGICAL_DISK_INFORMATION_SET::ComputeNewParentLogicalDiskIds(
  3053. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  3054. OUT PULONG NumLogicalDiskIds,
  3055. OUT PFT_LOGICAL_DISK_ID* OldLogicalDiskIds,
  3056. OUT PFT_LOGICAL_DISK_ID* NewLogicalDiskIds
  3057. )
  3058. /*++
  3059. Routine Description:
  3060. This routine finds all of the parents of the given logical disk id and
  3061. computes replacement logical disk ids for them.
  3062. Arguments:
  3063. LogicalDiskId - Supplies the logical disk id.
  3064. NumLogicalDiskIds - Returns the number of parents.
  3065. OldLogicalDiskIds - Returns the existing geneology for the given
  3066. logical disk id.
  3067. NewLogicalDiskIds - Returns the new geneology for the given
  3068. logical disk id.
  3069. Return Value:
  3070. FALSE - Insufficient resources.
  3071. TRUE - Success.
  3072. --*/
  3073. {
  3074. PFT_LOGICAL_DISK_DESCRIPTION p;
  3075. ULONG n, i;
  3076. n = 1;
  3077. for (p = GetParentLogicalDiskDescription(LogicalDiskId); p;
  3078. p = GetParentLogicalDiskDescription(p->LogicalDiskId)) {
  3079. n++;
  3080. }
  3081. *NumLogicalDiskIds = n;
  3082. *OldLogicalDiskIds = (PFT_LOGICAL_DISK_ID)
  3083. ExAllocatePool(PagedPool,
  3084. n*sizeof(FT_LOGICAL_DISK_ID));
  3085. if (!*OldLogicalDiskIds) {
  3086. return FALSE;
  3087. }
  3088. *NewLogicalDiskIds = (PFT_LOGICAL_DISK_ID)
  3089. ExAllocatePool(PagedPool,
  3090. n*sizeof(FT_LOGICAL_DISK_ID));
  3091. if (!*NewLogicalDiskIds) {
  3092. ExFreePool(*OldLogicalDiskIds);
  3093. return FALSE;
  3094. }
  3095. (*OldLogicalDiskIds)[0] = LogicalDiskId;
  3096. (*NewLogicalDiskIds)[0] = GenerateNewLogicalDiskId();
  3097. i = 1;
  3098. for (p = GetParentLogicalDiskDescription(LogicalDiskId); p;
  3099. p = GetParentLogicalDiskDescription(p->LogicalDiskId)) {
  3100. (*OldLogicalDiskIds)[i] = p->LogicalDiskId;
  3101. (*NewLogicalDiskIds)[i] = GenerateNewLogicalDiskId();
  3102. i++;
  3103. }
  3104. ASSERT(i == n);
  3105. return TRUE;
  3106. }
  3107. #ifdef ALLOC_PRAGMA
  3108. #pragma code_seg()
  3109. #endif
  3110. PFT_LOGICAL_DISK_DESCRIPTION
  3111. FT_LOGICAL_DISK_INFORMATION::GetNextLogicalDiskDescription(
  3112. IN PFT_LOGICAL_DISK_DESCRIPTION CurrentDiskDescription
  3113. )
  3114. /*++
  3115. Routine Description:
  3116. This routine returns the next logical disk description for a
  3117. given logical disk description.
  3118. Arguments:
  3119. CurrentDiskDescription - Supplies the current disk description.
  3120. Return Value:
  3121. The next disk description or NULL if no more disk descriptions
  3122. are present.
  3123. --*/
  3124. {
  3125. PFT_LOGICAL_DISK_DESCRIPTION next;
  3126. next = (PFT_LOGICAL_DISK_DESCRIPTION)
  3127. ((PCHAR) CurrentDiskDescription +
  3128. CurrentDiskDescription->DiskDescriptionSize);
  3129. if ((ULONG) ((PCHAR) next - (PCHAR) _diskBuffer) >
  3130. _length - sizeof(USHORT)) {
  3131. return NULL;
  3132. }
  3133. if ((ULONG) ((PCHAR) next - (PCHAR) _diskBuffer +
  3134. next->DiskDescriptionSize) > _length) {
  3135. return NULL;
  3136. }
  3137. if (next->DiskDescriptionSize < sizeof(FT_LOGICAL_DISK_DESCRIPTION)) {
  3138. return NULL;
  3139. }
  3140. return next;
  3141. }
  3142. PFT_LOGICAL_DISK_DESCRIPTION
  3143. FT_LOGICAL_DISK_INFORMATION_SET::GetParentLogicalDiskDescription(
  3144. IN PFT_LOGICAL_DISK_DESCRIPTION LogicalDiskDescription,
  3145. IN ULONG DiskInformationNumber
  3146. )
  3147. /*++
  3148. Routine Description:
  3149. This routine gets the parent logical disk description.
  3150. Arguments:
  3151. LogicalDiskDescription - Supplies the child logical disk description.
  3152. DiskInformationNumber - Supplies the disk information number.
  3153. Return Value:
  3154. The parent logical disk description or NULL.
  3155. --*/
  3156. {
  3157. FT_LOGICAL_DISK_ID diskId;
  3158. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  3159. PFT_LOGICAL_DISK_DESCRIPTION p;
  3160. diskId = LogicalDiskDescription->LogicalDiskId;
  3161. diskInfo = _arrayOfLogicalDiskInformations[DiskInformationNumber];
  3162. for (p = diskInfo->GetNextLogicalDiskDescription(LogicalDiskDescription);
  3163. p; p = diskInfo->GetNextLogicalDiskDescription(p)) {
  3164. if (p->LogicalDiskType != FtPartition &&
  3165. p->u.Other.ThisMemberLogicalDiskId == diskId) {
  3166. return p;
  3167. }
  3168. }
  3169. return NULL;
  3170. }
  3171. PFT_LOGICAL_DISK_DESCRIPTION
  3172. FT_LOGICAL_DISK_INFORMATION_SET::GetParentLogicalDiskDescription(
  3173. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  3174. OUT PULONG DiskInformationNumber
  3175. )
  3176. /*++
  3177. Routine Description:
  3178. This routine gets the parent logical disk description for the
  3179. given logical disk id.
  3180. Arguments:
  3181. LogicalDiskId - Supplies the logical disk id.
  3182. DiskInformationNumber - Returns the disk information number.
  3183. Return Value:
  3184. The parent logical disk description or NULL.
  3185. --*/
  3186. {
  3187. ULONG i;
  3188. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  3189. PFT_LOGICAL_DISK_DESCRIPTION p;
  3190. for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
  3191. diskInfo = _arrayOfLogicalDiskInformations[i];
  3192. for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
  3193. p = diskInfo->GetNextLogicalDiskDescription(p)) {
  3194. if (p->LogicalDiskType != FtPartition &&
  3195. p->u.Other.ThisMemberLogicalDiskId == LogicalDiskId) {
  3196. if (DiskInformationNumber) {
  3197. *DiskInformationNumber = i;
  3198. }
  3199. return p;
  3200. }
  3201. }
  3202. }
  3203. return NULL;
  3204. }
  3205. PFT_LOGICAL_DISK_DESCRIPTION
  3206. FT_LOGICAL_DISK_INFORMATION::GetFirstLogicalDiskDescription(
  3207. )
  3208. /*++
  3209. Routine Description:
  3210. This routine returns the first logical disk description in the
  3211. list.
  3212. Arguments:
  3213. None.
  3214. Return Value:
  3215. A pointer inside the buffer for the first logical disk description or
  3216. NULL if there are no logical disk descriptions.
  3217. --*/
  3218. {
  3219. PFT_ON_DISK_PREAMBLE preamble;
  3220. PFT_LOGICAL_DISK_DESCRIPTION diskDescription;
  3221. if (!_length) {
  3222. return NULL;
  3223. }
  3224. preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
  3225. if (preamble->FtOnDiskSignature != FT_ON_DISK_SIGNATURE ||
  3226. preamble->DiskDescriptionVersionNumber != FT_ON_DISK_DESCRIPTION_VERSION_NUMBER ||
  3227. preamble->ByteOffsetToFirstFtLogicalDiskDescription <
  3228. sizeof(FT_ON_DISK_PREAMBLE) ||
  3229. preamble->ByteOffsetToFirstFtLogicalDiskDescription >
  3230. _length - sizeof(ULONG)) {
  3231. return NULL;
  3232. }
  3233. diskDescription = (PFT_LOGICAL_DISK_DESCRIPTION)
  3234. ((PCHAR) preamble +
  3235. preamble->ByteOffsetToFirstFtLogicalDiskDescription);
  3236. if (diskDescription->DiskDescriptionSize <
  3237. sizeof(FT_LOGICAL_DISK_DESCRIPTION)) {
  3238. return NULL;
  3239. }
  3240. if ((ULONG) ((PCHAR) diskDescription - (PCHAR) _diskBuffer +
  3241. diskDescription->DiskDescriptionSize) > _length) {
  3242. return NULL;
  3243. }
  3244. return diskDescription;
  3245. }