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.

929 lines
22 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. syspart.c
  5. Abstract:
  6. Routines to determine the system partition on x86 machines.
  7. Author:
  8. Ted Miller (tedm) 30-June-1994
  9. Revision History:
  10. 24-Apr-1997 scotthal
  11. re-horked for system applet
  12. --*/
  13. #include "sysdm.h"
  14. #include <ntdddisk.h>
  15. #include <tchar.h>
  16. #define ISNT() TRUE
  17. #define MALLOC(s) LocalAlloc(LPTR, (s))
  18. #define REALLOC(p, s) LocalReAlloc((HLOCAL) (p), (s), 0L)
  19. #define FREE(p) LocalFree((HLOCAL) (p))
  20. BOOL g_fInitialized = FALSE;
  21. //
  22. // NT-specific routines we use from ntdll.dll
  23. //
  24. //NTSYSAPI
  25. NTSTATUS
  26. (NTAPI *NtOpenSymLinkRoutine)(
  27. OUT PHANDLE LinkHandle,
  28. IN ACCESS_MASK DesiredAccess,
  29. IN POBJECT_ATTRIBUTES ObjectAttributes
  30. );
  31. //NTSYSAPI
  32. NTSTATUS
  33. (NTAPI *NtQuerSymLinkRoutine)(
  34. IN HANDLE LinkHandle,
  35. IN OUT PUNICODE_STRING LinkTarget,
  36. OUT PULONG ReturnedLength OPTIONAL
  37. );
  38. //NTSYSAPI
  39. NTSTATUS
  40. (NTAPI *NtQuerDirRoutine) (
  41. IN HANDLE DirectoryHandle,
  42. OUT PVOID Buffer,
  43. IN ULONG Length,
  44. IN BOOLEAN ReturnSingleEntry,
  45. IN BOOLEAN RestartScan,
  46. IN OUT PULONG Context,
  47. OUT PULONG ReturnLength OPTIONAL
  48. );
  49. //NTSYSAPI
  50. NTSTATUS
  51. (NTAPI *NtOpenDirRoutine) (
  52. OUT PHANDLE DirectoryHandle,
  53. IN ACCESS_MASK DesiredAccess,
  54. IN POBJECT_ATTRIBUTES ObjectAttributes
  55. );
  56. BOOL
  57. MatchNTSymbolicPaths(
  58. PCTSTR lpDeviceName,
  59. PCTSTR lpSysPart,
  60. PCTSTR lpMatchName
  61. );
  62. IsNEC98(
  63. VOID
  64. )
  65. {
  66. static BOOL Checked = FALSE;
  67. static BOOL Is98;
  68. if(!Checked) {
  69. Is98 = ((GetKeyboardType(0) == 7) && ((GetKeyboardType(1) & 0xff00) == 0x0d00));
  70. Checked = TRUE;
  71. }
  72. return(Is98);
  73. }
  74. BOOL
  75. GetPartitionInfo(
  76. IN TCHAR Drive,
  77. OUT PPARTITION_INFORMATION PartitionInfo
  78. )
  79. /*++
  80. Routine Description:
  81. Fill in a PARTITION_INFORMATION structure with information about
  82. a particular drive.
  83. This routine is meaningful only when run on NT -- it always fails
  84. on Win95.
  85. Arguments:
  86. Drive - supplies drive letter whose partition info is desired.
  87. PartitionInfo - upon success, receives partition info for Drive.
  88. Return Value:
  89. Boolean value indicating whether PartitionInfo has been filled in.
  90. --*/
  91. {
  92. TCHAR DriveName[] = TEXT("\\\\.\\?:");
  93. HANDLE hDisk;
  94. BOOL b;
  95. DWORD DataSize;
  96. if(!ISNT()) {
  97. return(FALSE);
  98. }
  99. DriveName[4] = Drive;
  100. hDisk = CreateFile(
  101. DriveName,
  102. GENERIC_READ,
  103. FILE_SHARE_READ | FILE_SHARE_WRITE,
  104. NULL,
  105. OPEN_EXISTING,
  106. 0,
  107. NULL
  108. );
  109. if(hDisk == INVALID_HANDLE_VALUE) {
  110. return(FALSE);
  111. }
  112. b = DeviceIoControl(
  113. hDisk,
  114. IOCTL_DISK_GET_PARTITION_INFO,
  115. NULL,
  116. 0,
  117. PartitionInfo,
  118. sizeof(PARTITION_INFORMATION),
  119. &DataSize,
  120. NULL
  121. );
  122. CloseHandle(hDisk);
  123. return(b);
  124. }
  125. UINT
  126. MyGetDriveType(
  127. IN TCHAR Drive
  128. )
  129. /*++
  130. Routine Description:
  131. Same as GetDriveType() Win32 API except on NT returns
  132. DRIVE_FIXED for removeable hard drives.
  133. Arguments:
  134. Drive - supplies drive letter whose type is desired.
  135. Return Value:
  136. Same as GetDriveType().
  137. --*/
  138. {
  139. TCHAR DriveNameNt[] = TEXT("\\\\.\\?:");
  140. TCHAR DriveName[] = TEXT("?:\\");
  141. HANDLE hDisk;
  142. BOOL b;
  143. UINT rc;
  144. DWORD DataSize;
  145. DISK_GEOMETRY MediaInfo;
  146. //
  147. // First, get the win32 drive type. If it tells us DRIVE_REMOVABLE,
  148. // then we need to see whether it's a floppy or hard disk. Otherwise
  149. // just believe the api.
  150. //
  151. //
  152. DriveName[0] = Drive;
  153. rc = GetDriveType(DriveName);
  154. #ifdef _X86_ //NEC98
  155. if((rc != DRIVE_REMOVABLE) || !ISNT() || (!IsNEC98() && (Drive < L'C'))) {
  156. return(rc);
  157. }
  158. #else //NEC98
  159. if((rc != DRIVE_REMOVABLE) || !ISNT() || (Drive < L'C')) {
  160. return(rc);
  161. }
  162. #endif
  163. //
  164. // DRIVE_REMOVABLE on NT.
  165. //
  166. //
  167. // Disallow use of removable media (e.g. Jazz, Zip, ...).
  168. //
  169. #if 0
  170. DriveNameNt[4] = Drive;
  171. hDisk = CreateFile(
  172. DriveNameNt,
  173. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  174. FILE_SHARE_READ | FILE_SHARE_WRITE,
  175. NULL,
  176. OPEN_EXISTING,
  177. 0,
  178. NULL
  179. );
  180. if(hDisk != INVALID_HANDLE_VALUE) {
  181. b = DeviceIoControl(
  182. hDisk,
  183. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  184. NULL,
  185. 0,
  186. &MediaInfo,
  187. sizeof(MediaInfo),
  188. &DataSize,
  189. NULL
  190. );
  191. //
  192. // It's really a hard disk if the media type is removable.
  193. //
  194. if(b && (MediaInfo.MediaType == RemovableMedia)) {
  195. rc = DRIVE_FIXED;
  196. }
  197. CloseHandle(hDisk);
  198. }
  199. #endif
  200. return(rc);
  201. }
  202. BOOL
  203. ArcPathToNtPath(
  204. IN LPCTSTR ArcPath,
  205. OUT LPTSTR NtPath,
  206. IN UINT NtPathBufferLen
  207. )
  208. {
  209. WCHAR arcPath[256];
  210. UNICODE_STRING UnicodeString;
  211. OBJECT_ATTRIBUTES Obja;
  212. HANDLE ObjectHandle;
  213. NTSTATUS Status;
  214. WCHAR Buffer[512];
  215. PWSTR ntPath;
  216. lstrcpyW(arcPath,L"\\ArcName\\");
  217. #ifdef UNICODE
  218. lstrcpynW(arcPath+9,ArcPath,ARRAYSIZE(arcPath) - 9);
  219. #else
  220. MultiByteToWideChar(
  221. CP_ACP,
  222. 0,
  223. ArcPath,
  224. -1,
  225. arcPath+9,
  226. (sizeof(arcPath)/sizeof(WCHAR))-9
  227. );
  228. #endif
  229. UnicodeString.Buffer = arcPath;
  230. UnicodeString.Length = (USHORT)lstrlenW(arcPath)*sizeof(WCHAR);
  231. UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  232. InitializeObjectAttributes(
  233. &Obja,
  234. &UnicodeString,
  235. OBJ_CASE_INSENSITIVE,
  236. NULL,
  237. NULL
  238. );
  239. Status = (*NtOpenSymLinkRoutine)(
  240. &ObjectHandle,
  241. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  242. &Obja
  243. );
  244. if(NT_SUCCESS(Status)) {
  245. //
  246. // Query the object to get the link target.
  247. //
  248. UnicodeString.Buffer = Buffer;
  249. UnicodeString.Length = 0;
  250. UnicodeString.MaximumLength = sizeof(Buffer)-sizeof(WCHAR);
  251. Status = (*NtQuerSymLinkRoutine)(ObjectHandle,&UnicodeString,NULL);
  252. CloseHandle(ObjectHandle);
  253. if(NT_SUCCESS(Status)) {
  254. Buffer[UnicodeString.Length/sizeof(WCHAR)] = 0;
  255. #ifdef UNICODE
  256. lstrcpyn(NtPath,Buffer,NtPathBufferLen);
  257. #else
  258. WideCharToMultiByte(CP_ACP,0,Buffer,-1,NtPath,NtPathBufferLen,NULL,NULL);
  259. #endif
  260. return(TRUE);
  261. }
  262. }
  263. return(FALSE);
  264. }
  265. BOOL
  266. AppearsToBeSysPart(
  267. IN PDRIVE_LAYOUT_INFORMATION DriveLayout,
  268. IN TCHAR Drive
  269. )
  270. {
  271. PARTITION_INFORMATION PartitionInfo,*p;
  272. BOOL IsPrimary;
  273. UINT i;
  274. DWORD d;
  275. LPTSTR BootFiles[] = { TEXT("BOOT.INI"),
  276. TEXT("NTLDR"),
  277. TEXT("NTDETECT.COM"),
  278. NULL
  279. };
  280. TCHAR FileName[64];
  281. //
  282. // Get partition information for this partition.
  283. //
  284. if(!GetPartitionInfo(Drive,&PartitionInfo)) {
  285. return(FALSE);
  286. }
  287. //
  288. // See if the drive is a primary partition.
  289. //
  290. IsPrimary = FALSE;
  291. for(i=0; i<min(DriveLayout->PartitionCount,4); i++) {
  292. p = &DriveLayout->PartitionEntry[i];
  293. if((p->PartitionType != PARTITION_ENTRY_UNUSED)
  294. && (p->StartingOffset.QuadPart == PartitionInfo.StartingOffset.QuadPart)
  295. && (p->PartitionLength.QuadPart == PartitionInfo.PartitionLength.QuadPart)) {
  296. IsPrimary = TRUE;
  297. break;
  298. }
  299. }
  300. if(!IsPrimary) {
  301. return(FALSE);
  302. }
  303. //
  304. // Don't rely on the active partition flag. This could easily not be accurate
  305. // (like user is using os/2 boot manager, for example).
  306. //
  307. //
  308. // See whether all NT boot files are present on this drive.
  309. //
  310. for(i=0; BootFiles[i]; i++) {
  311. wsprintf(FileName,TEXT("%c:\\%s"),Drive,BootFiles[i]);
  312. d = GetFileAttributes(FileName);
  313. if(d == (DWORD)(-1)) {
  314. return(FALSE);
  315. }
  316. }
  317. return(TRUE);
  318. }
  319. DWORD
  320. QueryHardDiskNumber(
  321. IN TCHAR DriveLetter
  322. )
  323. {
  324. TCHAR driveName[10];
  325. HANDLE h;
  326. BOOL b;
  327. STORAGE_DEVICE_NUMBER number;
  328. DWORD bytes;
  329. driveName[0] = '\\';
  330. driveName[1] = '\\';
  331. driveName[2] = '.';
  332. driveName[3] = '\\';
  333. driveName[4] = DriveLetter;
  334. driveName[5] = ':';
  335. driveName[6] = 0;
  336. h = CreateFile(driveName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  337. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  338. INVALID_HANDLE_VALUE);
  339. if (h == INVALID_HANDLE_VALUE) {
  340. return (DWORD) -1;
  341. }
  342. b = DeviceIoControl(h, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
  343. &number, sizeof(number), &bytes, NULL);
  344. CloseHandle(h);
  345. if (!b) {
  346. return (DWORD) -1;
  347. }
  348. return number.DeviceNumber;
  349. }
  350. TCHAR
  351. x86DetermineSystemPartition(
  352. IN HWND ParentWindow
  353. )
  354. /*++
  355. Routine Description:
  356. Determine the system partition on x86 machines.
  357. On Win95, we always return C:. For NT, read on.
  358. The system partition is the primary partition on the boot disk.
  359. Usually this is the active partition on disk 0 and usually it's C:.
  360. However the user could have remapped drive letters and generally
  361. determining the system partition with 100% accuracy is not possible.
  362. The one thing we can be sure of is that the system partition is on
  363. the physical hard disk with the arc path multi(0)disk(0)rdisk(0).
  364. We can be sure of this because by definition this is the arc path
  365. for bios drive 0x80.
  366. This routine determines which drive letters represent drives on
  367. that physical hard drive, and checks each for the nt boot files.
  368. The first drive found with those files is assumed to be the system
  369. partition.
  370. If for some reason we cannot determine the system partition by the above
  371. method, we simply assume it's C:.
  372. Arguments:
  373. ParentWindow - supplies window handle for window to be the parent for
  374. any dialogs, etc.
  375. SysPartDrive - if successful, receives drive letter of system partition.
  376. Return Value:
  377. Boolean value indicating whether SysPartDrive has been filled in.
  378. If FALSE, the user will have been infomred about why.
  379. --*/
  380. {
  381. TCHAR DriveName[3];
  382. BOOL GotIt;
  383. TCHAR NtDevicePath[256];
  384. DWORD NtDevicePathLen;
  385. LPTSTR p;
  386. DWORD PhysicalDriveNumber;
  387. TCHAR Buffer[512];
  388. TCHAR FoundSystemPartition[20], temp[5];
  389. HANDLE hDisk;
  390. PDRIVE_LAYOUT_INFORMATION DriveLayout;
  391. DWORD DriveLayoutSize;
  392. TCHAR Drive;
  393. BOOL b;
  394. DWORD DataSize;
  395. DWORD BootPartitionNumber, cnt;
  396. PPARTITION_INFORMATION Start, i;
  397. if (!g_fInitialized) {
  398. GotIt = FALSE;
  399. goto c0;
  400. }
  401. if(IsNEC98())
  402. {
  403. *Buffer = TEXT('c'); // initialize to C in case GetWindowDirectory fails.
  404. if (!GetWindowsDirectory(Buffer, ARRAYSIZE(Buffer)))
  405. {
  406. *Buffer = TEXT('c'); // initialize to C in case GetWindowDirectory fails.
  407. }
  408. return Buffer[0];
  409. }
  410. if(!ISNT()) {
  411. return(TEXT('C'));
  412. }
  413. DriveName[1] = TEXT(':');
  414. DriveName[2] = 0;
  415. //
  416. // The system partition must be on multi(0)disk(0)rdisk(0)
  417. // If we can't translate that ARC path then something is really wrong.
  418. // We assume C: because we don't know what else to do.
  419. //
  420. b = ArcPathToNtPath(
  421. TEXT("multi(0)disk(0)rdisk(0)"),
  422. NtDevicePath,
  423. sizeof(NtDevicePath)/sizeof(TCHAR)
  424. );
  425. if(!b) {
  426. //
  427. // Missed. Try scsi(0) in case the user is using ntbootdd.sys
  428. //
  429. b = ArcPathToNtPath(
  430. TEXT("scsi(0)disk(0)rdisk(0)"),
  431. NtDevicePath,
  432. sizeof(NtDevicePath)/sizeof(TCHAR)
  433. );
  434. if(!b) {
  435. GotIt = FALSE;
  436. goto c0;
  437. }
  438. }
  439. //
  440. // The arc path for a disk device is usually linked
  441. // to partition0. Get rid of the partition part of the name.
  442. //
  443. CharLower(NtDevicePath);
  444. if(p = _tcsstr(NtDevicePath,TEXT("\\partition"))) {
  445. *p = 0;
  446. }
  447. NtDevicePathLen = lstrlen(NtDevicePath);
  448. //
  449. // Determine the physical drive number of this drive.
  450. // If the name is not of the form \device\harddiskx then
  451. // something is very wrong. Just assume we don't understand
  452. // this device type, and return C:.
  453. //
  454. if(memcmp(NtDevicePath,TEXT("\\device\\harddisk"),16*sizeof(TCHAR))) {
  455. Drive = TEXT('C');
  456. GotIt = TRUE;
  457. goto c0;
  458. }
  459. PhysicalDriveNumber = _tcstoul(NtDevicePath+16,NULL,10);
  460. wsprintf(Buffer,TEXT("\\\\.\\PhysicalDrive%u"),PhysicalDriveNumber);
  461. //
  462. // Get drive layout info for this physical disk.
  463. // If we can't do this something is very wrong.
  464. //
  465. hDisk = CreateFile(
  466. Buffer,
  467. FILE_READ_ATTRIBUTES | FILE_READ_DATA,
  468. FILE_SHARE_READ | FILE_SHARE_WRITE,
  469. NULL,
  470. OPEN_EXISTING,
  471. 0,
  472. NULL
  473. );
  474. if(hDisk == INVALID_HANDLE_VALUE) {
  475. GotIt = FALSE;
  476. goto c0;
  477. }
  478. //
  479. // Get partition information.
  480. //
  481. DriveLayout = MALLOC(1024);
  482. DriveLayoutSize = 1024;
  483. if(!DriveLayout) {
  484. GotIt = FALSE;
  485. goto c1;
  486. }
  487. _tcscpy( FoundSystemPartition, TEXT("Partition") );
  488. retry:
  489. b = DeviceIoControl(
  490. hDisk,
  491. IOCTL_DISK_GET_DRIVE_LAYOUT,
  492. NULL,
  493. 0,
  494. (PVOID)DriveLayout,
  495. DriveLayoutSize,
  496. &DataSize,
  497. NULL
  498. );
  499. if(!b) {
  500. if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  501. DriveLayoutSize += 1024;
  502. if(p = REALLOC((PVOID)DriveLayout,DriveLayoutSize)) {
  503. (PVOID)DriveLayout = p;
  504. } else {
  505. GotIt = FALSE;
  506. goto c2;
  507. }
  508. goto retry;
  509. } else {
  510. GotIt = FALSE;
  511. goto c2;
  512. }
  513. }else{
  514. // Now walk the Drive_Layout to find the boot partition
  515. Start = DriveLayout->PartitionEntry;
  516. cnt = 0;
  517. for( i = Start; cnt < DriveLayout->PartitionCount; i++ ){
  518. cnt++;
  519. if( i->BootIndicator == TRUE ){
  520. BootPartitionNumber = i->PartitionNumber;
  521. _ultot( BootPartitionNumber, temp, 10 );
  522. _tcscat( FoundSystemPartition, temp );
  523. break;
  524. }
  525. }
  526. }
  527. //
  528. // The system partition can only be a drive that is on
  529. // this disk. We make this determination by looking at NT drive names
  530. // for each drive letter and seeing if the NT equivalent of
  531. // multi(0)disk(0)rdisk(0) is a prefix.
  532. //
  533. GotIt = FALSE;
  534. for(Drive=TEXT('A'); Drive<=TEXT('Z'); Drive++) {
  535. if(MyGetDriveType(Drive) == DRIVE_FIXED) {
  536. DriveName[0] = Drive;
  537. if(QueryDosDevice(DriveName,Buffer,sizeof(Buffer)/sizeof(TCHAR))) {
  538. if( MatchNTSymbolicPaths(NtDevicePath,FoundSystemPartition,Buffer)) {
  539. //
  540. // Now look to see whether there's an nt boot sector and
  541. // boot files on this drive.
  542. //
  543. if(AppearsToBeSysPart(DriveLayout,Drive)) {
  544. GotIt = TRUE;
  545. break;
  546. }
  547. }
  548. }
  549. }
  550. }
  551. if(!GotIt) {
  552. //
  553. // Strange case, just assume C:
  554. //
  555. GotIt = TRUE;
  556. Drive = TEXT('C');
  557. }
  558. c2:
  559. if (DriveLayout) {
  560. FREE(DriveLayout);
  561. }
  562. c1:
  563. CloseHandle(hDisk);
  564. c0:
  565. if(GotIt) {
  566. return(Drive);
  567. }
  568. else {
  569. return(TEXT('C'));
  570. }
  571. }
  572. BOOL
  573. InitializeArcStuff(
  574. )
  575. {
  576. HMODULE NtdllLib;
  577. if(ISNT()) {
  578. //
  579. // On NT ntdll.dll had better be already loaded.
  580. //
  581. NtdllLib = LoadLibrary(TEXT("NTDLL"));
  582. if(!NtdllLib) {
  583. return(FALSE);
  584. }
  585. (FARPROC)NtOpenSymLinkRoutine = GetProcAddress(NtdllLib,"NtOpenSymbolicLinkObject");
  586. (FARPROC)NtQuerSymLinkRoutine = GetProcAddress(NtdllLib,"NtQuerySymbolicLinkObject");
  587. (FARPROC)NtOpenDirRoutine = GetProcAddress(NtdllLib,"NtOpenDirectoryObject");
  588. (FARPROC)NtQuerDirRoutine = GetProcAddress(NtdllLib,"NtQueryDirectoryObject");
  589. if(!NtOpenSymLinkRoutine || !NtQuerSymLinkRoutine || !NtOpenDirRoutine || !NtQuerDirRoutine) {
  590. FreeLibrary(NtdllLib);
  591. return(FALSE);
  592. }
  593. //
  594. // We don't need the extraneous handle any more.
  595. //
  596. FreeLibrary(NtdllLib);
  597. }
  598. return(g_fInitialized = TRUE);
  599. }
  600. BOOL
  601. MatchNTSymbolicPaths(
  602. PCTSTR lpDeviceName,
  603. PCTSTR lpSysPart,
  604. PCTSTR lpMatchName
  605. )
  606. /*
  607. Introduced this routine to mend the old way of finding if we determined the right system partition.
  608. Arguments:
  609. lpDeviceName - This should be the symbolic link (\Device\HarddiskX) name for the arcpath
  610. multi/scsi(0)disk(0)rdisk(0) which is the arcpath for bios drive 0x80.
  611. Remember that we strip the PartitionX part to get just \Device\HarddiskX.
  612. lpSysPart - When we traverse the lpDeviceName directory we compare the symbolic link corresponding to
  613. lpSysPart and see if it matches lpMatchName
  614. lpMatchName - This is the symbolic name that a drive letter translates to (got by calling
  615. QueryDosDevice() ).
  616. So it boils down to us trying to match a drive letter to the system partition on bios drive 0x80.
  617. */
  618. {
  619. NTSTATUS Status;
  620. UNICODE_STRING UnicodeString;
  621. OBJECT_ATTRIBUTES Attributes;
  622. HANDLE DirectoryHandle, SymLinkHandle;
  623. POBJECT_DIRECTORY_INFORMATION DirInfo;
  624. BOOLEAN RestartScan, ret;
  625. UCHAR DirInfoBuffer[ 512 ];
  626. WCHAR Buffer[1024];
  627. WCHAR pDevice[512], pMatch[512], pSysPart[20];
  628. ULONG Context = 0;
  629. ULONG ReturnedLength;
  630. #ifdef UNICODE
  631. lstrcpyW( pDevice,lpDeviceName);
  632. lstrcpyW( pMatch,lpMatchName);
  633. lstrcpyW( pSysPart,lpSysPart);
  634. #else
  635. MultiByteToWideChar(
  636. CP_ACP,
  637. 0,
  638. lpDeviceName,
  639. -1,
  640. pDevice,
  641. (sizeof(pDevice)/sizeof(WCHAR))
  642. );
  643. MultiByteToWideChar(
  644. CP_ACP,
  645. 0,
  646. lpMatchName,
  647. -1,
  648. pMatch,
  649. (sizeof(pMatch)/sizeof(WCHAR))
  650. );
  651. MultiByteToWideChar(
  652. CP_ACP,
  653. 0,
  654. lpSysPart,
  655. -1,
  656. pSysPart,
  657. (sizeof(pSysPart)/sizeof(WCHAR))
  658. );
  659. #endif
  660. UnicodeString.Buffer = pDevice;
  661. UnicodeString.Length = (USHORT)lstrlenW(pDevice)*sizeof(WCHAR);
  662. UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  663. InitializeObjectAttributes( &Attributes,
  664. &UnicodeString,
  665. OBJ_CASE_INSENSITIVE,
  666. NULL,
  667. NULL
  668. );
  669. Status = (*NtOpenDirRoutine)( &DirectoryHandle,
  670. DIRECTORY_QUERY,
  671. &Attributes
  672. );
  673. if (!NT_SUCCESS( Status ))
  674. return(FALSE);
  675. RestartScan = TRUE;
  676. DirInfo = (POBJECT_DIRECTORY_INFORMATION)&DirInfoBuffer;
  677. ret = FALSE;
  678. while (TRUE) {
  679. Status = (*NtQuerDirRoutine)( DirectoryHandle,
  680. (PVOID)DirInfo,
  681. sizeof( DirInfoBuffer ),
  682. TRUE,
  683. RestartScan,
  684. &Context,
  685. &ReturnedLength
  686. );
  687. //
  688. // Check the status of the operation.
  689. //
  690. if (!NT_SUCCESS( Status )) {
  691. if (Status == STATUS_NO_MORE_ENTRIES) {
  692. Status = STATUS_SUCCESS;
  693. }
  694. break;
  695. }
  696. if (!wcsncmp( DirInfo->TypeName.Buffer, L"SymbolicLink", DirInfo->TypeName.Length ) &&
  697. !_wcsnicmp( DirInfo->Name.Buffer, pSysPart, DirInfo->Name.Length ) ) {
  698. UnicodeString.Buffer = DirInfo->Name.Buffer;
  699. UnicodeString.Length = (USHORT)lstrlenW(DirInfo->Name.Buffer)*sizeof(WCHAR);
  700. UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  701. InitializeObjectAttributes( &Attributes,
  702. &UnicodeString,
  703. OBJ_CASE_INSENSITIVE,
  704. DirectoryHandle,
  705. NULL
  706. );
  707. Status = (*NtOpenSymLinkRoutine)(
  708. &SymLinkHandle,
  709. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  710. &Attributes
  711. );
  712. if(NT_SUCCESS(Status)) {
  713. //
  714. // Query the object to get the link target.
  715. //
  716. UnicodeString.Buffer = Buffer;
  717. UnicodeString.Length = 0;
  718. UnicodeString.MaximumLength = sizeof(Buffer)-sizeof(WCHAR);
  719. Status = (*NtQuerSymLinkRoutine)(SymLinkHandle,&UnicodeString,NULL);
  720. CloseHandle(SymLinkHandle);
  721. if( NT_SUCCESS(Status)){
  722. if (!_wcsnicmp(UnicodeString.Buffer, pMatch, (UnicodeString.Length/sizeof(WCHAR)))) {
  723. ret = TRUE;
  724. break;
  725. }
  726. }
  727. }
  728. }
  729. RestartScan = FALSE;
  730. }
  731. CloseHandle( DirectoryHandle );
  732. return( ret );
  733. }