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

4593 lines
117 KiB

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