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.

1006 lines
23 KiB

  1. /*++
  2. Copyright (C) 2000 Microsoft Corporation
  3. Module Name:
  4. ftcomp.cpp
  5. Abstract:
  6. This compatibility dll is used by winnt32.exe in order to decide
  7. whether the installation process should be aborted because of FT
  8. sets present in the system.
  9. Author:
  10. Cristian Teodorescu (cristiat) 6-July-2000
  11. Environment:
  12. compatibility dll for winnt32.exe
  13. Notes:
  14. Revision History:
  15. --*/
  16. #include <initguid.h>
  17. #include <winnt32.h>
  18. #include <ntddft.h>
  19. #include <ntddft2.h>
  20. #include "ftcomp.h"
  21. #include "ftcomprc.h"
  22. HINSTANCE g_hinst;
  23. WCHAR g_FTCOMP50_ERROR_HTML_FILE[] = L"compdata\\ftcomp1.htm";
  24. WCHAR g_FTCOMP50_ERROR_TEXT_FILE[] = L"compdata\\ftcomp1.txt";
  25. WCHAR g_FTCOMP40_ERROR_HTML_FILE[] = L"compdata\\ftcomp2.htm";
  26. WCHAR g_FTCOMP40_ERROR_TEXT_FILE[] = L"compdata\\ftcomp2.txt";
  27. WCHAR g_FTCOMP40_WARNING_HTML_FILE[] = L"compdata\\ftcomp3.htm";
  28. WCHAR g_FTCOMP40_WARNING_TEXT_FILE[] = L"compdata\\ftcomp3.txt";
  29. extern "C"
  30. BOOL WINAPI
  31. DllMain(
  32. HINSTANCE hInstance,
  33. DWORD dwReasonForCall,
  34. LPVOID lpReserved
  35. )
  36. {
  37. BOOL status = TRUE;
  38. switch( dwReasonForCall )
  39. {
  40. case DLL_PROCESS_ATTACH:
  41. g_hinst = hInstance;
  42. DisableThreadLibraryCalls(hInstance);
  43. break;
  44. case DLL_PROCESS_DETACH:
  45. case DLL_THREAD_ATTACH:
  46. case DLL_THREAD_DETACH:
  47. break;
  48. }
  49. return status;
  50. }
  51. BOOL WINAPI
  52. FtCompatibilityCheckError(
  53. IN PCOMPAIBILITYCALLBACK CompatibilityCallback,
  54. IN LPVOID Context
  55. )
  56. /*++
  57. Routine Description:
  58. This routine is called by winnt32.exe in order to decide whether
  59. the installation process should be aborted because of FT sets present
  60. in a Windows 2000 system or later. It also aborts the installation on
  61. NT 4.0 systems if the boot/system/pagefile volumes are FT sets
  62. Arguments:
  63. CompatibilityCallback - Supplies the winnt32 callback
  64. Context - Supplies the compatibility context
  65. Return Value:
  66. FALSE if the installation can continue
  67. TRUE if the installation must be aborted
  68. --*/
  69. {
  70. OSVERSIONINFO osvi;
  71. BOOL ftPresent;
  72. BOOL result;
  73. COMPATIBILITY_ENTRY ce;
  74. WCHAR description[100];
  75. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  76. if (!GetVersionEx(&osvi)) {
  77. return FALSE;
  78. }
  79. if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT ||
  80. osvi.dwMajorVersion < 4) {
  81. return FALSE;
  82. }
  83. if (osvi.dwMajorVersion == 4) {
  84. //
  85. // On NT 4.0 look for boot/system/pagefile FT sets
  86. //
  87. result = FtBootSystemPagefilePresent40(&ftPresent);
  88. } else {
  89. //
  90. // On Windows 2000 or later look for any FT sets.
  91. //
  92. result = FtPresent50(&ftPresent);
  93. }
  94. if (result && !ftPresent) {
  95. //
  96. // The setup can continue.
  97. //
  98. return FALSE;
  99. }
  100. //
  101. // FT sets are present in the system or a fatal error occured.
  102. // Queue the incompatibility error
  103. //
  104. ZeroMemory((PVOID) &ce, sizeof(COMPATIBILITY_ENTRY));
  105. if (osvi.dwMajorVersion == 4) {
  106. if (!LoadString(g_hinst, FTCOMP_STR_ERROR40_DESCRIPTION, description, 100)) {
  107. description[0] = 0;
  108. }
  109. ce.HtmlName = g_FTCOMP40_ERROR_HTML_FILE;
  110. ce.TextName = g_FTCOMP40_ERROR_TEXT_FILE;
  111. } else {
  112. if (!LoadString(g_hinst, FTCOMP_STR_ERROR50_DESCRIPTION, description, 100)) {
  113. description[0] = 0;
  114. }
  115. ce.HtmlName = g_FTCOMP50_ERROR_HTML_FILE;
  116. ce.TextName = g_FTCOMP50_ERROR_TEXT_FILE;
  117. }
  118. ce.Description = description;
  119. ce.RegKeyName = NULL;
  120. ce.RegValName = NULL;
  121. ce.RegValDataSize = 0;
  122. ce.RegValData = NULL;
  123. ce.SaveValue = NULL;
  124. ce.Flags = 0;
  125. CompatibilityCallback(&ce, Context);
  126. return TRUE;
  127. }
  128. BOOL WINAPI
  129. FtCompatibilityCheckWarning(
  130. IN PCOMPAIBILITYCALLBACK CompatibilityCallback,
  131. IN LPVOID Context
  132. )
  133. /*++
  134. Routine Description:
  135. This routine is called by winnt32.exe in order to decide whether the user
  136. should be warned about the presence of FT sets in a Windows NT 4.0 system
  137. Arguments:
  138. CompatibilityCallback - Supplies the winnt32 callback
  139. Context - Supplies the compatibility context
  140. Return Value:
  141. FALSE if the installation can continue
  142. TRUE if the installation must be aborted
  143. --*/
  144. {
  145. OSVERSIONINFO osvi;
  146. BOOL ftPresent;
  147. BOOL result;
  148. COMPATIBILITY_ENTRY ce;
  149. WCHAR description[100];
  150. //
  151. // This function is supposed to work only on Windows NT 4.0
  152. //
  153. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  154. if (!GetVersionEx(&osvi)) {
  155. return FALSE;
  156. }
  157. if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT ||
  158. osvi.dwMajorVersion != 4) {
  159. return FALSE;
  160. }
  161. result = FtPresent40(&ftPresent);
  162. if (result && !ftPresent) {
  163. //
  164. // No FT sets are present in the system. The setup can continue.
  165. //
  166. return FALSE;
  167. }
  168. //
  169. // FT sets are present in the system or a fatal error occured.
  170. // Queue the incompatibility warning
  171. //
  172. if (!LoadString(g_hinst, FTCOMP_STR_WARNING40_DESCRIPTION, description, 100)) {
  173. description[0] = 0;
  174. }
  175. ZeroMemory((PVOID) &ce, sizeof(COMPATIBILITY_ENTRY));
  176. ce.Description = description;
  177. ce.HtmlName = g_FTCOMP40_WARNING_HTML_FILE;
  178. ce.TextName = g_FTCOMP40_WARNING_TEXT_FILE;
  179. ce.RegKeyName = NULL;
  180. ce.RegValName = NULL;
  181. ce.RegValDataSize = 0;
  182. ce.RegValData = NULL;
  183. ce.SaveValue = NULL;
  184. ce.Flags = 0;
  185. CompatibilityCallback(&ce, Context);
  186. return TRUE;
  187. }
  188. BOOL
  189. FtPresent50(
  190. PBOOL FtPresent
  191. )
  192. /*++
  193. Routine Description:
  194. This routine looks for FT volumes on a Window 2000 or later
  195. system.
  196. Arguments:
  197. FtPresent - is set to true if FT sets are detected in the system
  198. Return Value:
  199. TRUE if the function is successful
  200. FALSE if some fatal error occured
  201. --*/
  202. {
  203. HANDLE handle;
  204. FT_ENUMERATE_LOGICAL_DISKS_OUTPUT output;
  205. BOOL result;
  206. DWORD bytes;
  207. *FtPresent = FALSE;
  208. handle = CreateFile(L"\\\\.\\FtControl", GENERIC_READ | GENERIC_WRITE,
  209. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  210. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  211. INVALID_HANDLE_VALUE);
  212. if (handle == INVALID_HANDLE_VALUE) {
  213. return FALSE;
  214. }
  215. memset(&output, 0, sizeof(output));
  216. result = DeviceIoControl(handle, FT_ENUMERATE_LOGICAL_DISKS, NULL, 0,
  217. &output, sizeof(output), &bytes, NULL);
  218. CloseHandle(handle);
  219. if (!result && GetLastError() != ERROR_MORE_DATA) {
  220. return FALSE;
  221. }
  222. if (output.NumberOfRootLogicalDisks > 0) {
  223. *FtPresent = TRUE;
  224. }
  225. return TRUE;
  226. }
  227. BOOL
  228. FtPresent40(
  229. PBOOL FtPresent
  230. )
  231. /*++
  232. Routine Description:
  233. This routine looks for NTFT partitions on a Window NT 4.0 system
  234. Arguments:
  235. FtPresent - is set to true if FT sets are detected in the system
  236. Return Value:
  237. TRUE if the function is successful
  238. FALSE if some fatal error occured
  239. --*/
  240. {
  241. HKEY hkey;
  242. DWORD registrySize;
  243. PDISK_CONFIG_HEADER registry;
  244. PDISK_REGISTRY diskRegistry;
  245. ULONG i;
  246. WCHAR devicePath[50];
  247. NTSTATUS status;
  248. HANDLE hdev;
  249. *FtPresent = FALSE;
  250. //
  251. // Get the ftdisk database from registry.
  252. // Key: HKLM\System\Disk
  253. // Value: Information
  254. //
  255. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\Disk", 0, KEY_QUERY_VALUE, &hkey) !=
  256. ERROR_SUCCESS) {
  257. return TRUE;
  258. }
  259. if (RegQueryValueEx(hkey, L"Information", NULL, NULL, NULL, &registrySize) !=
  260. ERROR_SUCCESS) {
  261. RegCloseKey(hkey);
  262. return TRUE;
  263. }
  264. registry = (PDISK_CONFIG_HEADER) LocalAlloc(0, registrySize);
  265. if (!registry) {
  266. RegCloseKey(hkey);
  267. return FALSE;
  268. }
  269. if (RegQueryValueEx(hkey, L"Information", NULL, NULL, (LPBYTE) registry, &registrySize) !=
  270. ERROR_SUCCESS) {
  271. LocalFree(registry);
  272. RegCloseKey(hkey);
  273. return TRUE;
  274. }
  275. RegCloseKey(hkey);
  276. //
  277. // If no FT volume info is present in the registry database we are done
  278. //
  279. if (registry->FtInformationSize == 0) {
  280. LocalFree(registry);
  281. return TRUE;
  282. }
  283. diskRegistry = (PDISK_REGISTRY)
  284. ((PUCHAR) registry + registry->DiskInformationOffset);
  285. //
  286. // Enumerate all disks present in the system by opening \Device\HarddiskX\Partition0
  287. // in sequence starting with disk 0. Stop when getting STATUS_OBJECT_PATH_NOT_FOUND
  288. //
  289. //
  290. for (i = 0;; i++) {
  291. //
  292. // Open the device
  293. //
  294. swprintf(devicePath, L"\\Device\\Harddisk%lu\\Partition0", i);
  295. status = OpenDevice(devicePath, &hdev);
  296. if (status == STATUS_OBJECT_PATH_NOT_FOUND) {
  297. break;
  298. }
  299. if (!NT_SUCCESS(status) || hdev == NULL ||
  300. hdev == INVALID_HANDLE_VALUE) {
  301. // inaccessible device
  302. continue;
  303. }
  304. //
  305. // Look for FT partitions on disk
  306. //
  307. if (!FtPresentOnDisk40(hdev, diskRegistry, FtPresent)) {
  308. CloseHandle(hdev);
  309. return FALSE;
  310. }
  311. CloseHandle(hdev);
  312. if (*FtPresent) {
  313. break;
  314. }
  315. }
  316. LocalFree(registry);
  317. return TRUE;
  318. }
  319. BOOL
  320. FtBootSystemPagefilePresent40(
  321. PBOOL FtPresent
  322. )
  323. /*++
  324. Routine Description:
  325. This routine looks for FT sets that are boot/system/pagefile volumes
  326. on a NT 4.0 system
  327. Arguments:
  328. FtPresent - is set to true if boot/system/pagefile FT sets are detected
  329. in the system
  330. Return Value:
  331. TRUE if the function is successful
  332. FALSE if some fatal error occured
  333. --*/
  334. {
  335. HKEY hkey;
  336. DWORD registrySize;
  337. PDISK_CONFIG_HEADER registry;
  338. PDISK_REGISTRY diskRegistry;
  339. WCHAR buffer[MAX_PATH + 1];
  340. NTSTATUS status;
  341. UCHAR genericBuffer[0x10000];
  342. PSYSTEM_PAGEFILE_INFORMATION pageFileInfo;
  343. PWCHAR p;
  344. WCHAR bootDL = 0, systemDL = 0;
  345. WCHAR dl;
  346. *FtPresent = FALSE;
  347. //
  348. // Get the ftdisk database from registry.
  349. // Key: HKLM\System\Disk
  350. // Value: Information
  351. //
  352. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\Disk", 0, KEY_QUERY_VALUE, &hkey) !=
  353. ERROR_SUCCESS) {
  354. return TRUE;
  355. }
  356. if (RegQueryValueEx(hkey, L"Information", NULL, NULL, NULL, &registrySize) !=
  357. ERROR_SUCCESS) {
  358. RegCloseKey(hkey);
  359. return TRUE;
  360. }
  361. registry = (PDISK_CONFIG_HEADER) LocalAlloc(0, registrySize);
  362. if (!registry) {
  363. RegCloseKey(hkey);
  364. return FALSE;
  365. }
  366. if (RegQueryValueEx(hkey, L"Information", NULL, NULL, (LPBYTE) registry, &registrySize) !=
  367. ERROR_SUCCESS) {
  368. LocalFree(registry);
  369. RegCloseKey(hkey);
  370. return TRUE;
  371. }
  372. RegCloseKey(hkey);
  373. //
  374. // If no FT volume info is present in the registry database we are done
  375. //
  376. if (registry->FtInformationSize == 0) {
  377. LocalFree(registry);
  378. return TRUE;
  379. }
  380. diskRegistry = (PDISK_REGISTRY)
  381. ((PUCHAR) registry + registry->DiskInformationOffset);
  382. //
  383. // Check the boot volume
  384. //
  385. if (!GetSystemDirectory(buffer, MAX_PATH)) {
  386. goto system;
  387. }
  388. if (buffer[1] != L':') {
  389. goto system;
  390. }
  391. bootDL = (WCHAR) tolower(buffer[0]);
  392. if (IsFtSet40(bootDL, diskRegistry)) {
  393. *FtPresent = TRUE;
  394. goto exit;
  395. }
  396. system:
  397. //
  398. // Check the system volume
  399. //
  400. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\Setup", 0, KEY_QUERY_VALUE, &hkey) !=
  401. ERROR_SUCCESS) {
  402. goto paging;
  403. }
  404. registrySize = MAX_PATH * sizeof(WCHAR);
  405. if (RegQueryValueEx(hkey, L"SystemPartition", NULL, NULL, (LPBYTE) buffer, &registrySize) !=
  406. ERROR_SUCCESS) {
  407. RegCloseKey(hkey);
  408. goto paging;
  409. }
  410. RegCloseKey(hkey);
  411. if (!GetDeviceDriveLetter(buffer, &systemDL)) {
  412. goto paging;
  413. }
  414. systemDL = (WCHAR) tolower(systemDL);
  415. if (systemDL == bootDL) {
  416. // already checked this drive letter
  417. goto paging;
  418. }
  419. if (IsFtSet40(systemDL, diskRegistry)) {
  420. *FtPresent = TRUE;
  421. goto exit;
  422. }
  423. paging:
  424. //
  425. // Check the paging volumes
  426. //
  427. if (!NT_SUCCESS(NtQuerySystemInformation(
  428. SystemPageFileInformation,
  429. genericBuffer, sizeof(genericBuffer),
  430. NULL))) {
  431. goto exit;
  432. }
  433. pageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION) genericBuffer;
  434. while (TRUE) {
  435. //
  436. // Since the format of the pagefile name generally
  437. // looks something like "\DosDevices\x:\pagefile.sys",
  438. // just use the first character before the column
  439. // and assume that's the drive letter.
  440. //
  441. for (p = pageFileInfo->PageFileName.Buffer;
  442. p < pageFileInfo->PageFileName.Buffer + pageFileInfo->PageFileName.Length
  443. && *p != L':'; p++);
  444. if (p < pageFileInfo->PageFileName.Buffer + pageFileInfo->PageFileName.Length &&
  445. p > pageFileInfo->PageFileName.Buffer) {
  446. p--;
  447. dl = (WCHAR) tolower(*p);
  448. if (dl >= L'a' && dl <= L'z') {
  449. //
  450. // Found the drive letter of a paging volume
  451. //
  452. if (dl != bootDL && dl != systemDL) {
  453. if (IsFtSet40(dl, diskRegistry)) {
  454. *FtPresent = TRUE;
  455. goto exit;
  456. }
  457. }
  458. }
  459. }
  460. if (!pageFileInfo->NextEntryOffset) {
  461. break;
  462. }
  463. pageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR) pageFileInfo +
  464. pageFileInfo->NextEntryOffset);
  465. }
  466. exit:
  467. LocalFree(registry);
  468. return TRUE;
  469. }
  470. NTSTATUS
  471. OpenDevice(
  472. PWSTR DeviceName,
  473. PHANDLE Handle
  474. )
  475. /*++
  476. Routine Description:
  477. This routine opens a device for read
  478. Arguments:
  479. DeviceName - supplies the device name
  480. Handle - returns a handle to the open device
  481. Return Value:
  482. NTSTATUS
  483. --*/
  484. {
  485. OBJECT_ATTRIBUTES oa;
  486. NTSTATUS status;
  487. IO_STATUS_BLOCK statusBlock;
  488. UNICODE_STRING unicodeName;
  489. int i;
  490. status = RtlCreateUnicodeString(&unicodeName, DeviceName);
  491. if (!NT_SUCCESS(status)) {
  492. return status;
  493. }
  494. memset(&statusBlock, 0, sizeof(IO_STATUS_BLOCK));
  495. memset(&oa, 0, sizeof(OBJECT_ATTRIBUTES));
  496. oa.Length = sizeof(OBJECT_ATTRIBUTES);
  497. oa.ObjectName = &unicodeName;
  498. oa.Attributes = OBJ_CASE_INSENSITIVE;
  499. //
  500. // If a sharing violation occurs, retry it for
  501. // max. 10 seconds
  502. //
  503. for (i = 0; i < 5; i++) {
  504. status = NtOpenFile(Handle, SYNCHRONIZE | GENERIC_READ,
  505. &oa, &statusBlock,
  506. FILE_SHARE_READ | FILE_SHARE_WRITE,
  507. FILE_SYNCHRONOUS_IO_ALERT);
  508. if (status == STATUS_SHARING_VIOLATION) {
  509. Sleep(2000);
  510. } else {
  511. break;
  512. }
  513. }
  514. RtlFreeUnicodeString(&unicodeName);
  515. return status;
  516. }
  517. PDISK_PARTITION
  518. FindPartitionInRegistry40(
  519. PDISK_REGISTRY DiskRegistry,
  520. ULONG Signature,
  521. LONGLONG Offset
  522. )
  523. /*++
  524. Routine Description:
  525. This routine looks for a gicen partition into the NT 4.0 ftdisk registry
  526. database
  527. Arguments:
  528. DiskRegistry - supplies the ftdisk registry database
  529. Signature - supplies the signature of the disk where the partition resides
  530. Offset - supplies the offset of the partition
  531. Return Value:
  532. The partition structure in the registry database.
  533. NULL if the partition is not there.
  534. --*/
  535. {
  536. PDISK_DESCRIPTION diskDescription;
  537. USHORT i, j;
  538. PDISK_PARTITION diskPartition;
  539. LONGLONG tmp;
  540. diskDescription = &DiskRegistry->Disks[0];
  541. for (i = 0; i < DiskRegistry->NumberOfDisks; i++) {
  542. if (diskDescription->Signature == Signature) {
  543. for (j = 0; j < diskDescription->NumberOfPartitions; j++) {
  544. diskPartition = &diskDescription->Partitions[j];
  545. memcpy(&tmp, &diskPartition->StartingOffset.QuadPart,
  546. sizeof(LONGLONG));
  547. if (tmp == Offset) {
  548. return diskPartition;
  549. }
  550. }
  551. }
  552. diskDescription = (PDISK_DESCRIPTION) &diskDescription->
  553. Partitions[diskDescription->NumberOfPartitions];
  554. }
  555. return NULL;
  556. }
  557. BOOL
  558. FtPresentOnDisk40(
  559. HANDLE Handle,
  560. PDISK_REGISTRY DiskRegistry,
  561. PBOOL FtPresent
  562. )
  563. /*++
  564. Routine Description:
  565. This routine looks for FT partitions on a disk
  566. Arguments:
  567. Handle - supplies a handle to the open disk
  568. DiskRegistry - supplies the ftdisk registry database
  569. FtPresent - is set to true if FT partitions are detected on the disk
  570. Return Value:
  571. TRUE if the function is successful
  572. FALSE if some fatal error occured
  573. --*/
  574. {
  575. PDRIVE_LAYOUT_INFORMATION layout;
  576. DWORD layoutSize;
  577. NTSTATUS status;
  578. IO_STATUS_BLOCK statusBlock;
  579. ULONG i;
  580. PPARTITION_INFORMATION partInfo;
  581. PDISK_PARTITION diskPartition;
  582. *FtPresent = FALSE;
  583. //
  584. // Allocate memory for IOCTL_GET_DRIVE_LAYOUT
  585. //
  586. layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry) +
  587. 32 * sizeof(PARTITION_INFORMATION);
  588. layout = (PDRIVE_LAYOUT_INFORMATION) LocalAlloc(0, layoutSize);
  589. if (!layout) {
  590. return FALSE;
  591. }
  592. //
  593. // Read the drive layout
  594. //
  595. while (1) {
  596. status = NtDeviceIoControlFile(Handle, 0, NULL, NULL,
  597. &statusBlock,
  598. IOCTL_DISK_GET_DRIVE_LAYOUT,
  599. NULL, 0,
  600. layout, layoutSize);
  601. if (status != STATUS_BUFFER_TOO_SMALL) {
  602. break;
  603. }
  604. layoutSize += 32 * sizeof(PARTITION_INFORMATION);
  605. if (layout) {
  606. LocalFree(layout);
  607. }
  608. layout = (PDRIVE_LAYOUT_INFORMATION) LocalAlloc(0, layoutSize);
  609. if (!layout) {
  610. return FALSE;
  611. }
  612. }
  613. if (!NT_SUCCESS(status)) {
  614. // inaccessible device. Act like it has no FT volumes
  615. LocalFree(layout);
  616. return TRUE;
  617. }
  618. //
  619. // Look for FT partitions
  620. //
  621. for (i = 0; i < layout->PartitionCount; i++) {
  622. //
  623. // We're looking after recognized partitions marked
  624. // with the 0x80 flag
  625. //
  626. partInfo = &(layout->PartitionEntry[i]);
  627. if (!IsFTPartition(partInfo->PartitionType)) {
  628. continue;
  629. }
  630. //
  631. // Check whether the partition is marked as a member
  632. // of an FT volume in the registry database
  633. //
  634. diskPartition = FindPartitionInRegistry40(
  635. DiskRegistry, layout->Signature,
  636. partInfo->StartingOffset.QuadPart);
  637. if (!diskPartition) {
  638. continue;
  639. }
  640. if (diskPartition->FtType != NotAnFtMember) {
  641. *FtPresent = TRUE;
  642. break;
  643. }
  644. }
  645. LocalFree(layout);
  646. return TRUE;
  647. }
  648. BOOL
  649. IsFtSet40(
  650. WCHAR DriveLetter,
  651. PDISK_REGISTRY DiskRegistry
  652. )
  653. /*++
  654. Routine Description:
  655. This routine cheks whether the given drive letter belongs to
  656. an FT set
  657. Arguments:
  658. DriveLetter - supplies a drive letter
  659. DiskRegistry - supplies the ftdisk registry database
  660. Return Value:
  661. TRUE if the function is the drive letter belongs to an FT set
  662. --*/
  663. {
  664. HANDLE handle;
  665. NTSTATUS status;
  666. WCHAR deviceName[20];
  667. PARTITION_INFORMATION partInfo;
  668. BOOL b;
  669. DWORD bytes;
  670. PDISK_DESCRIPTION diskDescription;
  671. PDISK_PARTITION diskPartition;
  672. USHORT i, j;
  673. //
  674. // Open the volume and get its "partition" type
  675. // If the NTFT flag is not set the volume is not an FT set
  676. //
  677. wsprintf(deviceName, L"\\DosDevices\\%c:", DriveLetter);
  678. status = OpenDevice(deviceName, &handle);
  679. if (!NT_SUCCESS(status)) {
  680. return FALSE;
  681. }
  682. b = DeviceIoControl(handle, IOCTL_DISK_GET_PARTITION_INFO,
  683. NULL, 0, &partInfo, sizeof(partInfo),
  684. &bytes, NULL);
  685. CloseHandle(handle);
  686. if (!b) {
  687. return FALSE;
  688. }
  689. if (!IsFTPartition(partInfo.PartitionType)) {
  690. return FALSE;
  691. }
  692. //
  693. // Look for the drive letter in the FT registry. See if it belongs
  694. // to an FT set
  695. //
  696. diskDescription = &DiskRegistry->Disks[0];
  697. for (i = 0; i < DiskRegistry->NumberOfDisks; i++) {
  698. for (j = 0; j < diskDescription->NumberOfPartitions; j++) {
  699. diskPartition = &diskDescription->Partitions[j];
  700. if (diskPartition->AssignDriveLetter &&
  701. tolower(diskPartition->DriveLetter) == tolower(DriveLetter) &&
  702. diskPartition->FtType != NotAnFtMember) {
  703. return TRUE;
  704. }
  705. }
  706. diskDescription = (PDISK_DESCRIPTION) &diskDescription->
  707. Partitions[diskDescription->NumberOfPartitions];
  708. }
  709. return FALSE;
  710. }
  711. BOOL
  712. GetDeviceDriveLetter(
  713. PWSTR DeviceName,
  714. PWCHAR DriveLetter
  715. )
  716. /*++
  717. Routine Description:
  718. This routine returns the drive letter (if any) of a device given
  719. the device name (like \Device\HarddiskVolume1)
  720. Arguments:
  721. DeviceName - supplies the device name
  722. DriveLetter - returns the drive letter
  723. Return Value:
  724. TRUE if the device has a drive letter
  725. --*/
  726. {
  727. DWORD cch;
  728. WCHAR dosDevices[4096];
  729. WCHAR target[4096];
  730. PWCHAR dosDevice;
  731. *DriveLetter = 0;
  732. if (!QueryDosDevice(NULL, dosDevices, 4096)) {
  733. return FALSE;
  734. }
  735. dosDevice = dosDevices;
  736. while (*dosDevice) {
  737. if (wcslen(dosDevice) == 2 && dosDevice[1] == L':' &&
  738. QueryDosDevice(dosDevice, target, 4096)) {
  739. if (!wcscmp(target, DeviceName)) {
  740. *DriveLetter = (WCHAR) tolower(dosDevice[0]);
  741. return TRUE;
  742. }
  743. }
  744. while (*dosDevice++);
  745. }
  746. return FALSE;
  747. }