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

877 lines
29 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. dosdev.c
  5. Abstract:
  6. This file contains the implementation of the DefineDosDevice API
  7. Author:
  8. Steve Wood (stevewo) 13-Dec-1992
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #define USHORT_MAX ((USHORT)(-1))
  13. #define DWORD_MAX ((DWORD)(-1))
  14. #define CH_COUNT_MAX ( DWORD_MAX / sizeof( WCHAR ) )
  15. BOOL
  16. WINAPI
  17. DefineDosDeviceA(
  18. DWORD dwFlags,
  19. LPCSTR lpDeviceName,
  20. LPCSTR lpTargetPath
  21. )
  22. {
  23. NTSTATUS Status;
  24. BOOL Result;
  25. ANSI_STRING AnsiString;
  26. PUNICODE_STRING DeviceName;
  27. UNICODE_STRING TargetPath;
  28. PCWSTR lpDeviceNameW;
  29. PCWSTR lpTargetPathW;
  30. RtlInitAnsiString( &AnsiString, lpDeviceName );
  31. DeviceName = &NtCurrentTeb()->StaticUnicodeString;
  32. Status = RtlAnsiStringToUnicodeString( DeviceName, &AnsiString, FALSE );
  33. if (!NT_SUCCESS( Status )) {
  34. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  35. SetLastError( ERROR_FILENAME_EXCED_RANGE );
  36. }
  37. else {
  38. BaseSetLastNTError( Status );
  39. }
  40. return FALSE;
  41. }
  42. else {
  43. lpDeviceNameW = DeviceName->Buffer;
  44. }
  45. if (ARGUMENT_PRESENT( lpTargetPath )) {
  46. RtlInitAnsiString( &AnsiString, lpTargetPath );
  47. Status = RtlAnsiStringToUnicodeString( &TargetPath, &AnsiString, TRUE );
  48. if (!NT_SUCCESS( Status )) {
  49. BaseSetLastNTError( Status );
  50. return FALSE;
  51. }
  52. else {
  53. lpTargetPathW = TargetPath.Buffer;
  54. }
  55. }
  56. else {
  57. lpTargetPathW = NULL;
  58. }
  59. Result = DefineDosDeviceW( dwFlags,
  60. lpDeviceNameW,
  61. lpTargetPathW
  62. );
  63. if (lpTargetPathW != NULL) {
  64. RtlFreeUnicodeString( &TargetPath );
  65. }
  66. return Result;
  67. }
  68. typedef
  69. long
  70. (WINAPI *PBROADCASTSYSTEMMESSAGEW)( DWORD, LPDWORD, UINT, WPARAM, LPARAM );
  71. BOOL
  72. WINAPI
  73. DefineDosDeviceW(
  74. DWORD dwFlags,
  75. PCWSTR lpDeviceName,
  76. PCWSTR lpTargetPath
  77. )
  78. /*++
  79. Routine Description:
  80. This function provides the capability to define new DOS device names or
  81. redefine or delete existing DOS device names. DOS Device names are stored
  82. as symbolic links in the NT object name space. The code that converts
  83. a DOS path into a corresponding NT path uses these symbolic links to
  84. handle mapping of DOS devices and drive letters. This API provides a
  85. mechanism for a Win32 Application to modify the symbolic links used
  86. to implement the DOS Device namespace. Use the QueryDosDevice API
  87. to query the current mapping for a DOS device name.
  88. Arguments:
  89. dwFlags - Supplies additional flags that control the creation
  90. of the DOS device.
  91. dwFlags Flags:
  92. DDD_PUSH_POP_DEFINITION - If lpTargetPath is not NULL, then push
  93. the new target path in front of any existing target path.
  94. If lpTargetPath is NULL, then delete the existing target path
  95. and pop the most recent one pushed. If nothing left to pop
  96. then the device name will be deleted.
  97. DDD_RAW_TARGET_PATH - Do not convert the lpTargetPath string from
  98. a DOS path to an NT path, but take it as is.
  99. lpDeviceName - Points to the DOS device name being defined, redefined or deleted.
  100. It must NOT have a trailing colon unless it is a drive letter being defined,
  101. redefined or deleted.
  102. lpTargetPath - Points to the DOS path that will implement this device. If the
  103. ADD_RAW_TARGET_PATH flag is specified, then this parameter points to an
  104. NT path string. If this parameter is NULL, then the device name is being
  105. deleted or restored if the ADD_PUSH_POP_DEFINITION flag is specified.
  106. Return Value:
  107. TRUE - The operation was successful
  108. FALSE/NULL - The operation failed. Extended error status is available
  109. using GetLastError.
  110. --*/
  111. {
  112. #if !defined(BUILD_WOW6432)
  113. BASE_API_MSG m;
  114. PBASE_DEFINEDOSDEVICE_MSG a = (PBASE_DEFINEDOSDEVICE_MSG)&m.u.DefineDosDeviceApi;
  115. PCSR_CAPTURE_HEADER p;
  116. ULONG PointerCount, n;
  117. #endif
  118. UNICODE_STRING DeviceName;
  119. UNICODE_STRING TargetPath;
  120. DWORD iDrive;
  121. DEV_BROADCAST_VOLUME dbv;
  122. DWORD dwRec = BSM_APPLICATIONS;
  123. BOOLEAN LuidDevMapsEnabled = BaseStaticServerData->LUIDDeviceMapsEnabled;
  124. #if defined(BUILD_WOW6432)
  125. NTSTATUS Status;
  126. #endif
  127. if (dwFlags & ~(DDD_RAW_TARGET_PATH |
  128. DDD_REMOVE_DEFINITION |
  129. DDD_EXACT_MATCH_ON_REMOVE |
  130. DDD_NO_BROADCAST_SYSTEM |
  131. DDD_LUID_BROADCAST_DRIVE
  132. ) ||
  133. ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) &&
  134. (!(dwFlags & DDD_REMOVE_DEFINITION))
  135. ) ||
  136. ((!ARGUMENT_PRESENT( lpTargetPath )) &&
  137. (!(dwFlags & (DDD_REMOVE_DEFINITION | DDD_LUID_BROADCAST_DRIVE)))
  138. ) ||
  139. ((dwFlags & DDD_LUID_BROADCAST_DRIVE) &&
  140. ((!ARGUMENT_PRESENT( lpDeviceName )) ||
  141. ARGUMENT_PRESENT( lpTargetPath ) ||
  142. (dwFlags & (DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE | DDD_NO_BROADCAST_SYSTEM)) ||
  143. (LuidDevMapsEnabled == FALSE)
  144. )
  145. )
  146. ) {
  147. SetLastError( ERROR_INVALID_PARAMETER );
  148. return FALSE;
  149. }
  150. RtlInitUnicodeString( &DeviceName, lpDeviceName );
  151. #if !defined(BUILD_WOW6432)
  152. PointerCount = 1;
  153. n = DeviceName.MaximumLength;
  154. #endif
  155. if (ARGUMENT_PRESENT( lpTargetPath )) {
  156. if (!(dwFlags & DDD_RAW_TARGET_PATH)) {
  157. if (!RtlDosPathNameToNtPathName_U( lpTargetPath,
  158. &TargetPath,
  159. NULL,
  160. NULL
  161. )
  162. ) {
  163. BaseSetLastNTError( STATUS_OBJECT_NAME_INVALID );
  164. return FALSE;
  165. }
  166. }
  167. else {
  168. RtlInitUnicodeString( &TargetPath, lpTargetPath );
  169. }
  170. #if !defined(BUILD_WOW6432)
  171. PointerCount += 1;
  172. n += TargetPath.MaximumLength;
  173. #endif
  174. }
  175. else {
  176. RtlInitUnicodeString( &TargetPath, NULL );
  177. }
  178. #if defined(BUILD_WOW6432)
  179. Status = CsrBasepDefineDosDevice(dwFlags, &DeviceName, &TargetPath);
  180. if (TargetPath.Length != 0 && !(dwFlags & DDD_RAW_TARGET_PATH)) {
  181. RtlFreeUnicodeString( &TargetPath );
  182. }
  183. #else
  184. p = CsrAllocateCaptureBuffer( PointerCount, n );
  185. if (p == NULL) {
  186. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  187. return FALSE;
  188. }
  189. a->Flags = dwFlags;
  190. a->DeviceName.MaximumLength =
  191. (USHORT)CsrAllocateMessagePointer( p,
  192. DeviceName.MaximumLength,
  193. (PVOID *)&a->DeviceName.Buffer
  194. );
  195. RtlUpcaseUnicodeString( &a->DeviceName, &DeviceName, FALSE );
  196. if (TargetPath.Length != 0) {
  197. a->TargetPath.MaximumLength =
  198. (USHORT)CsrAllocateMessagePointer( p,
  199. TargetPath.MaximumLength,
  200. (PVOID *)&a->TargetPath.Buffer
  201. );
  202. RtlCopyUnicodeString( &a->TargetPath, &TargetPath );
  203. if (!(dwFlags & DDD_RAW_TARGET_PATH)) {
  204. RtlFreeUnicodeString( &TargetPath );
  205. }
  206. }
  207. else {
  208. RtlInitUnicodeString( &a->TargetPath, NULL );
  209. }
  210. CsrClientCallServer( (PCSR_API_MSG)&m,
  211. p,
  212. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  213. BasepDefineDosDevice
  214. ),
  215. sizeof( *a )
  216. );
  217. CsrFreeCaptureBuffer( p );
  218. #endif
  219. #if defined(BUILD_WOW6432)
  220. if (NT_SUCCESS( Status )) {
  221. #else
  222. if (NT_SUCCESS( (NTSTATUS)m.ReturnValue )) {
  223. #endif
  224. HMODULE hUser32Dll;
  225. PBROADCASTSYSTEMMESSAGEW pBroadCastSystemMessageW;
  226. if (!(dwFlags & DDD_NO_BROADCAST_SYSTEM) &&
  227. DeviceName.Length == (2 * sizeof( WCHAR )) &&
  228. DeviceName.Buffer[ 1 ] == L':' &&
  229. (iDrive = RtlUpcaseUnicodeChar( DeviceName.Buffer[ 0 ] ) - L'A') < 26 &&
  230. LuidDevMapsEnabled == FALSE
  231. ) {
  232. dbv.dbcv_size = sizeof( dbv );
  233. dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
  234. dbv.dbcv_reserved = 0;
  235. dbv.dbcv_unitmask = (1 << iDrive);
  236. dbv.dbcv_flags = DBTF_NET;
  237. hUser32Dll = LoadLibraryW( L"USER32.DLL" );
  238. if (hUser32Dll != NULL) {
  239. pBroadCastSystemMessageW = (PBROADCASTSYSTEMMESSAGEW)
  240. GetProcAddress( hUser32Dll, "BroadcastSystemMessageW" );
  241. // broadcast to all windows!
  242. if (pBroadCastSystemMessageW != NULL) {
  243. (*pBroadCastSystemMessageW)( BSF_FORCEIFHUNG |
  244. BSF_NOHANG |
  245. BSF_NOTIMEOUTIFNOTHUNG,
  246. &dwRec,
  247. WM_DEVICECHANGE,
  248. (WPARAM)((dwFlags & DDD_REMOVE_DEFINITION) ?
  249. DBT_DEVICEREMOVECOMPLETE :
  250. DBT_DEVICEARRIVAL
  251. ),
  252. (LPARAM)(DEV_BROADCAST_HDR *)&dbv
  253. );
  254. }
  255. }
  256. FreeLibrary (hUser32Dll);
  257. }
  258. return TRUE;
  259. }
  260. else {
  261. #if defined(BUILD_WOW6432)
  262. BaseSetLastNTError( Status );
  263. #else
  264. BaseSetLastNTError( (NTSTATUS)m.ReturnValue );
  265. #endif
  266. return FALSE;
  267. }
  268. }
  269. NTSTATUS
  270. IsGlobalDeviceMap(
  271. IN HANDLE hDirObject,
  272. OUT PBOOLEAN pbGlobalDeviceMap
  273. )
  274. /*++
  275. Routine Description:
  276. Determine whether a directory object is the global device map
  277. Arguments:
  278. hDirObject - Supplies a handle to the directory object.
  279. pbGlobalDeviceMap - Points to a variable that will receive the result of
  280. "Is this directory object the global device map?"
  281. TRUE - directory object is the global device map
  282. FALSE - directory object is not the global device map
  283. Return Value:
  284. STATUS_SUCCESS - operations successful, did not encounter any errors,
  285. the result in pbGlobalDeviceMap is only valid for this
  286. status code
  287. STATUS_INVALID_PARAMETER - pbGlobalDeviceMap or hDirObject is NULL
  288. STATUS_NO_MEMORY - could not allocate memory to read the directory object's
  289. name
  290. STATUS_INFO_LENGTH_MISMATCH - did not allocate enough memory for the
  291. directory object's name
  292. STATUS_UNSUCCESSFUL - an unexpected error encountered
  293. --*/
  294. {
  295. UNICODE_STRING ObjectName;
  296. UNICODE_STRING GlobalDeviceMapName;
  297. PWSTR NameBuffer = NULL;
  298. ULONG ReturnedLength;
  299. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  300. if( ( pbGlobalDeviceMap == NULL ) || ( hDirObject == NULL ) ) {
  301. return( STATUS_INVALID_PARAMETER );
  302. }
  303. try {
  304. ObjectName.Length = 0;
  305. ObjectName.MaximumLength = 0;
  306. ObjectName.Buffer = NULL;
  307. ReturnedLength = 0;
  308. //
  309. // Determine the length of the directory object's name
  310. //
  311. Status = NtQueryObject( hDirObject,
  312. ObjectNameInformation,
  313. (PVOID) &ObjectName,
  314. 0,
  315. &ReturnedLength
  316. );
  317. if( !NT_SUCCESS( Status ) && (Status != STATUS_INFO_LENGTH_MISMATCH) ) {
  318. leave;
  319. }
  320. //
  321. // allocate memory for the directory object's name
  322. //
  323. NameBuffer = RtlAllocateHeap( RtlProcessHeap(),
  324. MAKE_TAG( TMP_TAG ),
  325. ReturnedLength
  326. );
  327. if( NameBuffer == NULL ) {
  328. Status = STATUS_NO_MEMORY;
  329. leave;
  330. }
  331. //
  332. // get the full name of the directory object
  333. //
  334. Status = NtQueryObject( hDirObject,
  335. ObjectNameInformation,
  336. NameBuffer,
  337. ReturnedLength,
  338. &ReturnedLength
  339. );
  340. if( !NT_SUCCESS( Status )) {
  341. leave;
  342. }
  343. RtlInitUnicodeString ( &GlobalDeviceMapName, L"\\GLOBAL??" );
  344. //
  345. // Check if the directory object is the global device map
  346. //
  347. *pbGlobalDeviceMap = RtlEqualUnicodeString( &GlobalDeviceMapName,
  348. (PUNICODE_STRING)NameBuffer,
  349. FALSE);
  350. Status = STATUS_SUCCESS;
  351. }
  352. finally {
  353. if( NameBuffer != NULL ) {
  354. RtlFreeHeap( RtlProcessHeap(), 0, NameBuffer );
  355. NameBuffer = NULL;
  356. }
  357. }
  358. return ( Status );
  359. }
  360. DWORD
  361. FindSymbolicLinkEntry(
  362. IN PWSTR lpKey,
  363. IN PWSTR lpBuffer,
  364. IN ULONG nElements,
  365. OUT PBOOLEAN pbResult
  366. )
  367. /*++
  368. Routine Description:
  369. Determine whether a symbolic link's name exists in a buffer of symbolic
  370. link names.
  371. Arguments:
  372. lpKey - Points to the symbolic link's name to search for
  373. lpBuffer - contains symbolic link names, where names are separated by a
  374. UNICODE_NULL
  375. nElements - the number of name elements to search
  376. pbResult - Points to a variable that will receive the result of
  377. "Does symbolic link name exist in the buffer?"
  378. TRUE - symbolic link name found in the buffer
  379. FALSE - symbolic link name not found in the buffer
  380. Return Value:
  381. NO_ERROR - operations successful, did not encounter any errors,
  382. the result in pbResult is only valid for this status code
  383. ERROR_INVALID_PARAMETER - lpKey, lpBuffer, or pbResult is a NULL pointer
  384. --*/
  385. {
  386. ULONG i = 0;
  387. //
  388. // Check for invalid parameters
  389. //
  390. if( (lpKey == NULL) || (lpBuffer == NULL) || (pbResult == NULL) ) {
  391. return( ERROR_INVALID_PARAMETER );
  392. }
  393. //
  394. // Assume the symbolic link's name is not in the buffer
  395. //
  396. *pbResult = FALSE;
  397. //
  398. // Search for the number of names specified
  399. //
  400. while( i < nElements ) {
  401. if( !wcscmp( lpKey, lpBuffer ) ) {
  402. //
  403. // Found the name, can stop searching & pass back the result
  404. //
  405. *pbResult = TRUE;
  406. break;
  407. }
  408. i++;
  409. //
  410. // Get the next name
  411. //
  412. while (*lpBuffer++);
  413. }
  414. return( NO_ERROR );
  415. }
  416. DWORD
  417. WINAPI
  418. QueryDosDeviceA(
  419. LPCSTR lpDeviceName,
  420. LPSTR lpTargetPath,
  421. DWORD ucchMax
  422. )
  423. {
  424. NTSTATUS Status;
  425. DWORD Result;
  426. ANSI_STRING AnsiString;
  427. PUNICODE_STRING DeviceName;
  428. UNICODE_STRING TargetPath;
  429. PCWSTR lpDeviceNameW;
  430. PWSTR lpTargetPathW;
  431. if (ARGUMENT_PRESENT( lpDeviceName )) {
  432. RtlInitAnsiString( &AnsiString, lpDeviceName );
  433. DeviceName = &NtCurrentTeb()->StaticUnicodeString;
  434. Status = RtlAnsiStringToUnicodeString( DeviceName, &AnsiString, FALSE );
  435. if (!NT_SUCCESS( Status )) {
  436. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  437. SetLastError( ERROR_FILENAME_EXCED_RANGE );
  438. }
  439. else {
  440. BaseSetLastNTError( Status );
  441. }
  442. return FALSE;
  443. }
  444. else {
  445. lpDeviceNameW = DeviceName->Buffer;
  446. }
  447. }
  448. else {
  449. lpDeviceNameW = NULL;
  450. }
  451. lpTargetPathW = RtlAllocateHeap( RtlProcessHeap(),
  452. MAKE_TAG( TMP_TAG ),
  453. ucchMax * sizeof( WCHAR )
  454. );
  455. if (lpTargetPathW == NULL) {
  456. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  457. return FALSE;
  458. }
  459. Result = QueryDosDeviceW( lpDeviceNameW,
  460. lpTargetPathW,
  461. ucchMax
  462. );
  463. if (Result != 0) {
  464. TargetPath.Buffer = lpTargetPathW;
  465. TargetPath.Length = (USHORT)(Result * sizeof( WCHAR ));
  466. TargetPath.MaximumLength = (USHORT)(TargetPath.Length + 1);
  467. AnsiString.Buffer = lpTargetPath;
  468. AnsiString.Length = 0;
  469. AnsiString.MaximumLength = (USHORT)ucchMax;
  470. Status = RtlUnicodeStringToAnsiString( &AnsiString,
  471. &TargetPath,
  472. FALSE
  473. );
  474. if (!NT_SUCCESS( Status )) {
  475. BaseSetLastNTError( Status );
  476. Result = 0;
  477. }
  478. }
  479. RtlFreeHeap( RtlProcessHeap(), 0, lpTargetPathW );
  480. return Result;
  481. }
  482. DWORD
  483. WINAPI
  484. QueryDosDeviceW(
  485. PCWSTR lpDeviceName,
  486. PWSTR lpTargetPath,
  487. DWORD ucchMax
  488. )
  489. {
  490. NTSTATUS Status;
  491. UNICODE_STRING UnicodeString;
  492. OBJECT_ATTRIBUTES Attributes;
  493. HANDLE DirectoryHandle = NULL;
  494. HANDLE LinkHandle;
  495. POBJECT_DIRECTORY_INFORMATION DirInfo;
  496. BOOLEAN RestartScan;
  497. UCHAR DirInfoBuffer[ 512 ];
  498. CLONG Count = 0;
  499. ULONG Context = 0;
  500. ULONG ReturnedLength;
  501. DWORD ucchName, ucchReturned;
  502. BOOLEAN ScanGlobalDeviceMap = FALSE;
  503. ULONG nElements = 0;
  504. BOOLEAN DuplicateEntry;
  505. PWSTR lpBuffer = lpTargetPath;
  506. DWORD Result, BufferSize;
  507. RtlInitUnicodeString( &UnicodeString, L"\\??" );
  508. InitializeObjectAttributes( &Attributes,
  509. &UnicodeString,
  510. OBJ_CASE_INSENSITIVE,
  511. NULL,
  512. NULL
  513. );
  514. Status = NtOpenDirectoryObject( &DirectoryHandle,
  515. DIRECTORY_QUERY,
  516. &Attributes
  517. );
  518. if (!NT_SUCCESS( Status )) {
  519. BaseSetLastNTError( Status );
  520. return 0;
  521. }
  522. ucchReturned = 0;
  523. try {
  524. if (ARGUMENT_PRESENT( lpDeviceName )) {
  525. RtlInitUnicodeString( &UnicodeString, lpDeviceName );
  526. InitializeObjectAttributes( &Attributes,
  527. &UnicodeString,
  528. OBJ_CASE_INSENSITIVE,
  529. DirectoryHandle,
  530. NULL
  531. );
  532. Status = NtOpenSymbolicLinkObject( &LinkHandle,
  533. SYMBOLIC_LINK_QUERY,
  534. &Attributes
  535. );
  536. if (NT_SUCCESS( Status )) {
  537. UnicodeString.Buffer = lpTargetPath;
  538. UnicodeString.Length = 0;
  539. //
  540. // Check for possible overflow of a DWORD
  541. //
  542. if (ucchMax > CH_COUNT_MAX) {
  543. BufferSize = DWORD_MAX;
  544. } else {
  545. BufferSize = ucchMax * sizeof( WCHAR );
  546. }
  547. //
  548. // Check for possible overflow of a USHORT
  549. //
  550. if (BufferSize > (DWORD)(USHORT_MAX)) {
  551. UnicodeString.MaximumLength = USHORT_MAX;
  552. } else {
  553. UnicodeString.MaximumLength = (USHORT)(BufferSize);
  554. }
  555. ReturnedLength = 0;
  556. Status = NtQuerySymbolicLinkObject( LinkHandle,
  557. &UnicodeString,
  558. &ReturnedLength
  559. );
  560. NtClose( LinkHandle );
  561. if (NT_SUCCESS( Status )) {
  562. ucchReturned = ReturnedLength / sizeof( WCHAR );
  563. if ( ( (ucchReturned == 0) ||
  564. ( (ucchReturned > 0) &&
  565. (lpTargetPath[ ucchReturned - 1 ] != UNICODE_NULL)
  566. )
  567. ) &&
  568. (ucchReturned < ucchMax)
  569. ) {
  570. lpTargetPath[ ucchReturned ] = UNICODE_NULL;
  571. ucchReturned++;
  572. }
  573. if (ucchReturned < ucchMax) {
  574. lpTargetPath[ ucchReturned++ ] = UNICODE_NULL;
  575. } else {
  576. ucchReturned = 0;
  577. Status = STATUS_BUFFER_TOO_SMALL;
  578. }
  579. }
  580. }
  581. } else {
  582. //
  583. // Dump all the symbolic links in the device map's directory
  584. // With LUID device maps enabled, we must search two directories
  585. // because the LUID device map is transparent on top of the
  586. // global device map
  587. //
  588. if (BaseStaticServerData->LUIDDeviceMapsEnabled == TRUE) {
  589. BOOLEAN GlobalDeviceMap = TRUE;
  590. //
  591. // Determine if directory is the global directory
  592. //
  593. Status = IsGlobalDeviceMap( DirectoryHandle,
  594. &GlobalDeviceMap );
  595. //
  596. // if !global, set second directory search flag
  597. //
  598. if( (NT_SUCCESS( Status )) &&
  599. (GlobalDeviceMap == FALSE) ) {
  600. ScanGlobalDeviceMap = TRUE;
  601. }
  602. }
  603. nElements = 0;
  604. RestartScan = TRUE;
  605. DirInfo = (POBJECT_DIRECTORY_INFORMATION)&DirInfoBuffer[0];
  606. while (TRUE) {
  607. Status = NtQueryDirectoryObject( DirectoryHandle,
  608. (PVOID)DirInfo,
  609. sizeof( DirInfoBuffer ),
  610. TRUE,
  611. RestartScan,
  612. &Context,
  613. &ReturnedLength
  614. );
  615. //
  616. // Check the status of the operation.
  617. //
  618. if (!NT_SUCCESS( Status )) {
  619. if (Status == STATUS_NO_MORE_ENTRIES) {
  620. Status = STATUS_SUCCESS;
  621. }
  622. break;
  623. }
  624. if (!wcscmp( DirInfo->TypeName.Buffer, L"SymbolicLink" )) {
  625. ucchName = DirInfo->Name.Length / sizeof( WCHAR );
  626. if ((ucchReturned + ucchName + 1 + 1) > ucchMax) {
  627. ucchReturned = 0;
  628. Status = STATUS_BUFFER_TOO_SMALL;
  629. break;
  630. }
  631. RtlCopyMemory( lpTargetPath,
  632. DirInfo->Name.Buffer,
  633. DirInfo->Name.Length
  634. );
  635. lpTargetPath += ucchName;
  636. *lpTargetPath++ = UNICODE_NULL;
  637. ucchReturned += ucchName + 1;
  638. nElements++;
  639. }
  640. RestartScan = FALSE;
  641. }
  642. if ( (BaseStaticServerData->LUIDDeviceMapsEnabled == TRUE) &&
  643. (NT_SUCCESS( Status )) &&
  644. ScanGlobalDeviceMap == TRUE) {
  645. //
  646. // need to perform a second scan for the
  647. // global device map because the first scan only
  648. // searches the LUID device map
  649. //
  650. //
  651. // close DirectoryHandle, set to NULL
  652. //
  653. if( DirectoryHandle != NULL ) {
  654. NtClose( DirectoryHandle );
  655. DirectoryHandle = NULL;
  656. }
  657. //
  658. // open the global device map
  659. //
  660. RtlInitUnicodeString( &UnicodeString, L"\\GLOBAL??" );
  661. InitializeObjectAttributes( &Attributes,
  662. &UnicodeString,
  663. OBJ_CASE_INSENSITIVE,
  664. NULL,
  665. NULL
  666. );
  667. Status = NtOpenDirectoryObject( &DirectoryHandle,
  668. DIRECTORY_QUERY,
  669. &Attributes
  670. );
  671. if (!NT_SUCCESS( Status )) {
  672. DirectoryHandle = NULL;
  673. leave;
  674. }
  675. //
  676. // perform the second scan
  677. // scan the global device map
  678. //
  679. RestartScan = TRUE;
  680. while (TRUE) {
  681. Status = NtQueryDirectoryObject( DirectoryHandle,
  682. (PVOID)DirInfo,
  683. sizeof( DirInfoBuffer ),
  684. TRUE,
  685. RestartScan,
  686. &Context,
  687. &ReturnedLength
  688. );
  689. //
  690. // Check the status of the operation.
  691. //
  692. if (!NT_SUCCESS( Status )) {
  693. if (Status == STATUS_NO_MORE_ENTRIES) {
  694. Status = STATUS_SUCCESS;
  695. }
  696. break;
  697. }
  698. if (!wcscmp( DirInfo->TypeName.Buffer, L"SymbolicLink" )) {
  699. Result = FindSymbolicLinkEntry(
  700. DirInfo->Name.Buffer,
  701. lpBuffer,
  702. nElements,
  703. &DuplicateEntry);
  704. if ((Result == NO_ERROR) && (DuplicateEntry == FALSE)) {
  705. ucchName = DirInfo->Name.Length / sizeof( WCHAR );
  706. if ((ucchReturned + ucchName + 1 + 1) > ucchMax) {
  707. ucchReturned = 0;
  708. Status = STATUS_BUFFER_TOO_SMALL;
  709. break;
  710. }
  711. RtlCopyMemory( lpTargetPath,
  712. DirInfo->Name.Buffer,
  713. DirInfo->Name.Length
  714. );
  715. lpTargetPath += ucchName;
  716. *lpTargetPath++ = UNICODE_NULL;
  717. ucchReturned += ucchName + 1;
  718. }
  719. }
  720. RestartScan = FALSE;
  721. }
  722. }
  723. if (NT_SUCCESS( Status )) {
  724. *lpTargetPath++ = UNICODE_NULL;
  725. ucchReturned++;
  726. }
  727. }
  728. } finally {
  729. if( DirectoryHandle != NULL ) {
  730. NtClose( DirectoryHandle );
  731. }
  732. }
  733. if (!NT_SUCCESS( Status )) {
  734. ucchReturned = 0;
  735. BaseSetLastNTError( Status );
  736. }
  737. return ucchReturned;
  738. }