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.

4468 lines
119 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. diskinfo.cpp
  5. Abstract:
  6. Routines that query and manipulate the
  7. disk configuration of the current system.
  8. Author:
  9. John Vert (jvert) 10/10/1996
  10. Revision History:
  11. --*/
  12. #include "diskinfo.h"
  13. #include <ntddvol.h>
  14. #include <devguid.h>
  15. #include <setupapi.h>
  16. #include "clusrtl.h"
  17. #include <strsafe.h> // Should be included last.
  18. /*
  19. NT5 porting notes - Charlie Wickham (2/10/98)
  20. I tried to touch as little of this as possible since there is alot of code
  21. here. Two major differences on NT5 are: 1) the System\Disk key is no longer
  22. used as the central "database" of disk configuration information and 2) all
  23. drive letters are sticky on NT5.
  24. NT5 Clusters still needs a central point of information (such as DISK key)
  25. since the joining node cannot determine anything about the disk configuration
  26. when the disks are reserved by the sponsor.
  27. Later... (3/29/99)
  28. Much has changed since I wrote the first blurb above a year ago. This code has
  29. been patched to keep up with the changes with slight improvements made due to
  30. the ever changing NT5 landscape with regard to supported storage types.
  31. */
  32. #if 1
  33. #define DISKERR(_MsgId_, _Err_) (DiskErrorFatal((0),(_Err_),__FILE__, __LINE__))
  34. #define DISKLOG(_x_) DiskErrorLogInfo _x_
  35. #define DISKASSERT(_x_) if (!(_x_)) DISKERR(IDS_GENERAL_FAILURE,ERROR_INVALID_PARAMETER)
  36. #else
  37. #define DISKERR(x,y)
  38. #define DISKLOG(_x_)
  39. #define DISKASSERT(_x_)
  40. #endif
  41. //
  42. // array that maps disk and partition numbers to drive letters. This
  43. // facilitates figuring out which drive letters are associated with a drive
  44. // and reduces the amount of calls to CreateFile dramatically. The array is
  45. // indexed by drive letter.
  46. //
  47. DRIVE_LETTER_INFO DriveLetterMap[26];
  48. //
  49. // Some handy registry utility routines
  50. //
  51. BOOL
  52. GetRegValue(
  53. IN HKEY hKey,
  54. IN LPCWSTR Name,
  55. OUT LPBYTE *Value,
  56. OUT LPDWORD Length
  57. )
  58. {
  59. LPBYTE Data = NULL;
  60. DWORD cbData=0;
  61. LONG Status;
  62. //
  63. // Call once to find the required size.
  64. //
  65. Status = RegQueryValueExW(hKey,
  66. Name,
  67. NULL,
  68. NULL,
  69. NULL,
  70. &cbData);
  71. if (Status != ERROR_SUCCESS) {
  72. SetLastError(Status);
  73. return(FALSE);
  74. }
  75. //
  76. // Allocate the buffer and call again to get the data.
  77. //
  78. retry:
  79. Data = (LPBYTE)LocalAlloc(LMEM_FIXED, cbData);;
  80. if (!Data) {
  81. Status = GetLastError();
  82. DISKERR(IDS_MEMORY_FAILURE, Status);
  83. return FALSE;
  84. }
  85. Status = RegQueryValueExW(hKey,
  86. Name,
  87. NULL,
  88. NULL,
  89. Data,
  90. &cbData);
  91. if (Status == ERROR_MORE_DATA) {
  92. LocalFree(Data);
  93. goto retry;
  94. }
  95. if (Status != ERROR_SUCCESS) {
  96. SetLastError(Status);
  97. DISKERR(IDS_REGISTRY_FAILURE, Status);
  98. return FALSE;
  99. }
  100. *Value = Data;
  101. *Length = cbData;
  102. return(TRUE);
  103. }
  104. BOOL
  105. MapDosVolumeToPhysicalPartition(
  106. CString DosVolume,
  107. PDRIVE_LETTER_INFO DriveInfo
  108. )
  109. /*++
  110. Routine Description:
  111. For a given dos volume (with the object space cruft in front of
  112. it), build a string that reflects the drive and partition numbers
  113. to which it is mapped.
  114. Arguments:
  115. DosVolume - pointer to "\??\C:" style name
  116. DeviceInfo - pointer to buffer to receive device info data
  117. Return Value:
  118. TRUE if completed successfully
  119. --*/
  120. {
  121. BOOL success = TRUE;
  122. HANDLE hVol;
  123. DWORD dwSize;
  124. DWORD Status;
  125. UINT driveType;
  126. DriveInfo->DriveType = GetDriveType( DosVolume );
  127. DISKLOG(("%ws drive type = %u\n", DosVolume, DriveInfo->DriveType ));
  128. if ( DriveInfo->DriveType == DRIVE_FIXED ) {
  129. WCHAR ntDosVolume[7] = L"\\\\.\\A:";
  130. ntDosVolume[4] = DosVolume[0];
  131. //
  132. // get handle to partition
  133. //
  134. hVol = CreateFile(ntDosVolume,
  135. GENERIC_READ,
  136. FILE_SHARE_READ | FILE_SHARE_WRITE,
  137. NULL,
  138. OPEN_EXISTING,
  139. FILE_ATTRIBUTE_NORMAL,
  140. NULL);
  141. if (hVol == INVALID_HANDLE_VALUE) {
  142. return FALSE;
  143. }
  144. //
  145. // issue storage class ioctl to get drive and partition numbers
  146. // for this device
  147. //
  148. success = DeviceIoControl(hVol,
  149. IOCTL_STORAGE_GET_DEVICE_NUMBER,
  150. NULL,
  151. 0,
  152. &DriveInfo->DeviceNumber,
  153. sizeof( DriveInfo->DeviceNumber ),
  154. &dwSize,
  155. NULL);
  156. if ( !success ) {
  157. DISK_EXTENT diskExtent;
  158. success = DeviceIoControl(hVol,
  159. IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
  160. NULL,
  161. 0,
  162. &diskExtent,
  163. sizeof( diskExtent ),
  164. &dwSize,
  165. NULL);
  166. if ( success ) {
  167. DriveInfo->DeviceNumber.DeviceType = FILE_DEVICE_DISK;
  168. DriveInfo->DeviceNumber.DeviceNumber = diskExtent.DiskNumber;
  169. DriveInfo->DeviceNumber.PartitionNumber = 0;
  170. }
  171. }
  172. CloseHandle( hVol );
  173. }
  174. return success;
  175. }
  176. CDiskConfig::~CDiskConfig()
  177. /*++
  178. Description:
  179. Destructor for CDiskConfig. Run down the list of disks selected for
  180. cluster control and remove them from the DiskConfig database
  181. Arguments:
  182. None
  183. Return Value:
  184. None
  185. --*/
  186. {
  187. CPhysicalDisk *PhysicalDisk;
  188. int diskIndex;
  189. POSITION pos;
  190. for(pos = m_PhysicalDisks.GetStartPosition(); pos;){
  191. m_PhysicalDisks.GetNextAssoc(pos, diskIndex, PhysicalDisk);
  192. RemoveDisk(PhysicalDisk);
  193. }
  194. }
  195. BOOL
  196. CDiskConfig::Initialize(
  197. VOID
  198. )
  199. /*++
  200. Routine Description:
  201. Build up a disk config database by poking all available disks
  202. on the system.
  203. Arguments:
  204. None
  205. Return Value:
  206. True if everything worked ok
  207. --*/
  208. {
  209. WCHAR System[3];
  210. DWORD Status;
  211. POSITION DiskPos;
  212. DWORD index;
  213. CFtInfoFtSet *FtSet;
  214. HDEVINFO setupDiskInfo;
  215. GUID diskDriveGuid = DiskClassGuid;
  216. CPhysicalDisk * PhysicalDisk;
  217. //
  218. // enum the disks through the SetupDi APIs and create physical disk
  219. // objects for them
  220. //
  221. setupDiskInfo = SetupDiGetClassDevs(&diskDriveGuid,
  222. NULL,
  223. NULL,
  224. DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
  225. if (setupDiskInfo != INVALID_HANDLE_VALUE ) {
  226. SP_DEVICE_INTERFACE_DATA interfaceData;
  227. GUID classGuid = DiskClassGuid;
  228. BOOL success;
  229. PSP_DEVICE_INTERFACE_DETAIL_DATA detailData;
  230. DWORD detailDataSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH * sizeof(WCHAR);
  231. DWORD requiredSize;
  232. detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED,
  233. detailDataSize);
  234. if ( detailData != NULL ) {
  235. detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  236. interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  237. for (index = 0; ; ++index ) {
  238. success = SetupDiEnumDeviceInterfaces(
  239. setupDiskInfo,
  240. NULL,
  241. &diskDriveGuid,
  242. index,
  243. &interfaceData);
  244. if ( success ) {
  245. success = SetupDiGetDeviceInterfaceDetail(
  246. setupDiskInfo,
  247. &interfaceData,
  248. detailData,
  249. detailDataSize,
  250. &requiredSize,
  251. NULL);
  252. if ( success ) {
  253. PhysicalDisk = new CPhysicalDisk;
  254. if (PhysicalDisk == NULL) {
  255. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  256. break;
  257. }
  258. DISKLOG(("Initializing disk %ws\n", detailData->DevicePath));
  259. Status = PhysicalDisk->Initialize(&m_FTInfo, detailData->DevicePath);
  260. if (Status != ERROR_SUCCESS) {
  261. DISKLOG(("Problem init'ing disk, status = %u\n", Status));
  262. delete PhysicalDisk;
  263. break;
  264. }
  265. //
  266. // Ignore disks with no partitions.
  267. //
  268. if (PhysicalDisk->m_PartitionCount == 0) {
  269. DISKLOG(("Partition count is zero on disk %ws\n",
  270. detailData->DevicePath));
  271. delete PhysicalDisk;
  272. } else {
  273. DISKLOG(("Drive number = %u\n", PhysicalDisk->m_DiskNumber));
  274. m_PhysicalDisks[PhysicalDisk->m_DiskNumber] = PhysicalDisk;
  275. }
  276. } else {
  277. Status = GetLastError();
  278. DISKLOG(("Couldn't get detail data, status %u\n",
  279. GetLastError()));
  280. }
  281. } else {
  282. Status = GetLastError();
  283. if ( Status != ERROR_NO_MORE_ITEMS ) {
  284. DISKLOG(("Couldn't enum dev IF #%u - %u\n",
  285. index, Status ));
  286. }
  287. break;
  288. }
  289. }
  290. LocalFree( detailData );
  291. } else {
  292. DISKLOG(("Couldn't get memory for detail data\n"));
  293. SetupDiDestroyDeviceInfoList( setupDiskInfo );
  294. return FALSE;
  295. }
  296. SetupDiDestroyDeviceInfoList( setupDiskInfo );
  297. } else {
  298. DISKLOG(("Couldn't get ptr to device info - %u\n", GetLastError()));
  299. return FALSE;
  300. }
  301. //
  302. // Enumerate all the FT sets in the DISK registry. Add each FT set
  303. // that does not share a disk with any other FT set to our list.
  304. //
  305. for (index=0; ; index++) {
  306. CFtSet *NewSet;
  307. FtSet = m_FTInfo.EnumFtSetInfo(index);
  308. if (FtSet == NULL) {
  309. break;
  310. }
  311. if (FtSet->IsAlone()) {
  312. NewSet = new CFtSet;
  313. if (NewSet == NULL) {
  314. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  315. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  316. return FALSE;
  317. }
  318. DISKLOG(("Initializing FTSet %u\n", index));
  319. if (NewSet->Initialize(this, FtSet)) {
  320. m_FtSetList.AddTail(NewSet);
  321. } else {
  322. DISKLOG(("Error initializing FTSet %u\n", index));
  323. delete NewSet;
  324. }
  325. }
  326. }
  327. //
  328. // get the disk/parition numbers for all defined drive letters
  329. //
  330. DWORD DriveMap = GetLogicalDrives();
  331. DWORD Letter = 0;
  332. WCHAR DosVolume[4] = L"A:\\";
  333. DISKLOG(("Getting Drive Letter mappings\n"));
  334. while (DriveMap) {
  335. if ( DriveMap & 1 ) {
  336. DosVolume[0] = (WCHAR)(Letter + L'A');
  337. DISKLOG(("Mapping %ws\n", DosVolume));
  338. if (MapDosVolumeToPhysicalPartition(DosVolume,
  339. &DriveLetterMap[ Letter ]))
  340. {
  341. if ( DriveLetterMap[ Letter ].DriveType != DRIVE_FIXED ) {
  342. DISKLOG(("%ws is not a fixed disk\n", DosVolume));
  343. DriveLetterMap[ Letter ].DeviceNumber.PartitionNumber = 0;
  344. }
  345. } else {
  346. DISKLOG(("Can't map %ws: %u\n", DosVolume, GetLastError()));
  347. }
  348. }
  349. DriveMap >>= 1;
  350. Letter += 1;
  351. }
  352. //
  353. // Go through all the physical partitions and create logical
  354. // disk objects for each one.
  355. //
  356. int diskIndex;
  357. DISKLOG(("Creating Logical disk objects\n"));
  358. DiskPos = m_PhysicalDisks.GetStartPosition();
  359. while (DiskPos != NULL) {
  360. m_PhysicalDisks.GetNextAssoc(DiskPos, diskIndex, PhysicalDisk);
  361. //
  362. // If there are no FT partitions on this disk, create the logical
  363. // volumes on this disk.
  364. //
  365. if (PhysicalDisk->FtPartitionCount() == 0) {
  366. //
  367. // Go through all the partitions on this disk.
  368. //
  369. POSITION PartitionPos = PhysicalDisk->m_PartitionList.GetHeadPosition();
  370. CPhysicalPartition *Partition;
  371. while (PartitionPos != NULL) {
  372. Partition = PhysicalDisk->m_PartitionList.GetNext(PartitionPos);
  373. //
  374. // If the partition type is recognized, create a volume object
  375. // for this partition.
  376. //
  377. if ( !IsFTPartition( Partition->m_Info.PartitionType ) &&
  378. (IsRecognizedPartition(Partition->m_Info.PartitionType))) {
  379. CLogicalDrive *Volume = new CLogicalDrive;
  380. if (Volume == NULL) {
  381. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  382. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  383. return FALSE;
  384. }
  385. DISKLOG(("Init'ing logical vol for disk %u, part %u\n",
  386. Partition->m_PhysicalDisk->m_DiskNumber,
  387. Partition->m_Info.PartitionNumber));
  388. if (Volume->Initialize(Partition)) {
  389. //
  390. // Add this volume to our list.
  391. //
  392. m_LogicalDrives[Volume->m_DriveLetter] = Volume;
  393. } else {
  394. DISKLOG(("Failed init logical vol\n"));
  395. delete(Volume);
  396. }
  397. }
  398. }
  399. }
  400. }
  401. //
  402. // Now find the volume for the system drive
  403. //
  404. DISKLOG(("Getting system drive info\n"));
  405. if (GetEnvironmentVariable(L"SystemDrive",
  406. System,
  407. sizeof(System)/sizeof(WCHAR)) == 0) {
  408. DISKERR(IDS_ERR_DRIVE_CONFIG, ERROR_PATH_NOT_FOUND);
  409. // Need to handle this failure
  410. }
  411. if (!m_LogicalDrives.Lookup(System[0], m_SystemVolume)) {
  412. //
  413. // There are some weird cases that cause us to not find the system
  414. // volume. For example, the system volume is on an FT set that shares
  415. // a member with another FT set. So we just leave m_SystemVolume==NULL
  416. // and assume that no other disks in our list will be on the same bus.
  417. //
  418. m_SystemVolume = NULL;
  419. }
  420. DISKLOG(("Finished gathering disk config info\n"));
  421. return(TRUE);
  422. }
  423. VOID
  424. CDiskConfig::RemoveAllFtInfoData(
  425. VOID
  426. )
  427. /*++
  428. Routine Description:
  429. clear out all FtInfo related data associated with each
  430. physical disk and physical partition instance.
  431. Arguments:
  432. None
  433. Return Value:
  434. None.
  435. --*/
  436. {
  437. POSITION diskPos;
  438. POSITION partitionPos;
  439. CPhysicalDisk *disk;
  440. CPhysicalPartition *partition;
  441. int Index;
  442. //
  443. // run through our list of physical disks, deleting any
  444. // associated FtInfo data. We enum the PhysicalDisks since
  445. // the back pointers to the FtInfoDisk and FtInfoPartition members
  446. // need to be cleared and this is the only (easy) to do that
  447. //
  448. for( diskPos = m_PhysicalDisks.GetStartPosition(); diskPos; ) {
  449. m_PhysicalDisks.GetNextAssoc(diskPos, Index, disk);
  450. if ( disk->m_FtInfo != NULL ) {
  451. DISKLOG(("Removing %08X from FtInfo DB\n", disk->m_Signature));
  452. m_FTInfo.DeleteDiskInfo( disk->m_Signature );
  453. disk->m_FtInfo = NULL;
  454. partitionPos = disk->m_PartitionList.GetHeadPosition();
  455. while (partitionPos) {
  456. partition = disk->m_PartitionList.GetNext( partitionPos );
  457. partition->m_FtPartitionInfo = NULL;
  458. }
  459. }
  460. }
  461. }
  462. VOID
  463. CDiskConfig::RemoveDisk(
  464. IN CPhysicalDisk *Disk
  465. )
  466. /*++
  467. Description:
  468. walk the logical drive and physical partition lists, removing all
  469. structures
  470. Arguments:
  471. Disk - pointer to physical disk that is being removed
  472. Return Value:
  473. None
  474. --*/
  475. {
  476. CLogicalDrive *Volume;
  477. //
  478. // Remove all the logical drives on this disk.
  479. //
  480. while (!Disk->m_LogicalDriveList.IsEmpty()) {
  481. Volume = Disk->m_LogicalDriveList.RemoveHead();
  482. m_LogicalDrives.RemoveKey(Volume->m_DriveLetter);
  483. delete(Volume);
  484. }
  485. //
  486. // Remove all the physical partitions on this disk.
  487. //
  488. CPhysicalPartition *Partition;
  489. while (!Disk->m_PartitionList.IsEmpty()) {
  490. Partition = Disk->m_PartitionList.RemoveHead();
  491. delete(Partition);
  492. }
  493. //
  494. // Remove this disk
  495. //
  496. m_PhysicalDisks.RemoveKey(Disk->m_DiskNumber);
  497. delete(Disk);
  498. }
  499. CPhysicalPartition *
  500. CDiskConfig::FindPartition(
  501. IN CFtInfoPartition *FtPartition
  502. )
  503. /*++
  504. Routine Description:
  505. Given the FtInfo description of a partition, attempts to find
  506. the corresponding CPhysicalPartition
  507. Arguments:
  508. FtPartition - Supplies an FT partition description
  509. Return Value:
  510. A pointer to the CPhysicalPartition if successful
  511. NULL otherwise
  512. --*/
  513. {
  514. POSITION pos;
  515. CPhysicalDisk *Disk;
  516. CPhysicalPartition *Partition;
  517. int DiskIndex;
  518. BOOL Found = FALSE;
  519. //
  520. // First find the appropriate CPhysicalDisk
  521. //
  522. pos = m_PhysicalDisks.GetStartPosition();
  523. while (pos) {
  524. m_PhysicalDisks.GetNextAssoc(pos, DiskIndex, Disk);
  525. if (Disk->m_FtInfo) {
  526. if (Disk->m_FtInfo->m_Signature == FtPartition->m_ParentDisk->m_Signature) {
  527. Found = TRUE;
  528. break;
  529. }
  530. }
  531. }
  532. if (!Found) {
  533. return(FALSE);
  534. }
  535. //
  536. // Now find the appropriate CPhysicalPartition in this disk.
  537. //
  538. pos = Disk->m_PartitionList.GetHeadPosition();
  539. while (pos) {
  540. Partition = Disk->m_PartitionList.GetNext(pos);
  541. if (Partition->m_FtPartitionInfo == FtPartition) {
  542. //
  543. // Found a match!
  544. //
  545. return(Partition);
  546. }
  547. }
  548. return(FALSE);
  549. }
  550. DWORD
  551. CDiskConfig::MakeSticky(
  552. IN CPhysicalDisk *Disk
  553. )
  554. {
  555. DWORD Status;
  556. Status = Disk->MakeSticky(&m_FTInfo);
  557. if (Status == ERROR_SUCCESS) {
  558. Status = m_FTInfo.CommitRegistryData();
  559. }
  560. return(Status);
  561. }
  562. DWORD
  563. CDiskConfig::MakeSticky(
  564. IN CFtSet *FtSet
  565. )
  566. {
  567. DWORD Status;
  568. Status = FtSet->MakeSticky();
  569. if (Status == ERROR_SUCCESS) {
  570. Status = m_FTInfo.CommitRegistryData();
  571. }
  572. return(Status);
  573. }
  574. BOOL
  575. CDiskConfig::OnSystemBus(
  576. IN CPhysicalDisk *Disk
  577. )
  578. {
  579. CPhysicalDisk *SystemDisk;
  580. if (m_SystemVolume == NULL) {
  581. return(FALSE);
  582. }
  583. SystemDisk = m_SystemVolume->m_Partition->m_PhysicalDisk;
  584. if (Disk == SystemDisk) {
  585. return(TRUE);
  586. }
  587. if (SystemDisk->ShareBus(Disk)) {
  588. return(TRUE);
  589. }
  590. return(FALSE);
  591. }
  592. BOOL
  593. CDiskConfig::OnSystemBus(
  594. IN CFtSet *FtSet
  595. )
  596. {
  597. POSITION pos = FtSet->m_Member.GetHeadPosition();
  598. CPhysicalPartition *Partition;
  599. while (pos) {
  600. Partition = FtSet->m_Member.GetNext(pos);
  601. if (OnSystemBus(Partition->m_PhysicalDisk)) {
  602. return(TRUE);
  603. }
  604. }
  605. return(FALSE);
  606. }
  607. //
  608. // Functions for the logical disk object
  609. //
  610. BOOL
  611. CLogicalDrive::Initialize(
  612. IN CPhysicalPartition *Partition
  613. )
  614. /*++
  615. Routine Description:
  616. Initializes a new logical disk object.
  617. Arguments:
  618. Partition - Supplies the physical partition.
  619. Return Value:
  620. --*/
  621. {
  622. CString DosVolume;
  623. WCHAR DriveLabel[32];
  624. WCHAR FsName[16];
  625. DWORD MaxLength;
  626. DWORD Flags;
  627. WCHAR Buff[128];
  628. DISK_PARTITION UNALIGNED *FtInfo;
  629. //
  630. // See if this drive has a "sticky" drive letter in the registry.
  631. //
  632. m_Partition = Partition;
  633. if (Partition->m_FtPartitionInfo != NULL) {
  634. FtInfo = Partition->m_FtPartitionInfo->m_PartitionInfo;
  635. } else {
  636. FtInfo = NULL;
  637. }
  638. if ((FtInfo) &&
  639. (FtInfo->AssignDriveLetter) &&
  640. (FtInfo->DriveLetter != 0))
  641. {
  642. m_IsSticky = TRUE;
  643. m_DriveLetter = (WCHAR)FtInfo->DriveLetter;
  644. } else {
  645. m_IsSticky = FALSE;
  646. //
  647. // There is no sticky drive letter for this device. Scan through the
  648. // Partition/Drive Letter map looking for a matching drive letter.
  649. //
  650. DWORD letter;
  651. for ( letter = 0; letter < 26; ++letter ) {
  652. if (DriveLetterMap[ letter ].DriveType == DRIVE_FIXED
  653. &&
  654. Partition->m_PhysicalDisk->m_DiskNumber == DriveLetterMap[ letter ].DeviceNumber.DeviceNumber
  655. &&
  656. Partition->m_Info.PartitionNumber == DriveLetterMap[ letter ].DeviceNumber.PartitionNumber)
  657. {
  658. break;
  659. }
  660. }
  661. if ( letter == 26 ) {
  662. //
  663. // There is no drive letter for this partition. Just ignore it.
  664. //
  665. return(FALSE);
  666. }
  667. m_DriveLetter = (WCHAR)(letter + L'A');
  668. }
  669. DosVolume = m_DriveLetter;
  670. DosVolume += L":\\";
  671. if (GetVolumeInformation(DosVolume,
  672. DriveLabel,
  673. sizeof(DriveLabel)/sizeof(WCHAR),
  674. NULL,
  675. &MaxLength,
  676. &Flags,
  677. FsName,
  678. sizeof(FsName)/sizeof(WCHAR))) {
  679. if ( CompareString( LOCALE_INVARIANT,
  680. NORM_IGNORECASE,
  681. FsName,
  682. -1,
  683. L"NTFS",
  684. -1 ) == CSTR_EQUAL ) {
  685. m_IsNTFS = TRUE;
  686. } else {
  687. m_IsNTFS = FALSE;
  688. }
  689. m_VolumeLabel = DriveLabel;
  690. (VOID) StringCchPrintf( Buff,
  691. RTL_NUMBER_OF(Buff),
  692. L"%c: (%ws)",
  693. m_DriveLetter,
  694. (LPCTSTR)m_VolumeLabel );
  695. } else {
  696. m_IsNTFS = TRUE; // Lie and say it is NTFS
  697. (VOID) StringCchPrintf( Buff,
  698. RTL_NUMBER_OF(Buff),
  699. L"%c: (RAW)",
  700. m_DriveLetter );
  701. }
  702. m_Identifier = Buff;
  703. m_Partition->m_PhysicalDisk->m_LogicalDriveList.AddTail(this);
  704. m_ContainerSet = NULL;
  705. return(TRUE);
  706. }
  707. BOOL
  708. CLogicalDrive::IsSCSI(
  709. VOID
  710. )
  711. /*++
  712. Routine Description:
  713. Returns whether or not a logical drive is SCSI. A logical
  714. drive is SCSI if all of its partitions are on SCSI drives.
  715. Arguments:
  716. None.
  717. Return Value:
  718. TRUE if the drive is entirely SCSI
  719. FALSE otherwise.
  720. --*/
  721. {
  722. return(m_Partition->m_PhysicalDisk->m_IsSCSI);
  723. }
  724. DWORD
  725. CLogicalDrive::MakeSticky(
  726. VOID
  727. )
  728. /*++
  729. Routine Description:
  730. Attempts to assign a sticky drive letter to the specified volume.
  731. Arguments:
  732. None.
  733. Return Value:
  734. ERROR_SUCCESS if the drive was made sticky.
  735. Win32 error code otherwise.
  736. --*/
  737. {
  738. m_Partition->m_FtPartitionInfo->MakeSticky((UCHAR)m_DriveLetter);
  739. m_IsSticky = TRUE;
  740. return(ERROR_SUCCESS);
  741. }
  742. BOOL
  743. CLogicalDrive::ShareBus(
  744. IN CLogicalDrive *OtherDrive
  745. )
  746. /*++
  747. Routine Description:
  748. Returns whether or not this drive shares a bus with another
  749. drive.
  750. Arguments:
  751. OtherDrive - Supplies the other drive
  752. Return Value:
  753. TRUE - if the drives have any of their partitions on the same bus.
  754. FALSE - if the drives do not hae any of their partitiosn on the same bus.
  755. --*/
  756. {
  757. PSCSI_ADDRESS MyAddress;
  758. PSCSI_ADDRESS OtherAddress;
  759. MyAddress = &m_Partition->m_PhysicalDisk->m_ScsiAddress;
  760. OtherAddress = &OtherDrive->m_Partition->m_PhysicalDisk->m_ScsiAddress;
  761. if ( (MyAddress->PortNumber == OtherAddress->PortNumber) &&
  762. (MyAddress->PathId == OtherAddress->PathId) ) {
  763. return(TRUE);
  764. } else {
  765. return(FALSE);
  766. }
  767. }
  768. //
  769. // Functions for the physical disk object
  770. //
  771. DWORD
  772. CPhysicalDisk::Initialize(
  773. CFtInfo *FtInfo,
  774. IN LPWSTR DeviceName
  775. )
  776. /*++
  777. Routine Description:
  778. Initializes a physical disk object
  779. Arguments:
  780. FtInfo - pointer to object's FtInfo data
  781. DeviceName - pointer to string of device to initialize
  782. Return Value:
  783. ERROR_SUCCESS if successful
  784. --*/
  785. {
  786. HKEY DiskKey;
  787. WCHAR Buff[100];
  788. DWORD BuffSize;
  789. DWORD dwType;
  790. HANDLE hDisk;
  791. DWORD Status;
  792. DWORD dwSize;
  793. PDRIVE_LAYOUT_INFORMATION DriveLayout;
  794. WCHAR KeyName[256];
  795. DISK_GEOMETRY Geometry;
  796. STORAGE_DEVICE_NUMBER deviceNumber;
  797. //
  798. // Open the physical drive and start probing it to find disk number and
  799. // other attributes
  800. //
  801. hDisk = GetPhysicalDriveHandle(GENERIC_READ, DeviceName);
  802. if (hDisk == NULL) {
  803. return(GetLastError());
  804. }
  805. if (!DeviceIoControl(hDisk,
  806. IOCTL_STORAGE_GET_DEVICE_NUMBER,
  807. NULL,
  808. 0,
  809. &deviceNumber,
  810. sizeof(deviceNumber),
  811. &dwSize,
  812. NULL))
  813. {
  814. Status = GetLastError();
  815. DISKLOG(("get device number failed for drive %ws. status = %u\n",
  816. DeviceName,
  817. Status));
  818. return Status;
  819. } else {
  820. m_DiskNumber = deviceNumber.DeviceNumber;
  821. }
  822. if (!DeviceIoControl(hDisk,
  823. IOCTL_SCSI_GET_ADDRESS,
  824. NULL,
  825. 0,
  826. &m_ScsiAddress,
  827. sizeof(SCSI_ADDRESS),
  828. &dwSize,
  829. NULL))
  830. {
  831. //
  832. // If the IOCTL was invalid, the drive is not a SCSI drive.
  833. //
  834. DISKLOG(("IOCTL_SCSI_GET_ADDRESS failed for drive %u. status = %u\n",
  835. m_DiskNumber,
  836. GetLastError()));
  837. m_IsSCSI = FALSE;
  838. } else {
  839. //
  840. // [THINKTHINK] John Vert (jvert) 10/12/1996
  841. // Need some way to make sure this is really SCSI and
  842. // not ATAPI?
  843. //
  844. m_IsSCSI = TRUE;
  845. //
  846. // Get the description of the disk from the registry.
  847. //
  848. (VOID) StringCchPrintf( KeyName,
  849. RTL_NUMBER_OF(KeyName),
  850. TEXT("HARDWARE\\DeviceMap\\Scsi\\Scsi Port %d\\Scsi Bus %d\\Target Id %d\\Logical Unit Id %d"),
  851. m_ScsiAddress.PortNumber,
  852. m_ScsiAddress.PathId,
  853. m_ScsiAddress.TargetId,
  854. m_ScsiAddress.Lun );
  855. Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  856. KeyName,
  857. 0,
  858. KEY_READ,
  859. &DiskKey);
  860. if (Status != ERROR_SUCCESS) {
  861. DISKERR(IDS_ERR_DRIVE_CONFIG, Status);
  862. // [REENGINEER] Need to handle this failure //
  863. }
  864. BuffSize = sizeof(Buff);
  865. Status = RegQueryValueExW(DiskKey,
  866. L"Identifier",
  867. NULL,
  868. &dwType,
  869. (LPBYTE)Buff,
  870. &BuffSize);
  871. RegCloseKey(DiskKey);
  872. if (Status != ERROR_SUCCESS) {
  873. DISKERR(IDS_ERR_DRIVE_CONFIG, Status);
  874. // [REENGINEER] Need to handle this failure //
  875. }
  876. m_Identifier = Buff;
  877. }
  878. //
  879. // Get the drive layout.
  880. //
  881. m_PartitionCount = 0;
  882. if (!ClRtlGetDriveLayoutTable( hDisk, &DriveLayout, NULL )) {
  883. DISKLOG(("Couldn't get partition table for drive %u. status = %u\n",
  884. m_DiskNumber,
  885. GetLastError()));
  886. m_Signature = 0;
  887. m_FtInfo = NULL;
  888. } else {
  889. m_Signature = DriveLayout->Signature;
  890. //
  891. // Get the FT information
  892. //
  893. m_FtInfo = FtInfo->FindDiskInfo(m_Signature);
  894. //
  895. // build the partition objects.
  896. //
  897. DWORD i;
  898. CPhysicalPartition *Partition;
  899. for (i=0; i<DriveLayout->PartitionCount; i++) {
  900. if (DriveLayout->PartitionEntry[i].RecognizedPartition) {
  901. m_PartitionCount++;
  902. Partition = new CPhysicalPartition(this, &DriveLayout->PartitionEntry[i]);
  903. if (Partition != NULL) {
  904. //
  905. // If we have FT information for the disk, make sure we
  906. // found it for each partition. If we didn't find it for
  907. // the partition, the registry is stale and doesn't match
  908. // the drive layout.
  909. //
  910. if ((m_FtInfo != NULL) &&
  911. (Partition->m_FtPartitionInfo == NULL)) {
  912. //
  913. // Stale registry info. Make up some new stuff.
  914. //
  915. CFtInfoPartition *FtInfoPartition;
  916. FtInfoPartition = new CFtInfoPartition(m_FtInfo, Partition);
  917. if (FtInfoPartition == NULL) {
  918. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  919. LocalFree( DriveLayout );
  920. return ERROR_NOT_ENOUGH_MEMORY;
  921. }
  922. Partition->m_FtPartitionInfo = FtInfoPartition;
  923. }
  924. m_PartitionList.AddTail(Partition);
  925. } else {
  926. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  927. LocalFree( DriveLayout );
  928. return ERROR_NOT_ENOUGH_MEMORY;
  929. }
  930. }
  931. }
  932. LocalFree( DriveLayout );
  933. }
  934. //
  935. // Check whether it is removable or not.
  936. //
  937. if (!DeviceIoControl(hDisk,
  938. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  939. NULL,
  940. 0,
  941. &Geometry,
  942. sizeof(Geometry),
  943. &dwSize,
  944. NULL)) {
  945. Status = GetLastError();
  946. if (Status == ERROR_NOT_READY) {
  947. //
  948. // Guess this must be removable!
  949. //
  950. m_IsRemovable = TRUE;
  951. } else {
  952. //
  953. // [FUTURE] John Vert (jvert) 10/18/1996
  954. // Remove this when we require the new SCSI driver.
  955. // The disk is reserved on the other system, so we can't
  956. // get the geometry.
  957. //
  958. m_IsRemovable = FALSE;
  959. }
  960. } else {
  961. if (Geometry.MediaType == RemovableMedia) {
  962. m_IsRemovable = TRUE;
  963. } else {
  964. m_IsRemovable = FALSE;
  965. }
  966. }
  967. CloseHandle(hDisk);
  968. return(ERROR_SUCCESS);
  969. }
  970. HANDLE
  971. CPhysicalDisk::GetPhysicalDriveHandle(DWORD Access)
  972. {
  973. WCHAR Buff[100];
  974. HANDLE hDisk;
  975. (VOID) StringCchPrintf( Buff,
  976. RTL_NUMBER_OF(Buff),
  977. TEXT("\\\\.\\PhysicalDrive%d"),
  978. m_DiskNumber );
  979. hDisk = CreateFile(Buff,
  980. Access,
  981. FILE_SHARE_READ | FILE_SHARE_WRITE,
  982. NULL,
  983. OPEN_EXISTING,
  984. FILE_ATTRIBUTE_NORMAL,
  985. NULL);
  986. if (hDisk == INVALID_HANDLE_VALUE) {
  987. DISKLOG(("Failed to get handle for drive %u. status = %u\n",
  988. m_DiskNumber,
  989. GetLastError()));
  990. return(NULL);
  991. }
  992. return(hDisk);
  993. }
  994. HANDLE
  995. CPhysicalDisk::GetPhysicalDriveHandle(DWORD Access, LPWSTR DeviceName)
  996. {
  997. HANDLE hDisk;
  998. hDisk = CreateFile(DeviceName,
  999. Access,
  1000. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1001. NULL,
  1002. OPEN_EXISTING,
  1003. FILE_ATTRIBUTE_NORMAL,
  1004. NULL);
  1005. if (hDisk == INVALID_HANDLE_VALUE) {
  1006. DISKLOG(("Failed to get handle for drive %u. status = %u\n",
  1007. m_DiskNumber,
  1008. GetLastError()));
  1009. return(NULL);
  1010. }
  1011. return(hDisk);
  1012. }
  1013. BOOL
  1014. CPhysicalDisk::ShareBus(
  1015. IN CPhysicalDisk *OtherDisk
  1016. )
  1017. /*++
  1018. Routine Description:
  1019. Returns whether or not this disk shares a bus with another
  1020. disk.
  1021. Arguments:
  1022. OtherDisk - Supplies the other disk
  1023. Return Value:
  1024. TRUE - if the disks share the same bus.
  1025. FALSE - if the disks do not share the same bus.
  1026. --*/
  1027. {
  1028. //
  1029. // Make sure they are either both SCSI or both not SCSI.
  1030. //
  1031. if (m_IsSCSI != OtherDisk->m_IsSCSI) {
  1032. return(FALSE);
  1033. }
  1034. if ( (m_ScsiAddress.PortNumber == OtherDisk->m_ScsiAddress.PortNumber) &&
  1035. (m_ScsiAddress.PathId == OtherDisk->m_ScsiAddress.PathId) ) {
  1036. return(TRUE);
  1037. } else {
  1038. return(FALSE);
  1039. }
  1040. }
  1041. BOOL
  1042. CPhysicalDisk::IsSticky(
  1043. VOID
  1044. )
  1045. /*++
  1046. Routine Description:
  1047. Returns whether or not this disk has a signature and all the partitions
  1048. on it have sticky drive letters.
  1049. Arguments:
  1050. None.
  1051. Return Value:
  1052. TRUE - if the disk is sticky
  1053. FALSE - if the disk is not sticky and needs to have some FT information
  1054. applied before it is suitable for clustering.
  1055. --*/
  1056. {
  1057. //
  1058. // If the signature is 0, return FALSE.
  1059. //
  1060. if ((m_FtInfo == NULL) ||
  1061. (m_FtInfo->m_Signature == 0)) {
  1062. return(FALSE);
  1063. }
  1064. //
  1065. // Check each volume to see if it has a sticky drive letter.
  1066. //
  1067. CLogicalDrive *Drive;
  1068. POSITION pos = m_LogicalDriveList.GetHeadPosition();
  1069. while (pos) {
  1070. Drive = m_LogicalDriveList.GetNext(pos);
  1071. if (!Drive->m_IsSticky) {
  1072. return(FALSE);
  1073. }
  1074. }
  1075. return(TRUE);
  1076. }
  1077. BOOL
  1078. CPhysicalDisk::IsNTFS(
  1079. VOID
  1080. )
  1081. /*++
  1082. Routine Description:
  1083. Returns whether or not all the partitions on this drive are NTFS.
  1084. Arguments:
  1085. None.
  1086. Return Value:
  1087. TRUE - if the disk is entirely NTFS
  1088. FALSE - if the disk is not entirely NTFS
  1089. --*/
  1090. {
  1091. //
  1092. // if no logical volumes were created for this drive, then it must not
  1093. // have any NTFS partitions
  1094. //
  1095. if ( m_LogicalDriveList.IsEmpty()) {
  1096. return FALSE;
  1097. }
  1098. //
  1099. // Check each volume to see if it has a sticky drive letter.
  1100. //
  1101. CLogicalDrive *Drive;
  1102. POSITION pos = m_LogicalDriveList.GetHeadPosition();
  1103. while (pos) {
  1104. Drive = m_LogicalDriveList.GetNext(pos);
  1105. if (!Drive->m_IsNTFS) {
  1106. return(FALSE);
  1107. }
  1108. }
  1109. return(TRUE);
  1110. }
  1111. DWORD
  1112. CPhysicalDisk::MakeSticky(
  1113. CFtInfo *FtInfo
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. Attempts to make a disk and all of its partitions have
  1118. sticky drive letters.
  1119. Arguments:
  1120. FtInfo - Supplies the FT information that will be updated.
  1121. Return Value:
  1122. ERROR_SUCCESS if successful
  1123. Win32 error code otherwise
  1124. --*/
  1125. {
  1126. DWORD Status;
  1127. if (m_Signature == 0) {
  1128. //
  1129. // Better not be any information in the registry for a disk
  1130. // with no signature.
  1131. //
  1132. if (m_FtInfo != NULL) {
  1133. DISKERR(IDS_GENERAL_FAILURE, ERROR_FILE_NOT_FOUND);
  1134. }
  1135. //
  1136. // There is no signature on this drive. Think one up and
  1137. // stamp the drive.
  1138. //
  1139. HANDLE hDisk = GetPhysicalDriveHandle(GENERIC_READ | GENERIC_WRITE);
  1140. PDRIVE_LAYOUT_INFORMATION DriveLayout;
  1141. DWORD dwSize;
  1142. DWORD NewSignature;
  1143. FILETIME CurrentTime;
  1144. BOOL success;
  1145. if (hDisk == NULL) {
  1146. return(GetLastError());
  1147. }
  1148. //
  1149. // Get the current drive layout, change the signature field, and
  1150. // set the new drive layout. The new drive layout will be identical
  1151. // except for the new signature.
  1152. //
  1153. if (!ClRtlGetDriveLayoutTable( hDisk, &DriveLayout, &dwSize )) {
  1154. Status = GetLastError();
  1155. DISKERR(IDS_GENERAL_FAILURE, Status);
  1156. CloseHandle(hDisk);
  1157. return(Status);
  1158. }
  1159. GetSystemTimeAsFileTime(&CurrentTime);
  1160. NewSignature = CurrentTime.dwLowDateTime;
  1161. //
  1162. // Make sure this signature is unique.
  1163. //
  1164. while (FtInfo->FindDiskInfo(NewSignature) != NULL) {
  1165. NewSignature++;
  1166. }
  1167. //
  1168. // Finally set the new signature information.
  1169. //
  1170. DriveLayout->Signature = NewSignature;
  1171. success = DeviceIoControl(hDisk,
  1172. IOCTL_DISK_SET_DRIVE_LAYOUT,
  1173. DriveLayout,
  1174. dwSize,
  1175. NULL,
  1176. 0,
  1177. &dwSize,
  1178. NULL);
  1179. LocalFree( DriveLayout );
  1180. if ( !success ) {
  1181. Status = GetLastError();
  1182. DISKERR(IDS_GENERAL_FAILURE, Status);
  1183. CloseHandle(hDisk);
  1184. return(Status);
  1185. }
  1186. m_Signature = NewSignature;
  1187. }
  1188. if (m_FtInfo == NULL) {
  1189. //
  1190. // There is no existing FT information for this drive.
  1191. // Create some FT information based on the drive.
  1192. //
  1193. m_FtInfo = new CFtInfoDisk(this);
  1194. if (m_FtInfo == NULL) {
  1195. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  1196. return ERROR_NOT_ENOUGH_MEMORY;
  1197. }
  1198. FtInfo->SetDiskInfo(m_FtInfo);
  1199. //
  1200. // Go through all our partitions and set their FT info.
  1201. //
  1202. POSITION pos = m_PartitionList.GetHeadPosition();
  1203. CPhysicalPartition *Partition;
  1204. while (pos) {
  1205. Partition = m_PartitionList.GetNext(pos);
  1206. Partition->m_FtPartitionInfo = m_FtInfo->GetPartition(Partition->m_Info.StartingOffset,
  1207. Partition->m_Info.PartitionLength);
  1208. }
  1209. }
  1210. //
  1211. // Go through all the volumes on this drive and make each one
  1212. // sticky.
  1213. //
  1214. CLogicalDrive *Drive;
  1215. POSITION pos = m_LogicalDriveList.GetHeadPosition();
  1216. while (pos) {
  1217. Drive = m_LogicalDriveList.GetNext(pos);
  1218. Status = Drive->MakeSticky();
  1219. if (Status != ERROR_SUCCESS) {
  1220. return(Status);
  1221. }
  1222. }
  1223. return(ERROR_SUCCESS);
  1224. }
  1225. //
  1226. // Functions for the physical disk partition
  1227. //
  1228. CPhysicalPartition::CPhysicalPartition(
  1229. CPhysicalDisk *Disk,
  1230. PPARTITION_INFORMATION Info
  1231. )
  1232. {
  1233. m_PhysicalDisk = Disk;
  1234. m_Info = *Info;
  1235. if (Disk->m_FtInfo) {
  1236. m_FtPartitionInfo = Disk->m_FtInfo->GetPartition(m_Info.StartingOffset,
  1237. m_Info.PartitionLength);
  1238. } else {
  1239. m_FtPartitionInfo = NULL;
  1240. }
  1241. }
  1242. //
  1243. // Functions for the FT set object
  1244. //
  1245. BOOL
  1246. CFtSet::Initialize(
  1247. CDiskConfig *Config,
  1248. CFtInfoFtSet *FtInfo
  1249. )
  1250. {
  1251. DWORD MemberCount;
  1252. DWORD FoundCount=0;
  1253. DWORD Index;
  1254. CFtInfoPartition *Partition;
  1255. CPhysicalPartition *FoundPartition;
  1256. m_FtInfo = FtInfo;
  1257. //
  1258. // Find the CPhysicalPartition that corresponds to each member of the
  1259. // FT set.
  1260. //
  1261. MemberCount = FtInfo->GetMemberCount();
  1262. for (Index=0; Index<MemberCount; Index++) {
  1263. Partition = FtInfo->GetMemberByIndex(Index);
  1264. if (Partition == NULL) {
  1265. break;
  1266. }
  1267. FoundPartition = Config->FindPartition(Partition);
  1268. if (FoundPartition != NULL) {
  1269. ++FoundCount;
  1270. m_Member.AddTail(FoundPartition);
  1271. }
  1272. }
  1273. //
  1274. // If we did not find all the required members, fail.
  1275. //
  1276. switch (FtInfo->GetType()) {
  1277. case Stripe:
  1278. case VolumeSet:
  1279. if (FoundCount != MemberCount) {
  1280. return(FALSE);
  1281. }
  1282. break;
  1283. case Mirror:
  1284. if (FoundCount == 0) {
  1285. return(FALSE);
  1286. }
  1287. break;
  1288. case StripeWithParity:
  1289. if (FoundCount < (MemberCount-1)) {
  1290. return(FALSE);
  1291. }
  1292. break;
  1293. default:
  1294. //
  1295. // Don't know what the heck this is supposed to be.
  1296. // Ignore it.
  1297. //
  1298. return(FALSE);
  1299. }
  1300. //
  1301. // If there are any other partitions on any of the drives, create logical
  1302. // volumes for them.
  1303. //
  1304. POSITION MemberPos;
  1305. POSITION PartitionPos;
  1306. CPhysicalPartition *PhysPartition;
  1307. CPhysicalDisk *Disk;
  1308. MemberPos = m_Member.GetHeadPosition();
  1309. while (MemberPos) {
  1310. Disk = m_Member.GetNext(MemberPos)->m_PhysicalDisk;
  1311. PartitionPos = Disk->m_PartitionList.GetHeadPosition();
  1312. while (PartitionPos) {
  1313. PhysPartition = Disk->m_PartitionList.GetNext(PartitionPos);
  1314. if ((!(PhysPartition->m_Info.PartitionType & PARTITION_NTFT)) &&
  1315. (IsRecognizedPartition(PhysPartition->m_Info.PartitionType))) {
  1316. CLogicalDrive *Vol = new CLogicalDrive;
  1317. if (Vol == NULL) {
  1318. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  1319. return FALSE;
  1320. }
  1321. if (Vol->Initialize(PhysPartition)) {
  1322. //
  1323. // Add this volume to our list.
  1324. //
  1325. m_OtherVolumes.AddTail(Vol);
  1326. Vol->m_ContainerSet = this;
  1327. //
  1328. // Update the disk config.
  1329. //
  1330. Config->m_LogicalDrives[Vol->m_DriveLetter] = Vol;
  1331. } else {
  1332. delete(Vol);
  1333. }
  1334. }
  1335. }
  1336. }
  1337. if (Volume.Initialize(m_Member.GetHead())) {
  1338. Volume.m_ContainerSet = this;
  1339. return(TRUE);
  1340. } else {
  1341. return(FALSE);
  1342. }
  1343. }
  1344. BOOL
  1345. CFtSet::IsSticky()
  1346. {
  1347. //
  1348. // FT sets are, by definition, sticky. Make sure any other volumes on the
  1349. // same drive are sticky as well.
  1350. //
  1351. POSITION pos = m_OtherVolumes.GetHeadPosition();
  1352. CLogicalDrive *Volume;
  1353. while (pos) {
  1354. Volume = m_OtherVolumes.GetNext(pos);
  1355. if (!Volume->m_IsSticky) {
  1356. return(FALSE);
  1357. }
  1358. }
  1359. return(TRUE);
  1360. }
  1361. DWORD
  1362. CFtSet::MakeSticky()
  1363. {
  1364. DWORD Status;
  1365. //
  1366. // FT sets are, by definition, sticky. Make sure any other volumes on the
  1367. // same drive are sticky as well.
  1368. //
  1369. POSITION pos = m_OtherVolumes.GetHeadPosition();
  1370. CLogicalDrive *Volume;
  1371. while (pos) {
  1372. Volume = m_OtherVolumes.GetNext(pos);
  1373. Status = Volume->MakeSticky();
  1374. if (Status != ERROR_SUCCESS) {
  1375. return(Status);
  1376. }
  1377. }
  1378. return(ERROR_SUCCESS);
  1379. }
  1380. BOOL
  1381. CFtSet::IsNTFS()
  1382. {
  1383. if (!Volume.m_IsNTFS) {
  1384. return(FALSE);
  1385. }
  1386. //
  1387. // Check the other volumes to make sure they are NTFS as well.
  1388. //
  1389. POSITION pos = m_OtherVolumes.GetHeadPosition();
  1390. CLogicalDrive *Volume;
  1391. while (pos) {
  1392. Volume = m_OtherVolumes.GetNext(pos);
  1393. if (!Volume->m_IsNTFS) {
  1394. return(FALSE);
  1395. }
  1396. }
  1397. return(TRUE);
  1398. }
  1399. BOOL
  1400. CFtSet::IsSCSI()
  1401. {
  1402. //
  1403. // Check the other volumes to make sure they are NTFS as well.
  1404. //
  1405. POSITION pos = m_Member.GetHeadPosition();
  1406. CPhysicalPartition *Partition;
  1407. while (pos) {
  1408. Partition = m_Member.GetNext(pos);
  1409. if (!Partition->m_PhysicalDisk->m_IsSCSI) {
  1410. return(FALSE);
  1411. }
  1412. }
  1413. return(TRUE);
  1414. }
  1415. //
  1416. // Functions for the FT disk information
  1417. //
  1418. CFtInfo::CFtInfo()
  1419. {
  1420. HKEY hKey;
  1421. LONG Status;
  1422. //
  1423. // for NT5, the DISK info key is no longer maintained by the disk
  1424. // system. Clusters still needs a centrally located key such that
  1425. // the other members of the cluster can query for the disk config
  1426. // of the sponsor's node.
  1427. //
  1428. Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  1429. L"System\\Disk",
  1430. 0,
  1431. KEY_READ | KEY_WRITE,
  1432. &hKey);
  1433. if (Status == ERROR_SUCCESS) {
  1434. Initialize(hKey, _T("Information"));
  1435. RegCloseKey(hKey);
  1436. } else {
  1437. Initialize();
  1438. }
  1439. }
  1440. CFtInfo::CFtInfo(
  1441. HKEY hKey,
  1442. LPWSTR lpszValueName
  1443. )
  1444. {
  1445. Initialize(hKey, lpszValueName);
  1446. }
  1447. CFtInfo::CFtInfo(
  1448. PDISK_CONFIG_HEADER Header
  1449. )
  1450. {
  1451. DWORD Length;
  1452. Length = Header->FtInformationOffset +
  1453. Header->FtInformationSize;
  1454. Initialize(Header, Length);
  1455. }
  1456. CFtInfo::CFtInfo(
  1457. CFtInfoFtSet *FtSet
  1458. )
  1459. /*++
  1460. Routine Description:
  1461. Constructor for generating a CFtInfo that contains only a
  1462. single FT set.
  1463. Arguments:
  1464. FtSet - Supplies the FT set
  1465. Return Value:
  1466. None
  1467. --*/
  1468. {
  1469. //
  1470. // Initialize an empty FT information.
  1471. //
  1472. Initialize();
  1473. //
  1474. // Add the FT set
  1475. //
  1476. if (FtSet != NULL) {
  1477. AddFtSetInfo(FtSet);
  1478. }
  1479. }
  1480. VOID
  1481. CFtInfo::Initialize(
  1482. HKEY hKey,
  1483. LPWSTR lpszValueName
  1484. )
  1485. {
  1486. PDISK_CONFIG_HEADER regHeader;
  1487. DWORD Length;
  1488. if (GetRegValue(hKey,
  1489. lpszValueName,
  1490. (LPBYTE *)&regHeader,
  1491. &Length)) {
  1492. Initialize(regHeader, Length);
  1493. LocalFree(regHeader);
  1494. } else {
  1495. DWORD Status = GetLastError();
  1496. if (Status == ERROR_FILE_NOT_FOUND) {
  1497. //
  1498. // There is no FT information on this machine.
  1499. //
  1500. Initialize();
  1501. } else {
  1502. DISKERR(IDS_GENERAL_FAILURE, Status);
  1503. }
  1504. }
  1505. }
  1506. VOID
  1507. CFtInfo::Initialize(
  1508. PDISK_CONFIG_HEADER Header,
  1509. DWORD Length
  1510. )
  1511. {
  1512. DWORD i;
  1513. DISK_REGISTRY UNALIGNED * diskRegistry;
  1514. DISK_DESCRIPTION UNALIGNED * diskDescription;
  1515. CFtInfoDisk *DiskInfo;
  1516. m_buffer = new BYTE[Length];
  1517. if (m_buffer == NULL) {
  1518. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  1519. return; // [REENGINEER] we avoided an AV, but the caller wouldn't know
  1520. }
  1521. CopyMemory(m_buffer, Header, Length);
  1522. m_bufferLength = Length;
  1523. //
  1524. // Iterate through all the disks and add each one to our list.
  1525. //
  1526. diskRegistry = (DISK_REGISTRY UNALIGNED *)
  1527. (m_buffer + ((PDISK_CONFIG_HEADER)m_buffer)->DiskInformationOffset);
  1528. diskDescription = &diskRegistry->Disks[0];
  1529. for (i = 0; i < diskRegistry->NumberOfDisks; i++) {
  1530. DiskInfo = new CFtInfoDisk(diskDescription);
  1531. if (DiskInfo) {
  1532. //
  1533. // Add this disk information to our list.
  1534. //
  1535. DiskInfo->SetOffset((DWORD)((PUCHAR)diskDescription - m_buffer));
  1536. m_DiskInfo.AddTail(DiskInfo);
  1537. } else {
  1538. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  1539. // [REENGINEER] do we need to exit here?
  1540. }
  1541. //
  1542. // Look at the next disk
  1543. //
  1544. diskDescription = (DISK_DESCRIPTION UNALIGNED *)
  1545. &diskDescription->Partitions[diskDescription->NumberOfPartitions];
  1546. }
  1547. if (((PDISK_CONFIG_HEADER)m_buffer)->FtInformationSize != 0) {
  1548. //
  1549. // Iterate through all the FT sets and add each one to our list.
  1550. //
  1551. PFT_REGISTRY ftRegistry;
  1552. PFT_DESCRIPTION ftDescription;
  1553. CFtInfoFtSet *FtSetInfo;
  1554. ftRegistry = (PFT_REGISTRY)
  1555. (m_buffer + ((PDISK_CONFIG_HEADER)m_buffer)->FtInformationOffset);
  1556. ftDescription = &ftRegistry->FtDescription[0];
  1557. for (i=0; i < ftRegistry->NumberOfComponents; i++) {
  1558. FtSetInfo = new CFtInfoFtSet;
  1559. if (FtSetInfo) {
  1560. if (!FtSetInfo->Initialize(this, ftDescription)) {
  1561. delete FtSetInfo;
  1562. } else {
  1563. //
  1564. // Add this FT set information to the list.
  1565. //
  1566. m_FtSetInfo.AddTail(FtSetInfo);
  1567. }
  1568. } else {
  1569. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  1570. // [REENGINEER] do we need to exit here?
  1571. }
  1572. ftDescription = (PFT_DESCRIPTION)(&ftDescription->FtMemberDescription[ftDescription->NumberOfMembers]);
  1573. }
  1574. }
  1575. }
  1576. VOID
  1577. CFtInfo::Initialize(VOID)
  1578. {
  1579. PDISK_CONFIG_HEADER regHeader;
  1580. DISK_REGISTRY UNALIGNED * diskRegistry;
  1581. //
  1582. // There is no FT information on this machine.
  1583. //
  1584. m_bufferLength = sizeof(DISK_CONFIG_HEADER) + sizeof(DISK_REGISTRY);
  1585. m_buffer = new BYTE[m_bufferLength];
  1586. if (m_buffer == NULL) {
  1587. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  1588. return; // [REENGINEER], we avoided an AV, but the caller wouldn't know
  1589. }
  1590. regHeader = (PDISK_CONFIG_HEADER)m_buffer;
  1591. regHeader->Version = DISK_INFORMATION_VERSION;
  1592. regHeader->CheckSum = 0;
  1593. regHeader->DirtyShutdown = FALSE;
  1594. regHeader->DiskInformationOffset = sizeof(DISK_CONFIG_HEADER);
  1595. regHeader->DiskInformationSize = sizeof(DISK_REGISTRY)-sizeof(DISK_DESCRIPTION);
  1596. regHeader->FtInformationOffset = regHeader->DiskInformationOffset +
  1597. regHeader->DiskInformationSize;
  1598. regHeader->FtInformationSize = 0;
  1599. regHeader->FtStripeWidth = 0;
  1600. regHeader->FtPoolSize = 0;
  1601. regHeader->NameOffset = 0;
  1602. regHeader->NameSize = 0;
  1603. diskRegistry = (DISK_REGISTRY UNALIGNED *)
  1604. ((PUCHAR)regHeader + regHeader->DiskInformationOffset);
  1605. diskRegistry->NumberOfDisks = 0;
  1606. diskRegistry->ReservedShort = 0;
  1607. }
  1608. CFtInfo::~CFtInfo()
  1609. {
  1610. CFtInfoDisk *DiskInfo;
  1611. CFtInfoFtSet *FtSetInfo;
  1612. POSITION pos = m_DiskInfo.GetHeadPosition();
  1613. while (pos) {
  1614. DiskInfo = m_DiskInfo.GetNext(pos);
  1615. delete(DiskInfo);
  1616. }
  1617. pos = m_FtSetInfo.GetHeadPosition();
  1618. while (pos) {
  1619. FtSetInfo = m_FtSetInfo.GetNext(pos);
  1620. delete FtSetInfo;
  1621. }
  1622. delete [] m_buffer;
  1623. }
  1624. DWORD
  1625. CFtInfo::CommitRegistryData()
  1626. {
  1627. HKEY hKey;
  1628. PDISK_CONFIG_HEADER Buffer;
  1629. DWORD Size;
  1630. DWORD Status = ERROR_SUCCESS;
  1631. Status = RegCreateKeyW(HKEY_LOCAL_MACHINE, L"System\\Disk", &hKey);
  1632. if (Status != ERROR_SUCCESS) {
  1633. DISKERR(IDS_REGISTRY_FAILURE, Status);
  1634. return Status;
  1635. }
  1636. Size = GetSize();
  1637. Buffer = (PDISK_CONFIG_HEADER)LocalAlloc(LMEM_FIXED, Size);
  1638. if (Buffer == NULL) {
  1639. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  1640. Status = ERROR_NOT_ENOUGH_MEMORY;
  1641. } else {
  1642. GetData(Buffer);
  1643. Status = RegSetValueExW(hKey,
  1644. L"Information",
  1645. 0,
  1646. REG_BINARY,
  1647. (PBYTE)Buffer,
  1648. Size);
  1649. if (Status != ERROR_SUCCESS) {
  1650. DISKERR(IDS_REGISTRY_FAILURE, Status);
  1651. }
  1652. LocalFree(Buffer);
  1653. }
  1654. RegCloseKey(hKey);
  1655. return(Status);
  1656. }
  1657. VOID
  1658. CFtInfo::SetDiskInfo(
  1659. CFtInfoDisk *NewDisk
  1660. )
  1661. {
  1662. CFtInfoDisk *OldDisk;
  1663. //
  1664. // See if we already have disk information for this signature
  1665. //
  1666. OldDisk = FindDiskInfo(NewDisk->m_Signature);
  1667. if (OldDisk == NULL) {
  1668. DISKLOG(("CFtInfo::SetDiskInfo adding new disk information for %08X\n",NewDisk->m_Signature));
  1669. //
  1670. // Just add the new disk to our list.
  1671. //
  1672. m_DiskInfo.AddTail(NewDisk);
  1673. } else {
  1674. //
  1675. // We already have some disk information. If they are the same,
  1676. // don't do anything.
  1677. //
  1678. if (*OldDisk == *NewDisk) {
  1679. DISKLOG(("CFtInfo::SetDiskInfo found identical disk information for %08X\n",OldDisk->m_Signature));
  1680. delete (NewDisk);
  1681. return;
  1682. }
  1683. //
  1684. // We need to replace the old information with the new information.
  1685. //
  1686. POSITION pos = m_DiskInfo.Find(OldDisk);
  1687. if (pos == NULL) {
  1688. DISKLOG(("CFtInfo::SetDiskInfo did not find OldDisk %08X\n",OldDisk->m_Signature));
  1689. DISKERR(IDS_GENERAL_FAILURE, ERROR_FILE_NOT_FOUND);
  1690. m_DiskInfo.AddTail(NewDisk);
  1691. } else {
  1692. m_DiskInfo.SetAt(pos, NewDisk);
  1693. delete(OldDisk);
  1694. }
  1695. }
  1696. }
  1697. CFtInfoDisk *
  1698. CFtInfo::FindDiskInfo(
  1699. IN DWORD Signature
  1700. )
  1701. {
  1702. CFtInfoDisk *RetInfo;
  1703. POSITION pos = m_DiskInfo.GetHeadPosition();
  1704. while (pos) {
  1705. RetInfo = m_DiskInfo.GetNext(pos);
  1706. if (RetInfo->m_Signature == Signature) {
  1707. return(RetInfo);
  1708. }
  1709. }
  1710. return(NULL);
  1711. }
  1712. CFtInfoDisk *
  1713. CFtInfo::EnumDiskInfo(
  1714. IN DWORD Index
  1715. )
  1716. {
  1717. DWORD i=0;
  1718. CFtInfoDisk *RetInfo;
  1719. POSITION pos = m_DiskInfo.GetHeadPosition();
  1720. while (pos) {
  1721. RetInfo = m_DiskInfo.GetNext(pos);
  1722. if (Index == i) {
  1723. return(RetInfo);
  1724. }
  1725. ++i;
  1726. }
  1727. return(NULL);
  1728. }
  1729. BOOL
  1730. CFtInfo::DeleteDiskInfo(
  1731. IN DWORD Signature
  1732. )
  1733. {
  1734. CFtInfoDisk *Info = FindDiskInfo(Signature);
  1735. CFtInfoFtSet *OldFtSet=NULL;
  1736. if (Info == NULL) {
  1737. DISKLOG(("CFtInfo::DeleteDiskInfo: Disk with signature %08X was not found\n",Signature));
  1738. return(FALSE);
  1739. }
  1740. //
  1741. // Remove any FT set containing this signature.
  1742. //
  1743. OldFtSet = FindFtSetInfo(Info->m_Signature);
  1744. if (OldFtSet != NULL) {
  1745. DeleteFtSetInfo(OldFtSet);
  1746. }
  1747. POSITION pos = m_DiskInfo.Find(Info);
  1748. if (pos == NULL) {
  1749. DISKLOG(("CFtInfo::DeleteDiskInfo did not find Info %08X\n",Signature));
  1750. DISKERR(IDS_GENERAL_FAILURE, ERROR_FILE_NOT_FOUND);
  1751. return(FALSE);
  1752. } else {
  1753. m_DiskInfo.RemoveAt(pos);
  1754. delete(Info);
  1755. }
  1756. return(TRUE);
  1757. }
  1758. VOID
  1759. CFtInfo::AddFtSetInfo(
  1760. CFtInfoFtSet *FtSet,
  1761. CFtInfoFtSet *OldFtSet
  1762. )
  1763. {
  1764. DWORD MemberCount;
  1765. DWORD i;
  1766. CFtInfoPartition *Partition;
  1767. CFtInfoPartition *NewPartition;
  1768. CFtInfoDisk *Disk;
  1769. CFtInfoFtSet *NewFtSet;
  1770. USHORT FtGroup;
  1771. POSITION pos;
  1772. BOOL Success;
  1773. if (OldFtSet != NULL) {
  1774. CFtInfoFtSet *pSet;
  1775. pos = m_FtSetInfo.GetHeadPosition();
  1776. for (FtGroup = 1; ; FtGroup++) {
  1777. pSet = m_FtSetInfo.GetNext(pos);
  1778. if (pSet == NULL) {
  1779. OldFtSet = NULL;
  1780. break;
  1781. }
  1782. if (pSet == OldFtSet) {
  1783. //
  1784. // Reset our position back to point at the OldFtSet
  1785. //
  1786. pos = m_FtSetInfo.Find(OldFtSet);
  1787. break;
  1788. }
  1789. }
  1790. }
  1791. if (OldFtSet == NULL) {
  1792. FtGroup = (USHORT)m_FtSetInfo.GetCount()+1;
  1793. }
  1794. //
  1795. // Add each disk in the FT set.
  1796. //
  1797. MemberCount = FtSet->GetMemberCount();
  1798. for (i=0; i<MemberCount; i++) {
  1799. Partition = FtSet->GetMemberByIndex(i);
  1800. DISKASSERT(Partition != NULL);
  1801. Disk = new CFtInfoDisk(Partition->m_ParentDisk);
  1802. if (Disk == NULL) {
  1803. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  1804. return; // [REENGINEER], caller doesn't know about the problem
  1805. }
  1806. SetDiskInfo(Disk);
  1807. }
  1808. //
  1809. // Create the empty FT set.
  1810. //
  1811. NewFtSet = new CFtInfoFtSet;
  1812. if (NewFtSet == NULL) {
  1813. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  1814. return; // [REENGINEER], caller doesn't know about the problem
  1815. }
  1816. Success = NewFtSet->Initialize(FtSet->GetType(), FtSet->GetState());
  1817. DISKASSERT(Success);
  1818. //
  1819. // Add each member to the empty FT set
  1820. //
  1821. for (i=0; i<MemberCount; i++) {
  1822. //
  1823. // Find each partition object in our FT information.
  1824. //
  1825. Partition = FtSet->GetMemberByIndex(i);
  1826. NewPartition = FindPartition(Partition->m_ParentDisk->m_Signature,
  1827. Partition->m_PartitionInfo->StartingOffset,
  1828. Partition->m_PartitionInfo->Length);
  1829. DISKASSERT(NewPartition != NULL);
  1830. NewFtSet->AddMember(NewPartition,
  1831. FtSet->GetMemberDescription(i),
  1832. FtGroup);
  1833. }
  1834. if (OldFtSet != NULL) {
  1835. //
  1836. // Replace the old FT set information
  1837. //
  1838. m_FtSetInfo.SetAt(pos, NewFtSet);
  1839. delete(OldFtSet);
  1840. } else {
  1841. //
  1842. // Add the new FT set to the FT information
  1843. //
  1844. m_FtSetInfo.AddTail(NewFtSet);
  1845. }
  1846. }
  1847. CFtInfoFtSet *
  1848. CFtInfo::FindFtSetInfo(
  1849. IN DWORD Signature
  1850. )
  1851. {
  1852. CFtInfoFtSet *RetInfo;
  1853. POSITION pos = m_FtSetInfo.GetHeadPosition();
  1854. while (pos) {
  1855. RetInfo = m_FtSetInfo.GetNext(pos);
  1856. if (RetInfo->GetMemberBySignature(Signature) != NULL) {
  1857. return(RetInfo);
  1858. }
  1859. }
  1860. return(NULL);
  1861. }
  1862. CFtInfoFtSet *
  1863. CFtInfo::EnumFtSetInfo(
  1864. IN DWORD Index
  1865. )
  1866. {
  1867. DWORD i=0;
  1868. CFtInfoFtSet *RetInfo;
  1869. POSITION pos = m_FtSetInfo.GetHeadPosition();
  1870. while (pos) {
  1871. RetInfo = m_FtSetInfo.GetNext(pos);
  1872. if (i == Index) {
  1873. return(RetInfo);
  1874. }
  1875. ++i;
  1876. }
  1877. return(NULL);
  1878. }
  1879. BOOL
  1880. CFtInfo::DeleteFtSetInfo(
  1881. IN CFtInfoFtSet *FtSet
  1882. )
  1883. {
  1884. POSITION pos = m_FtSetInfo.Find(FtSet);
  1885. if (pos == NULL) {
  1886. DISKLOG(("CFtInfo::DeleteFtSetInfo did not find Info %08X\n",FtSet));
  1887. DISKERR(IDS_GENERAL_FAILURE, ERROR_FILE_NOT_FOUND);
  1888. return(FALSE);
  1889. } else {
  1890. DWORD i;
  1891. CFtInfoPartition *FtPartition;
  1892. //
  1893. // Set the FT group of all this set's members to -1
  1894. //
  1895. for (i=0; ; i++) {
  1896. FtPartition = FtSet->GetMemberByIndex(i);
  1897. if (FtPartition == NULL) {
  1898. break;
  1899. }
  1900. FtPartition->m_PartitionInfo->FtGroup = (USHORT)-1;
  1901. FtPartition->m_PartitionInfo->FtMember = 0;
  1902. FtPartition->m_PartitionInfo->FtType = NotAnFtMember;
  1903. }
  1904. m_FtSetInfo.RemoveAt(pos);
  1905. delete(FtSet);
  1906. }
  1907. return(TRUE);
  1908. }
  1909. CFtInfoPartition *
  1910. CFtInfo::FindPartition(
  1911. DWORD Signature,
  1912. LARGE_INTEGER StartingOffset,
  1913. LARGE_INTEGER Length
  1914. )
  1915. {
  1916. CFtInfoDisk *Disk;
  1917. Disk = FindDiskInfo(Signature);
  1918. if (Disk == NULL) {
  1919. return(NULL);
  1920. }
  1921. return(Disk->GetPartition(StartingOffset, Length));
  1922. }
  1923. CFtInfoPartition *
  1924. CFtInfo::FindPartition(
  1925. UCHAR DriveLetter
  1926. )
  1927. {
  1928. CFtInfoDisk *Disk;
  1929. CFtInfoPartition *Partition;
  1930. DWORD DiskIndex;
  1931. DWORD PartitionIndex;
  1932. for (DiskIndex = 0; ; DiskIndex++) {
  1933. Disk = EnumDiskInfo(DiskIndex);
  1934. if (Disk == NULL) {
  1935. break;
  1936. }
  1937. for (PartitionIndex = 0; ; PartitionIndex++) {
  1938. Partition = Disk->GetPartitionByIndex(PartitionIndex);
  1939. if (Partition == NULL) {
  1940. break;
  1941. }
  1942. if (Partition->m_PartitionInfo->AssignDriveLetter &&
  1943. (Partition->m_PartitionInfo->DriveLetter == DriveLetter)) {
  1944. //
  1945. // Found a match.
  1946. //
  1947. return(Partition);
  1948. }
  1949. }
  1950. }
  1951. return(NULL);
  1952. }
  1953. DWORD
  1954. CFtInfo::GetSize()
  1955. {
  1956. CFtInfoDisk *DiskInfo;
  1957. CFtInfoFtSet *FtSetInfo;
  1958. DWORD Delta;
  1959. //
  1960. // Start off with the fixed size header
  1961. //
  1962. DWORD Size = sizeof(DISK_CONFIG_HEADER);
  1963. DISKLOG(("CFtInfo::GetSize headersize = %x\n",Size));
  1964. //
  1965. // Add in the size of the DISK_REGISTRY header
  1966. //
  1967. Delta = sizeof(DISK_REGISTRY) - sizeof(DISK_DESCRIPTION);
  1968. Size += Delta;
  1969. DISKLOG(("CFtInfo::GetSize += DISK_REGISTRY(%x) = %x\n",Delta, Size));
  1970. if (!m_DiskInfo.IsEmpty()) {
  1971. //
  1972. // Add the sizes of each disks partition information
  1973. //
  1974. POSITION pos = m_DiskInfo.GetHeadPosition();
  1975. while (pos) {
  1976. DiskInfo = m_DiskInfo.GetNext(pos);
  1977. Delta = DiskInfo->GetSize();
  1978. Size += Delta;
  1979. DISKLOG(("CFtInfo::GetSize += DiskInfo(%x) = %x\n",Delta, Size));
  1980. }
  1981. if (!m_FtSetInfo.IsEmpty()) {
  1982. //
  1983. // Add in the size of the FT_REGISTRY header
  1984. //
  1985. Delta = sizeof(FT_REGISTRY) - sizeof(FT_DESCRIPTION);
  1986. Size += Delta;
  1987. DISKLOG(("CFtInfo::GetSize += FT_REGISTRY(%x) = %x\n",Delta, Size));
  1988. //
  1989. // Add the sizes of each FT sets information
  1990. //
  1991. pos = m_FtSetInfo.GetHeadPosition();
  1992. while (pos) {
  1993. FtSetInfo = m_FtSetInfo.GetNext(pos);
  1994. Delta = FtSetInfo->GetSize();
  1995. Size += Delta;
  1996. DISKLOG(("CFtInfo::GetSize +=FtSetInfo(%x) = %x\n",Delta, Size));
  1997. }
  1998. }
  1999. }
  2000. return(Size);
  2001. }
  2002. VOID
  2003. CFtInfo::GetData(
  2004. PDISK_CONFIG_HEADER pDest
  2005. )
  2006. {
  2007. PDISK_CONFIG_HEADER DiskConfigHeader;
  2008. PDISK_REGISTRY DiskRegistry;
  2009. PDISK_DESCRIPTION DiskDescription;
  2010. PFT_REGISTRY FtRegistry;
  2011. PFT_DESCRIPTION FtDescription;
  2012. DWORD Count;
  2013. POSITION pos;
  2014. CFtInfoDisk *DiskInfo;
  2015. CFtInfoFtSet *FtSetInfo;
  2016. //
  2017. // Initialize the fixed size header.
  2018. //
  2019. // Copy the original header, then zero out the fields we might
  2020. // change.
  2021. //
  2022. DiskConfigHeader = pDest;
  2023. CopyMemory(DiskConfigHeader, m_buffer, sizeof(DISK_CONFIG_HEADER));
  2024. DiskConfigHeader->DiskInformationOffset = sizeof(DISK_CONFIG_HEADER);
  2025. DiskConfigHeader->FtInformationOffset = 0;
  2026. DiskConfigHeader->FtInformationSize = 0;
  2027. //
  2028. // Initialize the fixed size DISK_REGISTRY header
  2029. //
  2030. DiskRegistry = (PDISK_REGISTRY)(DiskConfigHeader + 1);
  2031. DiskRegistry->NumberOfDisks = (USHORT)m_DiskInfo.GetCount();
  2032. DiskRegistry->ReservedShort = 0;
  2033. DiskConfigHeader->DiskInformationSize = sizeof(DISK_REGISTRY) - sizeof(DISK_DESCRIPTION);
  2034. if (!m_DiskInfo.IsEmpty()) {
  2035. //
  2036. // Get each disk's information
  2037. //
  2038. DiskDescription = &DiskRegistry->Disks[0];
  2039. pos = m_DiskInfo.GetHeadPosition();
  2040. while (pos) {
  2041. DWORD Size;
  2042. DiskInfo = m_DiskInfo.GetNext(pos);
  2043. DiskInfo->SetOffset((DWORD)((PUCHAR)DiskDescription - (PUCHAR)DiskConfigHeader));
  2044. DiskInfo->GetData((PBYTE)DiskDescription);
  2045. Size = DiskInfo->GetSize();
  2046. DiskConfigHeader->DiskInformationSize += Size;
  2047. DiskDescription = (PDISK_DESCRIPTION)((PUCHAR)DiskDescription + Size);
  2048. }
  2049. //
  2050. // Now set the FT information
  2051. //
  2052. FtRegistry = (PFT_REGISTRY)DiskDescription;
  2053. DiskConfigHeader->FtInformationOffset =(DWORD)((PBYTE)FtRegistry - (PBYTE)DiskConfigHeader);
  2054. if (!m_FtSetInfo.IsEmpty()) {
  2055. //
  2056. // Initialize the fixed size FT_REGISTRY header
  2057. //
  2058. FtRegistry->NumberOfComponents = (USHORT)m_FtSetInfo.GetCount();
  2059. FtRegistry->ReservedShort = 0;
  2060. DiskConfigHeader->FtInformationSize = sizeof(FT_REGISTRY) - sizeof(FT_DESCRIPTION);
  2061. FtDescription = &FtRegistry->FtDescription[0];
  2062. pos = m_FtSetInfo.GetHeadPosition();
  2063. while (pos) {
  2064. DWORD Size;
  2065. FtSetInfo = m_FtSetInfo.GetNext(pos);
  2066. FtSetInfo->GetData((PBYTE)FtDescription);
  2067. Size = FtSetInfo->GetSize();
  2068. DiskConfigHeader->FtInformationSize += Size;
  2069. FtDescription = (PFT_DESCRIPTION)((PUCHAR)FtDescription + Size);
  2070. }
  2071. }
  2072. }
  2073. }
  2074. //********************
  2075. //
  2076. // Implementation of standard partition information
  2077. //
  2078. //********************
  2079. CFtInfoPartition::CFtInfoPartition(
  2080. CFtInfoDisk *Disk,
  2081. DISK_PARTITION UNALIGNED *Description
  2082. )
  2083. {
  2084. m_ParentDisk = Disk;
  2085. m_Modified = TRUE;
  2086. m_PartitionInfo = (PDISK_PARTITION)LocalAlloc(LMEM_FIXED, sizeof(DISK_PARTITION));
  2087. if (m_PartitionInfo == NULL) {
  2088. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  2089. // [REENGINEER], will AV in a second
  2090. }
  2091. CopyMemory(m_PartitionInfo, Description, sizeof(DISK_PARTITION));
  2092. }
  2093. CFtInfoPartition::CFtInfoPartition(
  2094. CFtInfoDisk *Disk,
  2095. CPhysicalPartition *Partition
  2096. )
  2097. {
  2098. m_ParentDisk = Disk;
  2099. m_Modified = TRUE;
  2100. m_PartitionInfo = (PDISK_PARTITION)LocalAlloc(LMEM_FIXED, sizeof(DISK_PARTITION));
  2101. if (m_PartitionInfo == NULL) {
  2102. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  2103. // [REENGINEER], will AV in a second
  2104. }
  2105. m_PartitionInfo->FtType = NotAnFtMember;
  2106. m_PartitionInfo->FtState = Healthy;
  2107. m_PartitionInfo->StartingOffset = Partition->m_Info.StartingOffset;
  2108. m_PartitionInfo->Length = Partition->m_Info.PartitionLength;
  2109. m_PartitionInfo->FtLength.QuadPart = 0;
  2110. m_PartitionInfo->DriveLetter = 0;
  2111. m_PartitionInfo->AssignDriveLetter = FALSE;
  2112. m_PartitionInfo->LogicalNumber = 0;
  2113. m_PartitionInfo->FtGroup = (USHORT)-1;
  2114. m_PartitionInfo->FtMember = 0;
  2115. m_PartitionInfo->Modified = FALSE;
  2116. }
  2117. CFtInfoPartition::CFtInfoPartition(
  2118. CFtInfoDisk *Disk,
  2119. PARTITION_INFORMATION * PartitionInfo
  2120. )
  2121. {
  2122. m_ParentDisk = Disk;
  2123. m_Modified = TRUE;
  2124. m_PartitionInfo = (PDISK_PARTITION)LocalAlloc(LMEM_FIXED, sizeof(DISK_PARTITION));
  2125. if (m_PartitionInfo == NULL) {
  2126. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  2127. // [REENGINEER], will AV in a second
  2128. }
  2129. m_PartitionInfo->FtType = NotAnFtMember;
  2130. m_PartitionInfo->FtState = Healthy;
  2131. m_PartitionInfo->StartingOffset = PartitionInfo->StartingOffset;
  2132. m_PartitionInfo->Length = PartitionInfo->PartitionLength;
  2133. m_PartitionInfo->FtLength.QuadPart = 0;
  2134. m_PartitionInfo->DriveLetter = 0;
  2135. m_PartitionInfo->AssignDriveLetter = FALSE;
  2136. m_PartitionInfo->LogicalNumber = 0;
  2137. m_PartitionInfo->FtGroup = (USHORT)-1;
  2138. m_PartitionInfo->FtMember = 0;
  2139. m_PartitionInfo->Modified = FALSE;
  2140. }
  2141. CFtInfoPartition::~CFtInfoPartition()
  2142. {
  2143. if (m_Modified) {
  2144. LocalFree(m_PartitionInfo);
  2145. }
  2146. }
  2147. VOID
  2148. CFtInfoPartition::GetData(
  2149. PDISK_PARTITION pDest
  2150. )
  2151. {
  2152. DISKLOG(("CFtInfoPartition::GetData %12I64X - %12I64X\n",
  2153. m_PartitionInfo->StartingOffset.QuadPart,
  2154. m_PartitionInfo->Length.QuadPart));
  2155. DISKLOG((" %c (%s) %x %x %x\n",
  2156. m_PartitionInfo->DriveLetter,
  2157. m_PartitionInfo->AssignDriveLetter ? "Sticky" : "Not Sticky",
  2158. m_PartitionInfo->LogicalNumber,
  2159. m_PartitionInfo->FtGroup,
  2160. m_PartitionInfo->FtMember));
  2161. CopyMemory(pDest, m_PartitionInfo, sizeof(DISK_PARTITION));
  2162. }
  2163. DWORD
  2164. CFtInfoPartition::GetOffset(
  2165. VOID
  2166. )
  2167. {
  2168. DWORD ParentOffset;
  2169. ParentOffset = m_ParentDisk->GetOffset();
  2170. return(ParentOffset + m_RelativeOffset);
  2171. }
  2172. VOID
  2173. CFtInfoPartition::MakeSticky(
  2174. UCHAR DriveLetter
  2175. )
  2176. {
  2177. m_PartitionInfo->DriveLetter = DriveLetter;
  2178. //
  2179. // if drive letter is being removed, clear the sticky bit
  2180. //
  2181. m_PartitionInfo->AssignDriveLetter = ( DriveLetter != 0 );
  2182. }
  2183. //********************
  2184. //
  2185. // Implementation of standard disk information
  2186. //
  2187. //********************
  2188. CFtInfoDisk::CFtInfoDisk(
  2189. DISK_DESCRIPTION UNALIGNED *Description
  2190. )
  2191. {
  2192. DWORD i;
  2193. DWORD Offset;
  2194. CFtInfoPartition *Partition;
  2195. //
  2196. // windisk sometimes puts in disk information
  2197. // for disks with no partitions. Seems a bit pointless.
  2198. //
  2199. // DISKASSERT(Description->NumberOfPartitions > 0);
  2200. m_PartitionCount = Description->NumberOfPartitions;
  2201. m_Signature = Description->Signature;
  2202. for (i=0; i<m_PartitionCount; i++) {
  2203. Partition = new CFtInfoPartition(this, &Description->Partitions[i]);
  2204. if (Partition != NULL) {
  2205. Offset = sizeof(DISK_DESCRIPTION) + i*sizeof(DISK_PARTITION) - sizeof(DISK_PARTITION);
  2206. Partition->SetOffset(Offset);
  2207. m_PartitionInfo.AddTail(Partition);
  2208. }
  2209. }
  2210. }
  2211. CFtInfoDisk::CFtInfoDisk(
  2212. CPhysicalDisk *Disk
  2213. )
  2214. {
  2215. DISKASSERT(Disk->m_PartitionCount > 0);
  2216. m_PartitionCount = Disk->m_PartitionCount;
  2217. m_Signature = Disk->m_Signature;
  2218. //
  2219. // Build up the partition objects
  2220. //
  2221. CFtInfoPartition *PartitionInfo;
  2222. CPhysicalPartition *Partition;
  2223. DWORD Offset;
  2224. DWORD i=0;
  2225. POSITION pos = Disk->m_PartitionList.GetHeadPosition();
  2226. while (pos) {
  2227. Partition = Disk->m_PartitionList.GetNext(pos);
  2228. PartitionInfo = new CFtInfoPartition(this, Partition);
  2229. if (PartitionInfo != NULL) {
  2230. Offset = sizeof(DISK_DESCRIPTION) + i*sizeof(DISK_PARTITION) - sizeof(DISK_PARTITION);
  2231. PartitionInfo->SetOffset(Offset);
  2232. m_PartitionInfo.AddTail(PartitionInfo);
  2233. ++i;
  2234. }
  2235. }
  2236. }
  2237. CFtInfoDisk::CFtInfoDisk(
  2238. CFtInfoDisk *DiskInfo
  2239. )
  2240. {
  2241. DISKASSERT(DiskInfo->m_PartitionCount > 0);
  2242. m_PartitionCount = DiskInfo->m_PartitionCount;
  2243. m_Signature = DiskInfo->m_Signature;
  2244. //
  2245. // Build up the partition objects
  2246. //
  2247. CFtInfoPartition *PartitionInfo;
  2248. CFtInfoPartition *SourcePartitionInfo;
  2249. DWORD Offset;
  2250. DWORD i=0;
  2251. POSITION pos = DiskInfo->m_PartitionInfo.GetHeadPosition();
  2252. while (pos) {
  2253. SourcePartitionInfo = DiskInfo->m_PartitionInfo.GetNext(pos);
  2254. PartitionInfo = new CFtInfoPartition(this, SourcePartitionInfo->m_PartitionInfo);
  2255. if (PartitionInfo != NULL) {
  2256. Offset = sizeof(DISK_DESCRIPTION) + i*sizeof(DISK_PARTITION) - sizeof(DISK_PARTITION);
  2257. PartitionInfo->SetOffset(Offset);
  2258. m_PartitionInfo.AddTail(PartitionInfo);
  2259. ++i;
  2260. }
  2261. }
  2262. }
  2263. CFtInfoDisk::CFtInfoDisk(
  2264. DRIVE_LAYOUT_INFORMATION *DriveLayout
  2265. )
  2266. {
  2267. DWORD i;
  2268. CFtInfoPartition *ftInfoPartition;
  2269. m_PartitionCount = 0; // [GN] Bugfix #278913
  2270. m_Signature = DriveLayout->Signature;
  2271. for (i=0; i < DriveLayout->PartitionCount; i++) {
  2272. if (DriveLayout->PartitionEntry[i].RecognizedPartition) {
  2273. m_PartitionCount++;
  2274. ftInfoPartition = new CFtInfoPartition(this, &DriveLayout->PartitionEntry[i]);
  2275. if (ftInfoPartition == NULL) {
  2276. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  2277. // [REENGINEER], we will add a 0 pointer into m_PartitionInfo ... bad
  2278. }
  2279. m_PartitionInfo.AddTail(ftInfoPartition);
  2280. }
  2281. }
  2282. }
  2283. CFtInfoDisk::~CFtInfoDisk()
  2284. {
  2285. CFtInfoPartition *Partition;
  2286. while (!m_PartitionInfo.IsEmpty()) {
  2287. Partition = m_PartitionInfo.RemoveHead();
  2288. delete(Partition);
  2289. }
  2290. }
  2291. BOOL
  2292. CFtInfoDisk::operator==(
  2293. const CFtInfoDisk& Disk
  2294. )
  2295. {
  2296. if (m_PartitionCount != Disk.m_PartitionCount) {
  2297. DISKLOG(("CFtInfoDisk::operator== partition count %d != %d\n",
  2298. m_PartitionCount,
  2299. Disk.m_PartitionCount));
  2300. return(FALSE);
  2301. }
  2302. if (m_Signature != Disk.m_Signature) {
  2303. DISKLOG(("CFtInfoDisk::operator== signature %08lx != %08lx\n",
  2304. m_Signature,
  2305. Disk.m_Signature));
  2306. return(FALSE);
  2307. }
  2308. POSITION MyPos, OtherPos;
  2309. CFtInfoPartition *MyPartition, *OtherPartition;
  2310. MyPos = m_PartitionInfo.GetHeadPosition();
  2311. OtherPos = Disk.m_PartitionInfo.GetHeadPosition();
  2312. while (MyPos || OtherPos) {
  2313. if (!MyPos) {
  2314. DISKLOG(("CFtInfoDisk::operator== MyPos is NULL\n"));
  2315. return(FALSE);
  2316. }
  2317. if (!OtherPos) {
  2318. DISKLOG(("CFtInfoDisk::operator== OtherPos is NULL\n"));
  2319. return(FALSE);
  2320. }
  2321. MyPartition = m_PartitionInfo.GetNext(MyPos);
  2322. OtherPartition = Disk.m_PartitionInfo.GetNext(OtherPos);
  2323. if (memcmp(MyPartition->m_PartitionInfo,
  2324. OtherPartition->m_PartitionInfo,
  2325. sizeof(DISK_PARTITION)) != 0) {
  2326. DISKLOG(("CFtInfoDisk::operator== DISK_PARTITIONs don't match\n"));
  2327. return(FALSE);
  2328. }
  2329. }
  2330. DISKLOG(("CFtInfoDisk::operator== disk information matches\n"));
  2331. return(TRUE);
  2332. }
  2333. CFtInfoPartition *
  2334. CFtInfoDisk::GetPartition(
  2335. LARGE_INTEGER StartingOffset,
  2336. LARGE_INTEGER Length
  2337. )
  2338. {
  2339. DWORD i;
  2340. CFtInfoPartition *Partition;
  2341. POSITION pos;
  2342. pos = m_PartitionInfo.GetHeadPosition();
  2343. while (pos) {
  2344. Partition = m_PartitionInfo.GetNext(pos);
  2345. if ((Partition->m_PartitionInfo->StartingOffset.QuadPart == StartingOffset.QuadPart) &&
  2346. (Partition->m_PartitionInfo->Length.QuadPart == Length.QuadPart)) {
  2347. return(Partition);
  2348. }
  2349. }
  2350. return(NULL);
  2351. }
  2352. CFtInfoPartition *
  2353. CFtInfoDisk::GetPartitionByOffset(
  2354. DWORD Offset
  2355. )
  2356. {
  2357. CFtInfoPartition *Partition;
  2358. POSITION pos;
  2359. pos = m_PartitionInfo.GetHeadPosition();
  2360. while (pos) {
  2361. Partition = m_PartitionInfo.GetNext(pos);
  2362. if (Partition->GetOffset() == Offset) {
  2363. return(Partition);
  2364. }
  2365. }
  2366. return(NULL);
  2367. }
  2368. CFtInfoPartition *
  2369. CFtInfoDisk::GetPartitionByIndex(
  2370. DWORD Index
  2371. )
  2372. {
  2373. DWORD i = 0;
  2374. CFtInfoPartition *Partition;
  2375. POSITION pos;
  2376. pos = m_PartitionInfo.GetHeadPosition();
  2377. while (pos) {
  2378. Partition = m_PartitionInfo.GetNext(pos);
  2379. if (i == Index) {
  2380. return(Partition);
  2381. }
  2382. ++i;
  2383. }
  2384. return(NULL);
  2385. }
  2386. DWORD
  2387. CFtInfoDisk::FtPartitionCount(
  2388. VOID
  2389. )
  2390. /*++
  2391. Routine Description:
  2392. Returns the number of FT partitions on this disk. This is useful
  2393. for determining whether a given FT set shares this disk with another
  2394. FT set.
  2395. Arguments:
  2396. None
  2397. Return Value:
  2398. The number of FT partitions on this disk
  2399. --*/
  2400. {
  2401. POSITION pos;
  2402. CFtInfoPartition *Partition;
  2403. DWORD Count = 0;
  2404. pos = m_PartitionInfo.GetHeadPosition();
  2405. while (pos) {
  2406. Partition = m_PartitionInfo.GetNext(pos);
  2407. if (Partition->IsFtPartition()) {
  2408. ++Count;
  2409. }
  2410. }
  2411. return(Count);
  2412. }
  2413. DWORD
  2414. CFtInfoDisk::GetSize(
  2415. VOID
  2416. )
  2417. {
  2418. return(sizeof(DISK_DESCRIPTION) +
  2419. (m_PartitionCount-1) * sizeof(DISK_PARTITION));
  2420. }
  2421. VOID
  2422. CFtInfoDisk::GetData(
  2423. PBYTE pDest
  2424. )
  2425. {
  2426. PDISK_DESCRIPTION Description = (PDISK_DESCRIPTION)pDest;
  2427. DWORD i;
  2428. CFtInfoPartition *Partition;
  2429. DISKLOG(("CFtInfoDisk::GetData signature %08lx has %d partitions\n",m_Signature, m_PartitionCount));
  2430. Description->NumberOfPartitions = (USHORT)m_PartitionCount;
  2431. Description->ReservedShort = 0;
  2432. Description->Signature = m_Signature;
  2433. POSITION pos = m_PartitionInfo.GetHeadPosition();
  2434. i=0;
  2435. while (pos) {
  2436. Partition = m_PartitionInfo.GetNext(pos);
  2437. Partition->GetData(&Description->Partitions[i]);
  2438. ++i;
  2439. }
  2440. }
  2441. //********************
  2442. //
  2443. // Implementation of FT registry information
  2444. //
  2445. //********************
  2446. BOOL
  2447. CFtInfoFtSet::Initialize(USHORT Type, FT_STATE FtVolumeState)
  2448. {
  2449. m_Modified = TRUE;
  2450. m_FtDescription = (PFT_DESCRIPTION)LocalAlloc(LMEM_FIXED, sizeof(FT_DESCRIPTION));
  2451. DISKASSERT(m_FtDescription);
  2452. m_FtDescription->NumberOfMembers = 0;
  2453. m_FtDescription->Type = Type;
  2454. m_FtDescription->Reserved = 0;
  2455. m_FtDescription->FtVolumeState = FtVolumeState;
  2456. return(TRUE);
  2457. }
  2458. BOOL
  2459. CFtInfoFtSet::Initialize(
  2460. CFtInfo *FtInfo,
  2461. PFT_DESCRIPTION Description
  2462. )
  2463. {
  2464. m_FtDescription = Description;
  2465. m_Modified = FALSE;
  2466. //
  2467. // Create the list of members.
  2468. //
  2469. CFtInfoDisk *Disk;
  2470. CFtInfoPartition *Partition;
  2471. PFT_MEMBER_DESCRIPTION Member;
  2472. DWORD i;
  2473. if (Description->NumberOfMembers == 0) {
  2474. //
  2475. // WINDISK will sometimes put FT sets with zero members in
  2476. // the registry after breaking a mirror set. Throw them out,
  2477. // seems pretty pointless...
  2478. //
  2479. DISKLOG(("CFtInfoFtSet::Initialize - FT Set with zero members ignored\n"));
  2480. return(FALSE);
  2481. }
  2482. m_Members.SetSize(Description->NumberOfMembers);
  2483. for (i=0; i<Description->NumberOfMembers; i++) {
  2484. Member = &Description->FtMemberDescription[i];
  2485. //
  2486. // Find the disk by its signature
  2487. //
  2488. Disk = FtInfo->FindDiskInfo(Member->Signature);
  2489. if (Disk == NULL) {
  2490. DISKLOG(("CFtInfoFtSet::Initialize - Disk signature %08lx not found\n",
  2491. Member->Signature));
  2492. return(FALSE);
  2493. }
  2494. //
  2495. // Find the partition by its offset.
  2496. //
  2497. Partition = Disk->GetPartitionByOffset(Member->OffsetToPartitionInfo);
  2498. if (Partition == NULL) {
  2499. DISKLOG(("CFtInfoFtSet::Initialize - Partition on disk %08lx at offset %08lx not found\n",
  2500. Member->Signature,
  2501. Member->OffsetToPartitionInfo));
  2502. return(FALSE);
  2503. }
  2504. //
  2505. // Add this partition to our list.
  2506. //
  2507. if (Partition->m_PartitionInfo->FtMember >= Description->NumberOfMembers) {
  2508. DISKLOG(("CFtInfoFtSet::Initialize - member %d out of range\n",
  2509. Partition->m_PartitionInfo->FtMember));
  2510. return(FALSE);
  2511. }
  2512. if (m_Members[Partition->m_PartitionInfo->FtMember] != NULL) {
  2513. DISKLOG(("CFtInfoFtSet::Initialize - Duplicate member %d\n",
  2514. Partition->m_PartitionInfo->FtMember));
  2515. return(FALSE);
  2516. }
  2517. m_Members.SetAt(Partition->m_PartitionInfo->FtMember, Partition);
  2518. }
  2519. return(TRUE);
  2520. }
  2521. CFtInfoFtSet::~CFtInfoFtSet()
  2522. {
  2523. if (m_Modified) {
  2524. LocalFree(m_FtDescription);
  2525. }
  2526. }
  2527. BOOL
  2528. CFtInfoFtSet::operator==(
  2529. const CFtInfoFtSet& FtSet1
  2530. )
  2531. {
  2532. DWORD MemberCount;
  2533. DWORD i;
  2534. CFtInfoDisk *Disk1;
  2535. CFtInfoDisk *Disk2;
  2536. if (GetType() != FtSet1.GetType()) {
  2537. return(FALSE);
  2538. }
  2539. if (GetState() != FtSet1.GetState()) {
  2540. return(FALSE);
  2541. }
  2542. MemberCount = GetMemberCount();
  2543. if (MemberCount != FtSet1.GetMemberCount()) {
  2544. return(FALSE);
  2545. }
  2546. for (i=0; i<MemberCount; i++) {
  2547. Disk1 = GetMemberByIndex(i)->m_ParentDisk;
  2548. Disk2 = FtSet1.GetMemberByIndex(i)->m_ParentDisk;
  2549. if (!(*Disk1 == *Disk2)) {
  2550. return(FALSE);
  2551. }
  2552. }
  2553. DISKLOG(("CFtInfoFtSet::operator== FT information matches\n"));
  2554. return(TRUE);
  2555. }
  2556. DWORD
  2557. CFtInfoFtSet::GetSize(
  2558. VOID
  2559. ) const
  2560. {
  2561. return(sizeof(FT_DESCRIPTION) +
  2562. (m_FtDescription->NumberOfMembers-1) * sizeof(FT_MEMBER_DESCRIPTION));
  2563. }
  2564. VOID
  2565. CFtInfoFtSet::GetData(
  2566. PBYTE pDest
  2567. )
  2568. {
  2569. PFT_DESCRIPTION Description = (PFT_DESCRIPTION)pDest;
  2570. DWORD Size = GetSize();
  2571. CopyMemory(Description, m_FtDescription, Size);
  2572. //
  2573. // Now go through the partitions and update the offsets.
  2574. //
  2575. DWORD i;
  2576. CFtInfoPartition *Partition;
  2577. for (i=0; i<GetMemberCount(); i++) {
  2578. Partition = m_Members[i];
  2579. Description->FtMemberDescription[i].OffsetToPartitionInfo = Partition->GetOffset();
  2580. }
  2581. }
  2582. BOOL
  2583. CFtInfoFtSet::IsAlone(
  2584. VOID
  2585. )
  2586. /*++
  2587. Routine Description:
  2588. Returns whether or not this FT set has a disk in common with
  2589. any other FT set.
  2590. Arguments:
  2591. None
  2592. Return Value:
  2593. TRUE if this FT set does not share any physical disk with any other
  2594. FT set
  2595. FALSE if there is another FT set sharing a disk as this one.
  2596. --*/
  2597. {
  2598. //
  2599. // Go through each member of the FT set and see if any disk has
  2600. // more than one partition that is marked as an FT partition.
  2601. //
  2602. POSITION pos;
  2603. CFtInfoPartition *Partition;
  2604. CFtInfoDisk *Disk;
  2605. DWORD i;
  2606. for (i=0; i<GetMemberCount(); i++) {
  2607. Partition = m_Members[i];
  2608. Disk = Partition->m_ParentDisk;
  2609. if (Disk->FtPartitionCount() > 1) {
  2610. //
  2611. // This disk has more than one FT partition, so there must be
  2612. // another set sharing it.
  2613. //
  2614. return(FALSE);
  2615. }
  2616. }
  2617. return(TRUE);
  2618. }
  2619. CFtInfoPartition *
  2620. CFtInfoFtSet::GetMemberBySignature(
  2621. IN DWORD Signature
  2622. ) const
  2623. {
  2624. CFtInfoPartition *Partition;
  2625. DWORD i;
  2626. for (i=0; i<GetMemberCount(); i++) {
  2627. Partition = m_Members[i];
  2628. if (Partition->m_ParentDisk->m_Signature == Signature) {
  2629. return(Partition);
  2630. }
  2631. }
  2632. return(NULL);
  2633. }
  2634. CFtInfoPartition *
  2635. CFtInfoFtSet::GetMemberByIndex(
  2636. IN DWORD Index
  2637. ) const
  2638. {
  2639. CFtInfoPartition *Partition;
  2640. if (Index >= GetMemberCount()) {
  2641. return(NULL);
  2642. }
  2643. return(m_Members[Index]);
  2644. }
  2645. DWORD
  2646. CFtInfoFtSet::AddMember(
  2647. CFtInfoPartition *Partition,
  2648. PFT_MEMBER_DESCRIPTION Description,
  2649. USHORT FtGroup
  2650. )
  2651. {
  2652. DWORD MemberCount;
  2653. PFT_DESCRIPTION NewBuff;
  2654. PFT_MEMBER_DESCRIPTION NewMember;
  2655. MemberCount = GetMemberCount();
  2656. if (MemberCount > 0) {
  2657. //
  2658. // Grow the size of our structure.
  2659. //
  2660. if (m_Modified) {
  2661. NewBuff = (PFT_DESCRIPTION)LocalReAlloc(m_FtDescription,
  2662. sizeof(FT_DESCRIPTION) + MemberCount*sizeof(FT_MEMBER_DESCRIPTION),
  2663. LMEM_MOVEABLE);
  2664. if (NewBuff == NULL) {
  2665. return(ERROR_NOT_ENOUGH_MEMORY);
  2666. }
  2667. m_FtDescription = NewBuff;
  2668. } else {
  2669. m_Modified = TRUE;
  2670. NewBuff = (PFT_DESCRIPTION)LocalAlloc(LMEM_FIXED,
  2671. sizeof(FT_DESCRIPTION) + MemberCount*sizeof(FT_MEMBER_DESCRIPTION));
  2672. if (NewBuff == NULL) {
  2673. return(ERROR_NOT_ENOUGH_MEMORY);
  2674. }
  2675. CopyMemory(NewBuff,
  2676. m_FtDescription,
  2677. sizeof(FT_DESCRIPTION) + (MemberCount-1)*sizeof(FT_MEMBER_DESCRIPTION));
  2678. m_FtDescription = NewBuff;
  2679. }
  2680. }
  2681. NewMember = &m_FtDescription->FtMemberDescription[MemberCount];
  2682. //
  2683. // Initialize the member description. Note that the OffsetToPartitionInfo
  2684. // will be updated when the user does a GetData.
  2685. //
  2686. NewMember->State = Description->State;
  2687. NewMember->ReservedShort = Description->ReservedShort;
  2688. NewMember->Signature = Description->Signature;
  2689. NewMember->LogicalNumber = Description->LogicalNumber;
  2690. //
  2691. // Add the partition to our list.
  2692. //
  2693. Partition->m_PartitionInfo->FtGroup = FtGroup;
  2694. Partition->m_PartitionInfo->FtMember = (USHORT)MemberCount;
  2695. m_Members.SetAtGrow(Partition->m_PartitionInfo->FtMember, Partition);
  2696. m_FtDescription->NumberOfMembers = (USHORT)GetMemberCount();
  2697. return(ERROR_SUCCESS);
  2698. }
  2699. //
  2700. // Some C wrappers used by the FT Set resource DLL
  2701. //
  2702. extern "C" {
  2703. PFT_INFO
  2704. DiskGetFtInfo(
  2705. VOID
  2706. )
  2707. {
  2708. PFT_INFO FtInfo;
  2709. FtInfo = (PFT_INFO)new CFtInfo;
  2710. return(FtInfo);
  2711. }
  2712. VOID
  2713. DiskFreeFtInfo(
  2714. PFT_INFO FtInfo
  2715. )
  2716. {
  2717. CFtInfo *Info;
  2718. Info = (CFtInfo *)FtInfo;
  2719. delete Info;
  2720. }
  2721. DWORD
  2722. DiskEnumFtSetSignature(
  2723. IN PFULL_FTSET_INFO FtSet,
  2724. IN DWORD MemberIndex,
  2725. OUT LPDWORD MemberSignature
  2726. )
  2727. /*++
  2728. Routine Description:
  2729. Returns the signature of the N'th member of the FT set.
  2730. Arguments:
  2731. FtSet - Supplies the FT information returned by DiskGetFullFtSetInfo
  2732. MemberIndex - Supplies the 0-based index of the member to return.
  2733. MemberSignature - Returns the signature of the MemberIndex'th member.
  2734. Return Value:
  2735. ERROR_SUCCESS if successful
  2736. ERROR_NO_MORE_ITEMS if the index is greather than the number of members
  2737. --*/
  2738. {
  2739. CFtInfo *Info;
  2740. CFtInfoFtSet *FtSetInfo;
  2741. CFtInfoPartition *Partition;
  2742. Info = new CFtInfo((PDISK_CONFIG_HEADER)FtSet);
  2743. if (Info == NULL) {
  2744. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  2745. return ERROR_NOT_ENOUGH_MEMORY;
  2746. }
  2747. FtSetInfo = Info->EnumFtSetInfo(0);
  2748. if (FtSetInfo == NULL) {
  2749. //
  2750. // There is no FT set information, so just return the signature of the n'th member
  2751. //
  2752. CFtInfoDisk *Disk;
  2753. Disk = Info->EnumDiskInfo(MemberIndex);
  2754. if (Disk == NULL) {
  2755. return(ERROR_NO_MORE_ITEMS);
  2756. } else {
  2757. *MemberSignature = Disk->m_Signature;
  2758. return(ERROR_SUCCESS);
  2759. }
  2760. }
  2761. Partition = FtSetInfo->GetMemberByIndex(MemberIndex);
  2762. if (Partition == NULL) {
  2763. return(ERROR_NO_MORE_ITEMS);
  2764. }
  2765. *MemberSignature = Partition->m_ParentDisk->m_Signature;
  2766. delete Info;
  2767. return(ERROR_SUCCESS);
  2768. }
  2769. PFULL_FTSET_INFO
  2770. DiskGetFullFtSetInfo(
  2771. IN PFT_INFO FtInfo,
  2772. IN LPCWSTR lpszMemberList,
  2773. OUT LPDWORD pSize
  2774. )
  2775. /*++
  2776. Routine Description:
  2777. Serializes the complete information from an FT set in a form
  2778. suitable for saving to a file or the registry. These bits can
  2779. be restored with DiskSetFullFtSetInfo.
  2780. Arguments:
  2781. FtInfo - supplies the FT information
  2782. lpszMemberList - Supplies a list of signatures. The list is in the
  2783. REG_MULTI_SZ format.
  2784. pSize - Returns the size of the FT information bytes.
  2785. Return Value:
  2786. A pointer to the serializable FT information if successful.
  2787. NULL on error
  2788. --*/
  2789. {
  2790. PDISK_CONFIG_HEADER DiskConfig;
  2791. DWORD Length;
  2792. CFtInfo *OriginalInfo;
  2793. CFtInfo *NewInfo;
  2794. CFtInfoFtSet *FtSetInfo;
  2795. CFtInfoPartition *FtPartitionInfo;
  2796. PDISK_PARTITION Member;
  2797. DWORD MemberCount;
  2798. DWORD i;
  2799. DWORD Index;
  2800. DWORD Signature;
  2801. LPCWSTR lpszSignature;
  2802. DWORD MultiSzLength;
  2803. WCHAR SignatureString[9];
  2804. OriginalInfo = (CFtInfo *)FtInfo;
  2805. MultiSzLength = ClRtlMultiSzLength(lpszMemberList);
  2806. //
  2807. // First, try to find an FT set that has the "identity" of at least one of the
  2808. // supplied members. This is tricky because we need to make sure that if multiple
  2809. // FT sets are broken and reformed with different members, only one FT resource
  2810. // picks up each FT set. We will find a matching FT set if:
  2811. // - One of the supplied members is the first member of a mirror or volume set.
  2812. // - The supplied members make up N-1 members of an N member SWP.
  2813. // - The supplied members make up all the members of a stripe.
  2814. //
  2815. for (i=0; ; i++) {
  2816. lpszSignature = ClRtlMultiSzEnum(lpszMemberList,
  2817. MultiSzLength,
  2818. i);
  2819. if (lpszSignature == NULL) {
  2820. DISKLOG(("DiskGetFullFtSetInfo: no FTSET containing members found\n"));
  2821. FtSetInfo = NULL;
  2822. break;
  2823. }
  2824. Signature = wcstoul(lpszSignature, NULL, 16);
  2825. DISKLOG(("DiskGetFullFtSetInfo: looking for member %08lx\n", Signature));
  2826. FtSetInfo = OriginalInfo->FindFtSetInfo(Signature);
  2827. if (FtSetInfo == NULL) {
  2828. DISKLOG(("DiskGetFullFtSetInfo: member %08lx is not in any FT set\n", Signature));
  2829. } else {
  2830. //
  2831. // Check to see if this is the first member of a volume set or mirror
  2832. //
  2833. if ((FtSetInfo->GetType() == Mirror) ||
  2834. (FtSetInfo->GetType() == VolumeSet)) {
  2835. //
  2836. // Now check to see if this member is the first member of the set.
  2837. //
  2838. if (FtSetInfo->GetMemberByIndex(0)->m_ParentDisk->m_Signature == Signature) {
  2839. //
  2840. // We have found a matching FT set.
  2841. //
  2842. DISKLOG(("DiskGetFullFtSetInfo: member %08lx found in FT set.\n", Signature));
  2843. break;
  2844. }
  2845. } else if ((FtSetInfo->GetType() == StripeWithParity) ||
  2846. (FtSetInfo->GetType() == Stripe)) {
  2847. DWORD MaxMissing;
  2848. //
  2849. // Check to see if the supplied member list makes up N-1 of the members
  2850. // of a stripe with parity or all the members of a stripe.
  2851. //
  2852. if (FtSetInfo->GetType() == StripeWithParity) {
  2853. MaxMissing = 1;
  2854. } else {
  2855. MaxMissing = 0;
  2856. }
  2857. for (Index = 0; ; Index++) {
  2858. FtPartitionInfo = FtSetInfo->GetMemberByIndex(Index);
  2859. if (FtPartitionInfo == NULL) {
  2860. break;
  2861. }
  2862. //
  2863. // Try to find this signature in the passed in member list.
  2864. //
  2865. (VOID) StringCchPrintf( SignatureString,
  2866. RTL_NUMBER_OF(SignatureString),
  2867. TEXT("%08lX"),
  2868. FtPartitionInfo->m_ParentDisk->m_Signature );
  2869. if (ClRtlMultiSzScan(lpszMemberList,SignatureString) == NULL) {
  2870. //
  2871. // This FT set member is not in the supplied list.
  2872. //
  2873. DISKLOG(("DiskGetFullFtSetInfo: member %08lx missing from old member list\n",
  2874. FtPartitionInfo->m_ParentDisk->m_Signature));
  2875. if (MaxMissing == 0) {
  2876. FtSetInfo = NULL;
  2877. break;
  2878. }
  2879. --MaxMissing;
  2880. }
  2881. }
  2882. if (FtSetInfo != NULL) {
  2883. //
  2884. // We have found a matching FT set
  2885. //
  2886. break;
  2887. }
  2888. }
  2889. }
  2890. }
  2891. if (FtSetInfo != NULL) {
  2892. //
  2893. // An FT Set exists that contains one of the supplied members.
  2894. // Create a new CFtInfo that contains nothing but the FT set and
  2895. // its members.
  2896. //
  2897. NewInfo = new CFtInfo(FtSetInfo);
  2898. if (NewInfo == NULL) {
  2899. SetLastError(ERROR_INVALID_DATA);
  2900. return(NULL);
  2901. }
  2902. } else {
  2903. //
  2904. // No FT Set contains any of the supplied members. Create a new CFtInfo
  2905. // that contains disk entries for each of the supplied members, but no
  2906. // FT set information. Any members which are members of an FT set will
  2907. // be excluded, since they have been assimilated into another set.
  2908. //
  2909. NewInfo = new CFtInfo((CFtInfoFtSet *)NULL);
  2910. if (NewInfo == NULL) {
  2911. SetLastError(ERROR_INVALID_DATA);
  2912. return(NULL);
  2913. }
  2914. //
  2915. // Find each member in the original FT info and add it to the new
  2916. // FT info.
  2917. //
  2918. for (i=0; ; i++) {
  2919. CFtInfoDisk *DiskInfo;
  2920. lpszSignature = ClRtlMultiSzEnum(lpszMemberList,
  2921. MultiSzLength,
  2922. i);
  2923. if (lpszSignature == NULL) {
  2924. break;
  2925. }
  2926. Signature = wcstoul(lpszSignature, NULL, 16);
  2927. if (OriginalInfo->FindFtSetInfo(Signature) != NULL) {
  2928. DISKLOG(("DiskGetFullFtSetInfo: removing member %08lx as it is already a member of another set.\n",Signature));
  2929. } else {
  2930. DiskInfo = OriginalInfo->FindDiskInfo(Signature);
  2931. if (DiskInfo != NULL) {
  2932. CFtInfoDisk *NewDisk;
  2933. NewDisk = new CFtInfoDisk(DiskInfo);
  2934. if ( NewDisk == NULL ) {
  2935. SetLastError(ERROR_INVALID_DATA);
  2936. return(NULL);
  2937. }
  2938. DISKLOG(("DiskGetFullFtSetInfo: adding member %08lx to new FT info\n",Signature));
  2939. NewInfo->SetDiskInfo(NewDisk);
  2940. } else {
  2941. DISKLOG(("DiskGetFullFtSetInfo: member %08lx not found in original FT info\n",Signature));
  2942. }
  2943. }
  2944. }
  2945. }
  2946. //
  2947. // Get the FT data
  2948. //
  2949. *pSize = NewInfo->GetSize();
  2950. DiskConfig = (PDISK_CONFIG_HEADER)LocalAlloc(LMEM_FIXED, *pSize);
  2951. if (DiskConfig == NULL) {
  2952. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2953. return(NULL);
  2954. }
  2955. NewInfo->GetData(DiskConfig);
  2956. delete NewInfo;
  2957. return((PFULL_FTSET_INFO)DiskConfig);
  2958. }
  2959. PFULL_FTSET_INFO
  2960. DiskGetFullFtSetInfoByIndex(
  2961. IN PFT_INFO FtInfo,
  2962. IN DWORD Index,
  2963. OUT LPDWORD pSize
  2964. )
  2965. /*++
  2966. Routine Description:
  2967. Serializes the complete information from an FT set in a form
  2968. suitable for saving to a file or the registry. These bits can
  2969. be restored with DiskSetFullFtSetInfo.
  2970. Arguments:
  2971. FtInfo - supplies the FT information
  2972. Index - Supplies the index
  2973. pSize - Returns the size of the FT information bytes.
  2974. Return Value:
  2975. A pointer to the serializable FT information if successful.
  2976. NULL on error
  2977. --*/
  2978. {
  2979. PDISK_CONFIG_HEADER DiskConfig;
  2980. DWORD Length;
  2981. CFtInfo *OriginalInfo;
  2982. CFtInfo *NewInfo;
  2983. CFtInfoFtSet *FtSetInfo;
  2984. OriginalInfo = (CFtInfo *)FtInfo;
  2985. FtSetInfo = OriginalInfo->EnumFtSetInfo(Index);
  2986. if (FtSetInfo == NULL) {
  2987. return(NULL);
  2988. }
  2989. //
  2990. // Create a new CFtInfo that contains nothing but the FT set and
  2991. // its members.
  2992. //
  2993. NewInfo = new CFtInfo(FtSetInfo);
  2994. if (NewInfo == NULL) {
  2995. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2996. return(NULL);
  2997. }
  2998. //
  2999. // Get the FT data
  3000. //
  3001. *pSize = NewInfo->GetSize();
  3002. DiskConfig = (PDISK_CONFIG_HEADER)LocalAlloc(LMEM_FIXED, *pSize);
  3003. if (DiskConfig == NULL) {
  3004. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3005. return(NULL);
  3006. }
  3007. NewInfo->GetData(DiskConfig);
  3008. delete NewInfo;
  3009. return((PFULL_FTSET_INFO)DiskConfig);
  3010. }
  3011. BOOL
  3012. DiskCheckFtSetLetters(
  3013. IN PFT_INFO FtInfo,
  3014. IN PFULL_FTSET_INFO Bytes,
  3015. OUT WCHAR *Letter
  3016. )
  3017. /*++
  3018. Routine Description:
  3019. This routine checks to see if the FT set info conflicts with
  3020. any already-defined sticky drive letters on the current system.
  3021. If a conflict is found, the conflicting drive letter is returned.
  3022. Arguments:
  3023. FtInfo - Supplies the FT information
  3024. Bytes - Supplies the information returned from DiskGetFullFtSetInfo
  3025. Return Value:
  3026. TRUE if no conflicts were detected
  3027. FALSE if a conflict was detected. If it returns FALSE, *Letter will be
  3028. set to the conflicting drive letter.
  3029. --*/
  3030. {
  3031. CFtInfo *RegistryInfo;
  3032. CFtInfo *NewInfo;
  3033. CFtInfoDisk *Disk;
  3034. CFtInfoFtSet *FtSet;
  3035. DWORD i;
  3036. RegistryInfo = (CFtInfo *)FtInfo;
  3037. NewInfo = new CFtInfo((PDISK_CONFIG_HEADER)Bytes);
  3038. if (NewInfo == NULL) {
  3039. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  3040. return ERROR_NOT_ENOUGH_MEMORY;
  3041. }
  3042. //
  3043. // Go through each physical disk in the FT set. For each one, see if
  3044. // there is a physical disk in the registry information with a different
  3045. // signature and the same drive letter. If so, we have a conflict.
  3046. //
  3047. FtSet = NewInfo->EnumFtSetInfo(0);
  3048. DISKASSERT(FtSet != NULL);
  3049. for (i=0; ; i++) {
  3050. Disk = NewInfo->EnumDiskInfo(i);
  3051. if (Disk == NULL) {
  3052. break;
  3053. }
  3054. //
  3055. // Go through each partition on this disk and look up the drive letter
  3056. // in the registry information.
  3057. //
  3058. CFtInfoPartition *Partition;
  3059. DWORD Index;
  3060. for (Index = 0; ; Index++) {
  3061. Partition = Disk->GetPartitionByIndex(Index);
  3062. if (Partition == NULL) {
  3063. break;
  3064. }
  3065. //
  3066. // If this partition has an assigned drive letter,
  3067. // check it out.
  3068. //
  3069. if (Partition->m_PartitionInfo->AssignDriveLetter) {
  3070. //
  3071. // See if there is an existing partition with this drive
  3072. // letter already in the registry information
  3073. //
  3074. CFtInfoPartition *Existing;
  3075. Existing = RegistryInfo->FindPartition(Partition->m_PartitionInfo->DriveLetter);
  3076. if (Existing != NULL) {
  3077. //
  3078. // If the existing partition has a different signature than
  3079. // the new partition, we have found a conflict.
  3080. //
  3081. if (Existing->m_ParentDisk->m_Signature !=
  3082. Partition->m_ParentDisk->m_Signature) {
  3083. *Letter = (WCHAR)Partition->m_PartitionInfo->DriveLetter;
  3084. delete NewInfo;
  3085. return(FALSE);
  3086. }
  3087. }
  3088. }
  3089. }
  3090. }
  3091. delete NewInfo;
  3092. return(TRUE);
  3093. }
  3094. DWORD
  3095. DiskSetFullFtSetInfo(
  3096. IN PFT_INFO FtInfo,
  3097. IN PFULL_FTSET_INFO Bytes
  3098. )
  3099. /*++
  3100. Routine Description:
  3101. Restores the complete information from an FT set to the DISK
  3102. key in the registry. The FT set information must have been
  3103. returned from DiskGetFullFtSetInfo.
  3104. Arguments:
  3105. FtInfo - supplies the FT information
  3106. Bytes - Supplies the information returned from DiskGetFullFtSetInfo.
  3107. Return Value:
  3108. ERROR_SUCCESS if successful.
  3109. Win32 error otherwise
  3110. --*/
  3111. {
  3112. CFtInfo *RegistryInfo;
  3113. CFtInfo *NewInfo;
  3114. CFtInfoFtSet *OldFtSet=NULL;
  3115. CFtInfoFtSet *NewFtSet=NULL;
  3116. CFtInfoDisk *Disk;
  3117. DWORD i;
  3118. BOOL Modified = FALSE;
  3119. DWORD Status;
  3120. RegistryInfo = (CFtInfo *)FtInfo;
  3121. NewInfo = new CFtInfo((PDISK_CONFIG_HEADER)Bytes);
  3122. if (NewInfo == NULL) {
  3123. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  3124. return ERROR_NOT_ENOUGH_MEMORY;
  3125. }
  3126. //
  3127. // If the new information contains an FT set, merge that into the
  3128. // current registry.
  3129. //
  3130. if (NewInfo->EnumFtSetInfo(0) != NULL) {
  3131. //
  3132. // Find an FT set in the registry that has a signature
  3133. // that is the same as one of those in the restored FT set.
  3134. //
  3135. NewFtSet = NewInfo->EnumFtSetInfo(0);
  3136. DISKASSERT(NewFtSet != NULL);
  3137. for (i=0; ; i++) {
  3138. Disk = NewInfo->EnumDiskInfo(i);
  3139. if (Disk == NULL) {
  3140. break;
  3141. }
  3142. //
  3143. // Try and find an existing FT set containing this signature
  3144. //
  3145. OldFtSet = RegistryInfo->FindFtSetInfo(Disk->m_Signature);
  3146. if (OldFtSet != NULL) {
  3147. break;
  3148. }
  3149. }
  3150. if (Disk == NULL) {
  3151. //
  3152. // No matching FT set was found. We can just add this one directly.
  3153. //
  3154. Modified = TRUE;
  3155. RegistryInfo->AddFtSetInfo(NewFtSet);
  3156. } else {
  3157. if (!(*OldFtSet == *NewFtSet)) {
  3158. Modified = TRUE;
  3159. RegistryInfo->AddFtSetInfo(NewFtSet, OldFtSet);
  3160. }
  3161. }
  3162. } else {
  3163. //
  3164. // There is no FT set in the new registry. This will happen if a mirror
  3165. // set gets broken. For each member in the new information, delete any
  3166. // FT sets that it is a part of and merge it into the registry.
  3167. //
  3168. for (i=0; ; i++) {
  3169. Disk = NewInfo->EnumDiskInfo(i);
  3170. if (Disk == NULL) {
  3171. break;
  3172. }
  3173. Modified = TRUE;
  3174. //
  3175. // Remove any FT sets containing this signature
  3176. //
  3177. OldFtSet = RegistryInfo->FindFtSetInfo(Disk->m_Signature);
  3178. if (OldFtSet != NULL) {
  3179. RegistryInfo->DeleteFtSetInfo(OldFtSet);
  3180. }
  3181. //
  3182. // Set the FT information for this member into the registry.
  3183. //
  3184. CFtInfoDisk *NewDisk;
  3185. NewDisk = new CFtInfoDisk(Disk);
  3186. if (NewDisk == NULL) {
  3187. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  3188. return ERROR_NOT_ENOUGH_MEMORY;
  3189. }
  3190. RegistryInfo->SetDiskInfo(NewDisk);
  3191. }
  3192. }
  3193. delete NewInfo;
  3194. if (Modified) {
  3195. //
  3196. // Commit these changes to the Disk key
  3197. //
  3198. DISKLOG(("DiskSetFullFtSetInfo: committing changes to registry\n"));
  3199. Status = RegistryInfo->CommitRegistryData();
  3200. } else {
  3201. DISKLOG(("DiskSetFullFtSetInfo: no changes detected\n"));
  3202. Status = ERROR_SUCCESS;
  3203. }
  3204. return(Status);
  3205. }
  3206. DWORD
  3207. DiskDeleteFullFtSetInfo(
  3208. IN PFT_INFO FtInfo,
  3209. IN LPCWSTR lpszMemberList
  3210. )
  3211. /*++
  3212. Routine Description:
  3213. Deletes any FT set information for the specified members. This is
  3214. used when a mirror set is broken.
  3215. Arguments:
  3216. FtInfo - supplies the FT information
  3217. lpszMemberList - Supplies the list of members whose FT information is to
  3218. be deleted.
  3219. Return Value:
  3220. ERROR_SUCCESS if successful
  3221. Win32 error code otherwise
  3222. --*/
  3223. {
  3224. CFtInfo *OriginalInfo;
  3225. DWORD Signature;
  3226. LPCWSTR lpszSignature;
  3227. DWORD MultiSzLength;
  3228. CFtInfoFtSet *FtSetInfo;
  3229. DWORD i;
  3230. BOOL Modified = FALSE;
  3231. DWORD Status;
  3232. OriginalInfo = (CFtInfo *)FtInfo;
  3233. MultiSzLength = ClRtlMultiSzLength(lpszMemberList);
  3234. //
  3235. // Go through each disk in the MultiSzLength and remove any FT information
  3236. // for it.
  3237. //
  3238. for (i=0; ; i++) {
  3239. lpszSignature = ClRtlMultiSzEnum(lpszMemberList,
  3240. MultiSzLength,
  3241. i);
  3242. if (lpszSignature == NULL) {
  3243. break;
  3244. }
  3245. Signature = wcstoul(lpszSignature, NULL, 16);
  3246. DISKLOG(("DiskDeleteFullFtSetInfo: deleting member %1!08lx!\n", Signature));
  3247. FtSetInfo = OriginalInfo->FindFtSetInfo(Signature);
  3248. if (FtSetInfo == NULL) {
  3249. DISKLOG(("DiskDeleteFullFtSetInfo: member %08lx is not in any FT set\n", Signature));
  3250. } else {
  3251. DISKLOG(("DiskDeleteFullFtSetInfo: member %08lx found. \n", Signature));
  3252. Modified = TRUE;
  3253. OriginalInfo->DeleteFtSetInfo(FtSetInfo);
  3254. }
  3255. }
  3256. if (Modified) {
  3257. //
  3258. // Commit these changes to the Disk key
  3259. //
  3260. DISKLOG(("DiskDeleteFullFtSetInfo: committing changes to registry\n"));
  3261. Status = OriginalInfo->CommitRegistryData();
  3262. } else {
  3263. DISKLOG(("DiskDeleteFullFtSetInfo: no changes detected\n"));
  3264. Status = ERROR_SUCCESS;
  3265. }
  3266. return(Status);
  3267. }
  3268. VOID
  3269. DiskMarkFullFtSetDirty(
  3270. IN PFULL_FTSET_INFO FtSet
  3271. )
  3272. /*++
  3273. Routine Description:
  3274. Changes the FT set information so that when it is mounted by FTDISK
  3275. the redundant information will be regenerated. This is necessary because
  3276. FTDISK only looks at the FT_REGISTRY dirty bit at boot time. By doing
  3277. this, we simulate a per-FT Set dirty bit that FT will respect when
  3278. sets are brought online after boot.
  3279. Magic algorithm from norbertk:
  3280. If (and only if) the entire FT set is healthy
  3281. If the set is a mirror
  3282. set state of second member to SyncRedundantCopy
  3283. If the set is a SWP
  3284. set state of first member to SyncRedundantCopy
  3285. Arguments:
  3286. FtSet - Supplies the FT set information returned from DiskGetFullFtSetInfo
  3287. Return Value:
  3288. None.
  3289. --*/
  3290. {
  3291. DWORD i;
  3292. CFtInfo *Info;
  3293. CFtInfoFtSet *FtSetInfo;
  3294. CFtInfoPartition *Partition;
  3295. USHORT FtType;
  3296. Info = new CFtInfo((PDISK_CONFIG_HEADER)FtSet);
  3297. if (Info == NULL) {
  3298. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  3299. return; // [REENGINEER] we avoided an AV but the caller won't know
  3300. }
  3301. FtSetInfo = Info->EnumFtSetInfo(0);
  3302. if (FtSetInfo != NULL) {
  3303. //
  3304. // Check all the members to see if they are all healthy.
  3305. //
  3306. for (i=0; ; i++) {
  3307. Partition = FtSetInfo->GetMemberByIndex(i);
  3308. if (Partition == NULL) {
  3309. break;
  3310. } else {
  3311. if (Partition->m_PartitionInfo->FtState != Healthy) {
  3312. break;
  3313. }
  3314. }
  3315. }
  3316. if (Partition == NULL) {
  3317. //
  3318. // All the members are marked healthy. Set one of them to
  3319. // SyncRedundantCopy to force a regen.
  3320. //
  3321. FtType = FtSetInfo->GetType();
  3322. if ((FtType == Mirror) || (FtType == StripeWithParity)) {
  3323. if (FtType == Mirror) {
  3324. Partition = FtSetInfo->GetMemberByIndex(1);
  3325. } else {
  3326. Partition = FtSetInfo->GetMemberByIndex(0);
  3327. }
  3328. if ( Partition != NULL ) {
  3329. Partition->m_PartitionInfo->FtState = SyncRedundantCopy;
  3330. }
  3331. //
  3332. // Get the modified FT data
  3333. //
  3334. Info->GetData((PDISK_CONFIG_HEADER)FtSet);
  3335. }
  3336. }
  3337. }
  3338. delete Info;
  3339. }
  3340. PFULL_DISK_INFO
  3341. DiskGetFullDiskInfo(
  3342. IN PFT_INFO DiskInfo,
  3343. IN DWORD Signature,
  3344. OUT LPDWORD pSize
  3345. )
  3346. /*++
  3347. Routine Description:
  3348. Serializes the complete information from a disk in a form
  3349. suitable for saving to a file or the registry. These bits can
  3350. be restored with DiskSetFullDiskInfo.
  3351. Arguments:
  3352. DiskInfo - supplies the disk information.
  3353. Signature - Supplies the signature.
  3354. pSize - Returns the size of the disk information in bytes.
  3355. Return Value:
  3356. A pointer to the serializable disk information if successful.
  3357. NULL on error
  3358. --*/
  3359. {
  3360. PDISK_CONFIG_HEADER DiskConfig;
  3361. DWORD Length;
  3362. CFtInfo *OriginalInfo;
  3363. CFtInfo *NewInfo;
  3364. CFtInfoDisk *FtDiskInfo;
  3365. CFtInfoDisk *NewDiskInfo;
  3366. OriginalInfo = (CFtInfo *)DiskInfo;
  3367. //
  3368. // First, try to find a disk that matches the supplied signature.
  3369. //
  3370. DISKLOG(("DiskGetFullDiskInfo: looking for signature %08lx\n", Signature));
  3371. FtDiskInfo = OriginalInfo->FindDiskInfo(Signature);
  3372. if (FtDiskInfo == NULL) {
  3373. DISKLOG(("DiskGetFullDiskInfo: signature %08lx not found\n", Signature));
  3374. SetLastError(ERROR_INVALID_DATA);
  3375. return(NULL);
  3376. }
  3377. //
  3378. // Create a new CFtInfo that contains no disk information.
  3379. //
  3380. NewInfo = new CFtInfo((CFtInfoFtSet *)NULL);
  3381. if (NewInfo == NULL) {
  3382. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3383. return(NULL);
  3384. }
  3385. NewDiskInfo = new CFtInfoDisk(FtDiskInfo);
  3386. if (NewDiskInfo == NULL) {
  3387. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3388. return(NULL);
  3389. }
  3390. //
  3391. // Disk info already exists. Use that data.
  3392. //
  3393. NewInfo->SetDiskInfo(NewDiskInfo);
  3394. //
  3395. // Get the disk data
  3396. //
  3397. *pSize = NewInfo->GetSize();
  3398. DiskConfig = (PDISK_CONFIG_HEADER)LocalAlloc(LMEM_FIXED, *pSize);
  3399. if (DiskConfig == NULL) {
  3400. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3401. return(NULL);
  3402. }
  3403. NewInfo->GetData(DiskConfig);
  3404. delete NewInfo;
  3405. return((PFULL_DISK_INFO)DiskConfig);
  3406. } // DiskGetFullDiskInfo
  3407. DWORD
  3408. DiskSetFullDiskInfo(
  3409. IN PFT_INFO DiskInfo,
  3410. IN PFULL_DISK_INFO Bytes
  3411. )
  3412. /*++
  3413. Routine Description:
  3414. Restores the complete information from a disk to the DISK
  3415. key in the registry. The disk information must have been
  3416. returned from DiskGetFullDiskInfo.
  3417. Arguments:
  3418. DiskInfo - supplies the disk information
  3419. Bytes - Supplies the information returned from DiskGetFullDiskInfo.
  3420. Return Value:
  3421. ERROR_SUCCESS if successful.
  3422. Win32 error otherwise
  3423. --*/
  3424. {
  3425. CFtInfo *RegistryInfo;
  3426. CFtInfo *NewInfo;
  3427. CFtInfoDisk *OldDisk=NULL;
  3428. CFtInfoDisk *NewDisk=NULL;
  3429. CFtInfoDisk *Disk;
  3430. DWORD Status;
  3431. RegistryInfo = (CFtInfo *)DiskInfo;
  3432. NewInfo = new CFtInfo((PDISK_CONFIG_HEADER)Bytes);
  3433. if (NewInfo == NULL) {
  3434. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  3435. return ERROR_NOT_ENOUGH_MEMORY;
  3436. }
  3437. DISKASSERT(NewInfo->EnumFtSetInfo(0) == NULL); // No FT sets
  3438. DISKASSERT(NewInfo->EnumDiskInfo(1) == NULL); // No more than 1 disk
  3439. //
  3440. // There is no FT set in the new registry. This will happen if a mirror
  3441. // set gets broken. For each member in the new information, delete any
  3442. // FT sets that it is a part of and merge it into the registry.
  3443. //
  3444. Disk = NewInfo->EnumDiskInfo(0);
  3445. if ( Disk == NULL ) {
  3446. DISKLOG(("DiskSetFullDiskInfo: no disks detected\n"));
  3447. return(ERROR_SUCCESS);
  3448. }
  3449. //
  3450. // Remove old data containing this signature
  3451. //
  3452. OldDisk = RegistryInfo->FindDiskInfo(Disk->m_Signature);
  3453. if (OldDisk != NULL) {
  3454. RegistryInfo->DeleteDiskInfo(Disk->m_Signature);
  3455. }
  3456. //
  3457. // Set the disk information for this disk into the registry.
  3458. //
  3459. NewDisk = new CFtInfoDisk(Disk);
  3460. if (NewDisk == NULL) {
  3461. DISKERR(IDS_GENERAL_FAILURE, ERROR_NOT_ENOUGH_MEMORY);
  3462. return ERROR_NOT_ENOUGH_MEMORY;
  3463. }
  3464. RegistryInfo->SetDiskInfo(NewDisk);
  3465. delete NewInfo;
  3466. //
  3467. // Commit these changes to the Disk key
  3468. //
  3469. DISKLOG(("DiskSetFullDiskInfo: committing changes to registry\n"));
  3470. Status = RegistryInfo->CommitRegistryData();
  3471. return(Status);
  3472. } // DiskSetFullDiskInfo
  3473. PFT_INFO
  3474. DiskGetFtInfoFromFullDiskinfo(
  3475. IN PFULL_DISK_INFO Bytes
  3476. )
  3477. {
  3478. CFtInfo* DiskInfo = new CFtInfo((PDISK_CONFIG_HEADER)Bytes);
  3479. if (DiskInfo) {
  3480. SetLastError(ERROR_SUCCESS);
  3481. } else {
  3482. SetLastError(ERROR_OUTOFMEMORY);
  3483. }
  3484. return reinterpret_cast<PFT_INFO>(DiskInfo);
  3485. } // DiskGetFtInfoFromFullDiskinfo //
  3486. DWORD
  3487. DiskAddDiskInfoEx(
  3488. IN PFT_INFO DiskInfo,
  3489. IN DWORD DiskIndex,
  3490. IN DWORD Signature,
  3491. IN DWORD Options
  3492. )
  3493. /*++
  3494. Routine Description:
  3495. Adds an NT4 style DISK registry entry for the specified
  3496. disk. Used to handle new disks being added to the system
  3497. after the cluster service has started. On NT4, windisk would
  3498. have been run to configure the disk and generate an entry
  3499. in the DISK key. On NT5, the DISK is no longer maintained by
  3500. the disk stack; most of the code in this module depends on
  3501. windisk maintaining this key. For NT5,
  3502. Arguments:
  3503. DiskIndex - the physical drive number for the new drive
  3504. Signature - the signature of the drive; used for sanity checking
  3505. Options - 0 or combination of the following:
  3506. DISKRTL_REPLACE_IF_EXISTS: Replace the information for the
  3507. disk if it is already exists
  3508. DISKRTL_COMMIT: If this flag is set then registry key System\DISK
  3509. is updated with a new information
  3510. Return Value:
  3511. ERROR_SUCCESS if successful.
  3512. Win32 error otherwise
  3513. --*/
  3514. {
  3515. DWORD status = ERROR_SUCCESS;
  3516. CFtInfo * diskInfo;
  3517. CFtInfoDisk * newDisk, * oldDisk;
  3518. WCHAR physDriveBuff[100];
  3519. HANDLE hDisk;
  3520. PDRIVE_LAYOUT_INFORMATION driveLayout;
  3521. diskInfo = (CFtInfo *)DiskInfo;
  3522. //
  3523. // read in the drive layout data for this new drive
  3524. //
  3525. (VOID) StringCchPrintf( physDriveBuff,
  3526. RTL_NUMBER_OF(physDriveBuff),
  3527. TEXT("\\\\.\\PhysicalDrive%d"),
  3528. DiskIndex );
  3529. hDisk = CreateFile(physDriveBuff,
  3530. GENERIC_READ,
  3531. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3532. NULL,
  3533. OPEN_EXISTING,
  3534. FILE_ATTRIBUTE_NORMAL,
  3535. NULL);
  3536. if (hDisk == INVALID_HANDLE_VALUE) {
  3537. return GetLastError();
  3538. }
  3539. if (ClRtlGetDriveLayoutTable( hDisk, &driveLayout, NULL )) {
  3540. //
  3541. // make sure signatures line up and that a
  3542. // description for this disk doesn't already exist
  3543. //
  3544. if ( Signature == driveLayout->Signature ) {
  3545. oldDisk = diskInfo->FindDiskInfo(Signature);
  3546. if (oldDisk != NULL) {
  3547. if (Options & DISKRTL_REPLACE_IF_EXISTS) {
  3548. diskInfo->DeleteDiskInfo(Signature);
  3549. oldDisk = NULL;
  3550. }
  3551. }
  3552. if ( oldDisk == NULL ) {
  3553. //
  3554. // Pull in a copy of the existing data in the registry
  3555. // and initialize a new disk and its associated partitions.
  3556. //
  3557. newDisk = new CFtInfoDisk( driveLayout );
  3558. if ( newDisk != NULL ) {
  3559. //
  3560. // add the disk to the current database and
  3561. // commit the updated database to the registry
  3562. //
  3563. diskInfo->AddDiskInfo( newDisk );
  3564. if (Options & DISKRTL_COMMIT) {
  3565. status = diskInfo->CommitRegistryData();
  3566. } else {
  3567. status = ERROR_SUCCESS;
  3568. }
  3569. } else {
  3570. status = ERROR_OUTOFMEMORY;
  3571. }
  3572. } else {
  3573. status = ERROR_ALREADY_EXISTS;
  3574. }
  3575. } else {
  3576. status = ERROR_INVALID_PARAMETER;
  3577. }
  3578. LocalFree( driveLayout );
  3579. } else {
  3580. status = GetLastError();
  3581. }
  3582. CloseHandle( hDisk );
  3583. return status;
  3584. } // DiskAddDiskEx
  3585. DWORD
  3586. DiskAddDriveLetterEx(
  3587. IN PFT_INFO DiskInfo,
  3588. IN DWORD Signature,
  3589. IN LARGE_INTEGER StartingOffset,
  3590. IN LARGE_INTEGER PartitionLength,
  3591. IN UCHAR DriveLetter,
  3592. IN DWORD Options
  3593. )
  3594. /*++
  3595. Routine Description:
  3596. Add a drive letter to the specified partition
  3597. Arguments:
  3598. Signature - the signature of the drive; used for sanity checking
  3599. StartingOffset
  3600. PartitionLength - describes which partition
  3601. DriveLetter - letter to be associated with this partition
  3602. Options - if DISKRTL_COMMIT flag is set then registry System\DISK
  3603. is immedately updated with a new information
  3604. Return Value:
  3605. ERROR_SUCCESS if successful.
  3606. Win32 error otherwise
  3607. --*/
  3608. {
  3609. DWORD status;
  3610. CFtInfo * diskInfo;
  3611. CFtInfoPartition * partInfo;
  3612. diskInfo = (CFtInfo *)DiskInfo;
  3613. partInfo = diskInfo->FindPartition( Signature, StartingOffset, PartitionLength );
  3614. if ( partInfo != NULL ) {
  3615. partInfo->MakeSticky( DriveLetter );
  3616. if (Options & DISKRTL_COMMIT) {
  3617. status = diskInfo->CommitRegistryData();
  3618. } else {
  3619. status = ERROR_SUCCESS;
  3620. }
  3621. } else {
  3622. status = ERROR_INVALID_PARAMETER;
  3623. }
  3624. return status;
  3625. }
  3626. DWORD
  3627. DiskCommitFtInfo(
  3628. IN PFT_INFO FtInfo
  3629. )
  3630. {
  3631. CFtInfo * info = reinterpret_cast<CFtInfo*>( FtInfo );
  3632. DWORD status = info->CommitRegistryData();
  3633. return status;
  3634. }
  3635. PFT_DISK_INFO
  3636. FtInfo_GetFtDiskInfoBySignature(
  3637. IN PFT_INFO FtInfo,
  3638. IN DWORD Signature
  3639. )
  3640. /*++
  3641. Routine Description:
  3642. Finds an information for a particular drive
  3643. Arguments:
  3644. DiskInfo - supplies the disk information
  3645. Signature - describes which drive
  3646. Return Value:
  3647. NULL - if not found
  3648. CFtInfoDisk - otherwise
  3649. --*/
  3650. {
  3651. CFtInfo* Info = reinterpret_cast<CFtInfo *>(FtInfo);
  3652. PFT_DISK_INFO result = reinterpret_cast<PFT_DISK_INFO>(Info->FindDiskInfo(Signature));
  3653. if (result == 0) {
  3654. SetLastError(ERROR_FILE_NOT_FOUND);
  3655. }
  3656. return result;
  3657. } // FtInfo_GetFtDiskInfoBySignature //
  3658. DISK_PARTITION UNALIGNED *
  3659. FtDiskInfo_GetPartitionInfoByIndex(
  3660. IN PFT_DISK_INFO DiskInfo,
  3661. IN DWORD Index
  3662. )
  3663. /*++
  3664. Routine Description:
  3665. Get Drive Letter for a partition specified by an offset
  3666. Arguments:
  3667. DiskInfo - supplies the disk information
  3668. index - describes which partition (0 based)
  3669. Return Value:
  3670. PDISK_PARTITION stucture or NULL
  3671. if return value is NULL, SetLastError value is set as follows:
  3672. ERROR_FILE_NOT_FOUND: if partition cannot be found
  3673. ERROR_INVALID_HANDLE: if partition is found, but m_PartitionInfo is unassigned
  3674. --*/
  3675. {
  3676. CFtInfoDisk* Info = reinterpret_cast<CFtInfoDisk*>(DiskInfo);
  3677. CFtInfoPartition* Partition = Info->GetPartitionByIndex( Index );
  3678. if (Partition == 0) {
  3679. SetLastError(ERROR_FILE_NOT_FOUND);
  3680. return NULL;
  3681. }
  3682. if (Partition->m_PartitionInfo == 0) {
  3683. SetLastError(ERROR_INVALID_HANDLE);
  3684. return 0;
  3685. }
  3686. return Partition->m_PartitionInfo;
  3687. } // FtDiskInfo_GetDriveLetterByIndex //
  3688. DWORD
  3689. FtDiskInfo_GetPartitionCount(
  3690. IN PFT_DISK_INFO DiskInfo
  3691. )
  3692. {
  3693. CFtInfoDisk* Info = reinterpret_cast<CFtInfoDisk*>(DiskInfo);
  3694. return Info->m_PartitionCount;
  3695. } // FtDiskInfo_GetPartitionCount //
  3696. } // extern C