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.

1490 lines
36 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. blkshare.c
  5. Abstract:
  6. This module implements routines for managing share blocks.
  7. Author:
  8. Chuck Lenzmeier (chuckl) 4-Oct-1989
  9. David Treadwell (davidtr)
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include "blkshare.tmh"
  14. #pragma hdrstop
  15. #define BugCheckFileId SRV_FILE_BLKSHARE
  16. VOID
  17. GetShareQueryNamePrefix (
  18. PSHARE Share
  19. );
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text( PAGE, SrvAllocateShare )
  22. #pragma alloc_text( PAGE, SrvCloseShare )
  23. #pragma alloc_text( PAGE, SrvDereferenceShare )
  24. #pragma alloc_text( PAGE, SrvDereferenceShareForTreeConnect )
  25. #pragma alloc_text( PAGE, SrvFreeShare )
  26. #pragma alloc_text( PAGE, SrvReferenceShare )
  27. #pragma alloc_text( PAGE, SrvReferenceShareForTreeConnect )
  28. #pragma alloc_text( PAGE, SrvFillInFileSystemName )
  29. #pragma alloc_text( PAGE, SrvGetShareRootHandle )
  30. #pragma alloc_text( PAGE, SrvRefreshShareRootHandle )
  31. #pragma alloc_text( PAGE, GetShareQueryNamePrefix )
  32. #endif
  33. VOID
  34. SrvAllocateShare (
  35. OUT PSHARE *Share,
  36. IN PUNICODE_STRING ShareName,
  37. IN PUNICODE_STRING NtPathName,
  38. IN PUNICODE_STRING DosPathName,
  39. IN PUNICODE_STRING Remark,
  40. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  41. IN PSECURITY_DESCRIPTOR FileSecurityDescriptor OPTIONAL,
  42. IN SHARE_TYPE ShareType
  43. )
  44. /*++
  45. Routine Description:
  46. This function allocates a Share Block from the FSP heap.
  47. Arguments:
  48. Share - Returns a pointer to the share block, or NULL if no
  49. heap space was available.
  50. ShareName - Supplies the name of the share.
  51. NtPathName - Supplies a fully qualified directory path in NT format
  52. to the share.
  53. DosPathName - Supplies a fully qualified directory path in DOS
  54. format to the share.
  55. Remark - a comment to store with the share.
  56. SecurityDescriptor - security descriptor used for determining whether
  57. a user can connect to this share.
  58. FileSecurityDescriptor - security descriptor used for determining the
  59. permissions of clients on files in this share.
  60. ShareType - Enumerated type indicating type of resource.
  61. Return Value:
  62. None.
  63. --*/
  64. {
  65. CLONG blockSize;
  66. PSHARE share;
  67. ULONG securityDescriptorLength;
  68. ULONG fileSdLength;
  69. PAGED_CODE( );
  70. //
  71. // Attempt to allocate from the heap. Note that space for the
  72. // remark (if any) is allocated separately. Allocate extra space
  73. // for the security descriptor since it must be longword aligned,
  74. // and there may be padding between the DOS path name and the
  75. // security descriptor.
  76. //
  77. securityDescriptorLength = RtlLengthSecurityDescriptor( SecurityDescriptor );
  78. blockSize = sizeof(SHARE) +
  79. ShareName->Length + sizeof(WCHAR) +
  80. NtPathName->Length + sizeof(WCHAR) +
  81. DosPathName->Length + sizeof(WCHAR) +
  82. securityDescriptorLength + sizeof(ULONG);
  83. share = ALLOCATE_HEAP( blockSize, BlockTypeShare );
  84. *Share = share;
  85. if ( share == NULL ) {
  86. INTERNAL_ERROR(
  87. ERROR_LEVEL_EXPECTED,
  88. "SrvAllocateShare: Unable to allocate %d bytes from heap.",
  89. blockSize,
  90. NULL
  91. );
  92. return;
  93. }
  94. IF_DEBUG(HEAP) {
  95. SrvPrint1( "SrvAllocateShare: Allocated share at %p\n", share );
  96. }
  97. RtlZeroMemory( share, blockSize );
  98. SET_BLOCK_TYPE_STATE_SIZE( share, BlockTypeShare, BlockStateActive, blockSize );
  99. share->BlockHeader.ReferenceCount = 2; // allow for Active status
  100. // and caller's pointer
  101. //
  102. // Save the share type.
  103. //
  104. share->ShareType = ShareType;
  105. //
  106. // Indicate that we've haven't determined the share's query name prefix yet.
  107. //
  108. share->QueryNamePrefixLength = -1;
  109. //
  110. // Put the share name after the share block.
  111. //
  112. share->ShareName.Buffer = (PWSTR)(share + 1);
  113. share->ShareName.Length = ShareName->Length;
  114. share->ShareName.MaximumLength =
  115. (SHORT)(ShareName->Length + sizeof(WCHAR));
  116. RtlCopyMemory(
  117. share->ShareName.Buffer,
  118. ShareName->Buffer,
  119. ShareName->Length
  120. );
  121. //
  122. // Put the NT path name after share name. If no NT path name was
  123. // specified, just set the path name string to NULL.
  124. //
  125. share->NtPathName.Buffer = (PWSTR)((PCHAR)share->ShareName.Buffer +
  126. share->ShareName.MaximumLength);
  127. share->NtPathName.Length = NtPathName->Length;
  128. share->NtPathName.MaximumLength = (SHORT)(NtPathName->Length +
  129. sizeof(WCHAR));
  130. RtlCopyMemory(
  131. share->NtPathName.Buffer,
  132. NtPathName->Buffer,
  133. NtPathName->Length
  134. );
  135. //
  136. // Put the DOS path name after share name. If no DOS path name was
  137. // specified, just set the path name string to NULL.
  138. //
  139. share->DosPathName.Buffer = (PWSTR)((PCHAR)share->NtPathName.Buffer +
  140. share->NtPathName.MaximumLength);
  141. share->DosPathName.Length = DosPathName->Length;
  142. share->DosPathName.MaximumLength = (SHORT)(DosPathName->Length +
  143. sizeof(WCHAR));
  144. RtlCopyMemory(
  145. share->DosPathName.Buffer,
  146. DosPathName->Buffer,
  147. DosPathName->Length
  148. );
  149. //
  150. // Initialize the security RESOURCE for the share
  151. //
  152. share->SecurityDescriptorLock = ALLOCATE_NONPAGED_POOL( sizeof(ERESOURCE), BlockTypeShare );
  153. if( !share->SecurityDescriptorLock )
  154. {
  155. INTERNAL_ERROR(
  156. ERROR_LEVEL_EXPECTED,
  157. "SrvAllocateShare: Unable to allocate %d bytes from NP pool.",
  158. sizeof(ERESOURCE),
  159. NULL
  160. );
  161. SrvFreeShare( share );
  162. *Share = NULL;
  163. return;
  164. }
  165. INITIALIZE_LOCK( share->SecurityDescriptorLock, 1, "Share Security Descriptor Lock" );
  166. share->SnapShotLock = ALLOCATE_NONPAGED_POOL( sizeof(SRV_LOCK), BlockTypeShare );
  167. if( !share->SnapShotLock )
  168. {
  169. INTERNAL_ERROR(
  170. ERROR_LEVEL_EXPECTED,
  171. "SrvAllocateShare: Unable to allocate %d bytes from NP pool.",
  172. sizeof(ERESOURCE),
  173. NULL
  174. );
  175. SrvFreeShare( share );
  176. *Share = NULL;
  177. return;
  178. }
  179. INITIALIZE_LOCK( share->SnapShotLock, 1, "Share SnapShot Lock" );
  180. //
  181. // Allocate space for the remark and copy over the remark. We
  182. // cannot put the remark after the share block because the remark is
  183. // settable by NetShareSetInfo. It is possible for the storage
  184. // required for the remark to increase.
  185. //
  186. // If no remark was passed in, do not allocate space. Just set up
  187. // a null string to describe it.
  188. //
  189. if ( ARGUMENT_PRESENT( Remark ) ) {
  190. share->Remark.Buffer = ALLOCATE_HEAP(
  191. Remark->Length + sizeof(*Remark->Buffer),
  192. BlockTypeShareRemark
  193. );
  194. if ( share->Remark.Buffer == NULL ) {
  195. INTERNAL_ERROR(
  196. ERROR_LEVEL_EXPECTED,
  197. "SrvAllocateShare: Unable to allocate %d bytes from heap.",
  198. blockSize,
  199. NULL
  200. );
  201. SrvFreeShare( share );
  202. *Share = NULL;
  203. return;
  204. }
  205. share->Remark.Length = Remark->Length;
  206. share->Remark.MaximumLength =
  207. (SHORT)(Remark->Length + sizeof(*Remark->Buffer));
  208. RtlCopyMemory(
  209. share->Remark.Buffer,
  210. Remark->Buffer,
  211. Remark->Length
  212. );
  213. *(PWCH)((PCHAR)share->Remark.Buffer + share->Remark.Length) = 0;
  214. } else {
  215. RtlInitUnicodeString( &share->Remark, NULL );
  216. }
  217. //
  218. // Set up the security descriptor for the share. It must be longword-
  219. // aligned to be used in various calls.
  220. //
  221. share->SecurityDescriptor =
  222. (PSECURITY_DESCRIPTOR)( ((ULONG_PTR)share->DosPathName.Buffer +
  223. share->DosPathName.MaximumLength + 3) & ~3);
  224. RtlCopyMemory(
  225. share->SecurityDescriptor,
  226. SecurityDescriptor,
  227. securityDescriptorLength
  228. );
  229. //
  230. // Set up the file security descriptor for the share. We did not allocate
  231. // space for the file SD because this is settable and thus cannot have
  232. // preallocated space.
  233. //
  234. ASSERT( share->FileSecurityDescriptor == NULL );
  235. if ( ARGUMENT_PRESENT( FileSecurityDescriptor) ) {
  236. fileSdLength = RtlLengthSecurityDescriptor( FileSecurityDescriptor );
  237. share->FileSecurityDescriptor = ALLOCATE_HEAP(
  238. fileSdLength,
  239. BlockTypeShareSecurityDescriptor
  240. );
  241. if ( share->FileSecurityDescriptor == NULL ) {
  242. INTERNAL_ERROR(
  243. ERROR_LEVEL_EXPECTED,
  244. "SrvAllocateShare: Unable to allocate %d bytes from heap.",
  245. fileSdLength,
  246. NULL
  247. );
  248. SrvFreeShare( share );
  249. *Share = NULL;
  250. return;
  251. }
  252. RtlCopyMemory(
  253. share->FileSecurityDescriptor,
  254. FileSecurityDescriptor,
  255. fileSdLength
  256. );
  257. }
  258. //
  259. // Indicate whether or not this share potentially contains the system directory.
  260. //
  261. if( DosPathName->Length != 0 && SrvSystemRoot.Length != 0 ) {
  262. UNICODE_STRING tmpString;
  263. if( DosPathName->Length == SrvSystemRoot.Length ) {
  264. //
  265. // If the two names are the same, then the share is exactly at the system
  266. // directory. All files within this share are system files!
  267. //
  268. if( RtlCompareUnicodeString( DosPathName, &SrvSystemRoot, TRUE ) == 0 ) {
  269. share->PotentialSystemFile = TRUE;
  270. }
  271. } else if( DosPathName->Length < SrvSystemRoot.Length ) {
  272. //
  273. // If the share path is a substring of the system root path...
  274. //
  275. if( DosPathName->Buffer[ DosPathName->Length/sizeof(WCHAR) - 1 ] ==
  276. OBJ_NAME_PATH_SEPARATOR ||
  277. SrvSystemRoot.Buffer[ DosPathName->Length/sizeof(WCHAR) ] ==
  278. OBJ_NAME_PATH_SEPARATOR ) {
  279. //
  280. // .. and if the share path is for the root of the drive...
  281. //
  282. tmpString = SrvSystemRoot;
  283. tmpString.Length = DosPathName->Length;
  284. //
  285. // ... and if the system root is on the same drive...
  286. //
  287. if( RtlCompareUnicodeString( DosPathName, &tmpString, TRUE ) == 0 ) {
  288. //
  289. // ... then we potentially are accessing system files
  290. //
  291. share->PotentialSystemFile = TRUE;
  292. }
  293. }
  294. } else {
  295. //
  296. // If the system root path is a substring of the share path, then every file
  297. // within the share is a system file.
  298. //
  299. if( DosPathName->Buffer[ SrvSystemRoot.Length / sizeof( WCHAR ) ] ==
  300. OBJ_NAME_PATH_SEPARATOR ) {
  301. tmpString = *DosPathName;
  302. tmpString.Length = SrvSystemRoot.Length;
  303. if( RtlCompareUnicodeString( DosPathName, &tmpString, TRUE ) == 0 ) {
  304. //
  305. // Every file in the share is a system file
  306. //
  307. share->PotentialSystemFile = TRUE;
  308. }
  309. }
  310. }
  311. }
  312. //
  313. // Initialize the share's tree connect list.
  314. //
  315. InitializeListHead( &share->TreeConnectList );
  316. //
  317. // Initialize the SnapShot list
  318. //
  319. InitializeListHead( &share->SnapShots );
  320. INITIALIZE_REFERENCE_HISTORY( share );
  321. INCREMENT_DEBUG_STAT( SrvDbgStatistics.ShareInfo.Allocations );
  322. #ifdef SRVCATCH
  323. SrvIsMonitoredShare( share );
  324. #endif
  325. return;
  326. } // SrvAllocateShare
  327. VOID
  328. SrvCloseShare (
  329. IN PSHARE Share
  330. )
  331. /*++
  332. Routine Description:
  333. This function closes a share.
  334. Arguments:
  335. Share - Supplies a pointer to a share Block
  336. Return Value:
  337. None.
  338. --*/
  339. {
  340. PAGED_CODE( );
  341. ACQUIRE_LOCK( &SrvShareLock );
  342. //
  343. // If the share hasn't already been closed, do so now.
  344. //
  345. if ( GET_BLOCK_STATE(Share) == BlockStateActive ) {
  346. IF_DEBUG(BLOCK1) SrvPrint1( "Closing share at %p\n", Share );
  347. SET_BLOCK_STATE( Share, BlockStateClosing );
  348. RELEASE_LOCK( &SrvShareLock );
  349. //
  350. // Close all the tree connects on this share.
  351. //
  352. SrvCloseTreeConnectsOnShare( Share );
  353. //
  354. // Dereference the share--this will cause it to be freed when
  355. // all other references are closed.
  356. //
  357. SrvDereferenceShare( Share );
  358. INCREMENT_DEBUG_STAT( SrvDbgStatistics.ShareInfo.Closes );
  359. } else {
  360. RELEASE_LOCK( &SrvShareLock );
  361. }
  362. return;
  363. } // SrvCloseShare
  364. VOID
  365. SrvDereferenceShare (
  366. IN PSHARE Share
  367. )
  368. /*++
  369. Routine Description:
  370. This function decrements the reference count on a share. If the
  371. reference count goes to zero, the share block is deleted.
  372. Arguments:
  373. Share - Address of share
  374. Return Value:
  375. None.
  376. --*/
  377. {
  378. PAGED_CODE( );
  379. //
  380. // Enter a critical section and decrement the reference count on the
  381. // block.
  382. //
  383. ACQUIRE_LOCK( &SrvShareLock );
  384. IF_DEBUG(REFCNT) {
  385. SrvPrint2( "Dereferencing share %p; old refcnt %lx\n",
  386. Share, Share->BlockHeader.ReferenceCount );
  387. }
  388. ASSERT( GET_BLOCK_TYPE(Share) == BlockTypeShare );
  389. ASSERT( (LONG)Share->BlockHeader.ReferenceCount > 0 );
  390. UPDATE_REFERENCE_HISTORY( Share, TRUE );
  391. if ( --Share->BlockHeader.ReferenceCount == 0 ) {
  392. //
  393. // The new reference count is 0, meaning that it's time to
  394. // delete this block.
  395. //
  396. ASSERT( Share->CurrentUses == 0 );
  397. ASSERT( GET_BLOCK_STATE( Share ) != BlockStateActive );
  398. RELEASE_LOCK( &SrvShareLock );
  399. //
  400. // Remove the block from the global list.
  401. //
  402. SrvRemoveShare( Share );
  403. //
  404. // Free the share block.
  405. //
  406. SrvFreeShare( Share );
  407. } else {
  408. RELEASE_LOCK( &SrvShareLock );
  409. }
  410. return;
  411. } // SrvDereferenceShare
  412. VOID
  413. SrvDereferenceShareForTreeConnect (
  414. PSHARE Share
  415. )
  416. /*++
  417. Routine Description:
  418. This function decrements the reference count on a share block for
  419. the referenced pointer in a tree connect block. If this is the last
  420. reference by a tree connect to the share, the share root directory
  421. is closed.
  422. Arguments:
  423. Share - Address of share
  424. Return Value:
  425. None.
  426. --*/
  427. {
  428. PAGED_CODE( );
  429. ACQUIRE_LOCK( &SrvShareLock );
  430. //
  431. // Update the count of tree connects on the share.
  432. //
  433. ASSERT( Share->CurrentUses > 0 );
  434. Share->CurrentUses--;
  435. //
  436. // If this is the last reference by a tree connect to the share and
  437. // this is a disk share, close the share root directory handle.
  438. //
  439. if ( Share->CurrentUses == 0 && Share->ShareType == ShareTypeDisk ) {
  440. if ( !Share->Removable ) {
  441. SRVDBG_RELEASE_HANDLE( Share->RootDirectoryHandle, "RTD", 5, Share );
  442. SrvNtClose( Share->RootDirectoryHandle, FALSE );
  443. }
  444. Share->RootDirectoryHandle = NULL;
  445. }
  446. //
  447. // Dereference the share and return.
  448. //
  449. SrvDereferenceShare( Share );
  450. RELEASE_LOCK( &SrvShareLock );
  451. return;
  452. } // SrvDereferenceShareForTreeConnect
  453. VOID
  454. SrvFreeShare (
  455. IN PSHARE Share
  456. )
  457. /*++
  458. Routine Description:
  459. This function returns a Share Block to the FSP heap.
  460. Arguments:
  461. Share - Address of share
  462. Return Value:
  463. None.
  464. --*/
  465. {
  466. PLIST_ENTRY shareList;
  467. PAGED_CODE( );
  468. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Share, BlockTypeGarbage, BlockStateDead, -1 );
  469. DEBUG Share->BlockHeader.ReferenceCount = (ULONG)-1;
  470. TERMINATE_REFERENCE_HISTORY( Share );
  471. // Delete all the SnapShot shares
  472. shareList = Share->SnapShots.Flink;
  473. while( shareList != &Share->SnapShots )
  474. {
  475. PSHARE_SNAPSHOT snapShare = CONTAINING_RECORD( shareList, SHARE_SNAPSHOT, SnapShotList );
  476. shareList = shareList->Flink;
  477. SrvSnapRemoveShare( snapShare );
  478. }
  479. //
  480. // Remove storage for the remark, if any.
  481. //
  482. if ( Share->Remark.Buffer != NULL ) {
  483. FREE_HEAP( Share->Remark.Buffer );
  484. }
  485. //
  486. // Remove storage for the file security descriptor, if any.
  487. //
  488. if ( Share->FileSecurityDescriptor != NULL ) {
  489. FREE_HEAP( Share->FileSecurityDescriptor );
  490. }
  491. //
  492. // Cleanup the file security descriptor lock
  493. //
  494. if( Share->SecurityDescriptorLock )
  495. {
  496. DELETE_LOCK( Share->SecurityDescriptorLock );
  497. DEALLOCATE_NONPAGED_POOL( Share->SecurityDescriptorLock );
  498. }
  499. //
  500. // Cleanup the SnapShot lock
  501. //
  502. if( Share->SnapShotLock )
  503. {
  504. DELETE_LOCK( Share->SnapShotLock );
  505. DEALLOCATE_NONPAGED_POOL( Share->SnapShotLock );
  506. }
  507. //
  508. // Remove storage for the filesystem name
  509. //
  510. if ( Share->Type.FileSystem.Name.Buffer != NULL ) {
  511. FREE_HEAP( Share->Type.FileSystem.Name.Buffer );
  512. }
  513. FREE_HEAP( Share );
  514. IF_DEBUG(HEAP) {
  515. SrvPrint1( "SrvFreeShare: Freed share block at %p\n", Share );
  516. }
  517. INCREMENT_DEBUG_STAT( SrvDbgStatistics.ShareInfo.Frees );
  518. return;
  519. } // SrvFreeShare
  520. VOID
  521. SrvReferenceShare (
  522. PSHARE Share
  523. )
  524. /*++
  525. Routine Description:
  526. This function increments the reference count on a share block.
  527. Arguments:
  528. Share - Address of share
  529. Return Value:
  530. None.
  531. --*/
  532. {
  533. PAGED_CODE( );
  534. //
  535. // Enter a critical section and increment the reference count on the
  536. // share.
  537. //
  538. ACQUIRE_LOCK( &SrvShareLock );
  539. ASSERT( (LONG)Share->BlockHeader.ReferenceCount > 0 );
  540. ASSERT( GET_BLOCK_TYPE(Share) == BlockTypeShare );
  541. // ASSERT( GET_BLOCK_STATE(Share) == BlockStateActive );
  542. UPDATE_REFERENCE_HISTORY( Share, FALSE );
  543. Share->BlockHeader.ReferenceCount++;
  544. IF_DEBUG(REFCNT) {
  545. SrvPrint2( "Referencing share %p; new refcnt %lx\n",
  546. Share, Share->BlockHeader.ReferenceCount );
  547. }
  548. RELEASE_LOCK( &SrvShareLock );
  549. return;
  550. } // SrvReferenceShare
  551. NTSTATUS
  552. SrvReferenceShareForTreeConnect (
  553. PSHARE Share
  554. )
  555. /*++
  556. Routine Description:
  557. This function increments the reference count on a share block for
  558. the referenced pointer in a tree connect block. If this is the
  559. first tree connect to reference the share, the share root directory
  560. is opened.
  561. Arguments:
  562. Share - Address of share
  563. Return Value:
  564. None.
  565. --*/
  566. {
  567. NTSTATUS status;
  568. OBJECT_ATTRIBUTES objectAttributes;
  569. IO_STATUS_BLOCK iosb;
  570. PFILE_FS_ATTRIBUTE_INFORMATION attributeInfo;
  571. CHAR buffer[ FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) + 32 ];
  572. PVOID allocatedBuffer = NULL;
  573. PFILE_OBJECT fileObject;
  574. PDEVICE_OBJECT deviceObject;
  575. PAGED_CODE( );
  576. ACQUIRE_LOCK( &SrvShareLock );
  577. //
  578. // Update the count of tree connects on the share.
  579. //
  580. Share->CurrentUses++;
  581. //
  582. // Check if this is the first tree connect to the share.
  583. //
  584. if ( Share->CurrentUses > 1 ) {
  585. //
  586. // There are already open tree connects on the share. Just
  587. // reference the share and return.
  588. //
  589. SrvReferenceShare( Share );
  590. goto done;
  591. }
  592. //
  593. // If this is not a disk share, then we do not need to open the
  594. // share root directory, so reference the share and return.
  595. //
  596. if ( Share->ShareType != ShareTypeDisk || Share->Removable ) {
  597. SrvReferenceShare( Share );
  598. goto done;
  599. }
  600. #ifdef INCLUDE_SMB_IFMODIFIED
  601. //
  602. // by default, we'll assume USN capable until we get back an "unsupported"
  603. // from the filesystem.
  604. //
  605. Share->UsnCapable = TRUE;
  606. #endif
  607. //
  608. // This is the first tree connect, so we need to open the share root
  609. // directory. Future opens of files within the share will be relative
  610. // to the root of the share.
  611. //
  612. Share->RootDirectoryHandle = NULL;
  613. if( SrvRefreshShareRootHandle( Share, &status ) == FALSE ) {
  614. Share->CurrentUses--;
  615. RELEASE_LOCK( &SrvShareLock );
  616. return status;
  617. }
  618. //
  619. // All is well -- we are now going to return STATUS_SUCCESS no matter what!
  620. //
  621. SrvReferenceShare( Share );
  622. if ( Share->QueryNamePrefixLength == -1 ) {
  623. //
  624. // Query the name associated with the share root directory.
  625. // The prefix is removed whenever the name of a file in the
  626. // share is queried. (The logical root must be preserved
  627. // for remote clients.)
  628. //
  629. GetShareQueryNamePrefix( Share );
  630. }
  631. //
  632. // Now extract the name of the file system, so that it can be returned
  633. // in the TreeConnectAndX response.
  634. //
  635. //
  636. if ( Share->Type.FileSystem.Name.Buffer == NULL ) {
  637. attributeInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)buffer;
  638. status = NtQueryVolumeInformationFile(
  639. Share->RootDirectoryHandle,
  640. &iosb,
  641. attributeInfo,
  642. sizeof( buffer ),
  643. FileFsAttributeInformation
  644. );
  645. if ( status == STATUS_BUFFER_OVERFLOW ) {
  646. //
  647. // The file system information was too large to fit in our small
  648. // stack buffer. Allocate an ample buffer and try again.
  649. //
  650. allocatedBuffer = ALLOCATE_HEAP(
  651. FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION,FileSystemName) +
  652. attributeInfo->FileSystemNameLength,
  653. BlockTypeVolumeInformation
  654. );
  655. if ( allocatedBuffer == NULL ) {
  656. //
  657. // Couldn't allocate the buffer. Give up.
  658. //
  659. goto done;
  660. }
  661. status = NtQueryVolumeInformationFile(
  662. Share->RootDirectoryHandle,
  663. &iosb,
  664. allocatedBuffer,
  665. FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) +
  666. attributeInfo->FileSystemNameLength,
  667. FileFsAttributeInformation
  668. );
  669. if ( !NT_SUCCESS( status ) ) {
  670. goto done;
  671. }
  672. attributeInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)allocatedBuffer;
  673. } else if ( !NT_SUCCESS( status ) ) {
  674. //
  675. // Some other, unexpected error occured. Give up.
  676. //
  677. goto done;
  678. }
  679. //
  680. // Fill in the file system name
  681. //
  682. SrvFillInFileSystemName(
  683. Share,
  684. attributeInfo->FileSystemName,
  685. attributeInfo->FileSystemNameLength
  686. );
  687. }
  688. done:
  689. if ( allocatedBuffer != NULL ) {
  690. FREE_HEAP( allocatedBuffer );
  691. }
  692. RELEASE_LOCK( &SrvShareLock );
  693. return STATUS_SUCCESS;
  694. } // SrvReferenceShareForTreeConnect
  695. BOOLEAN
  696. SrvCheckNtfsForUniqueFiles()
  697. {
  698. ULONG lengthNeeded;
  699. NTSTATUS status;
  700. HANDLE keyHandle;
  701. UNICODE_STRING unicodeParamPath;
  702. UNICODE_STRING unicodeKeyName;
  703. OBJECT_ATTRIBUTES objAttributes;
  704. PKEY_VALUE_FULL_INFORMATION infoBuffer = NULL;
  705. RtlInitUnicodeString( &unicodeParamPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\FileSystem" );
  706. RtlInitUnicodeString( &unicodeKeyName, L"NtfsDisable8dot3NameCreation" );
  707. InitializeObjectAttributes(
  708. &objAttributes,
  709. &unicodeParamPath,
  710. OBJ_CASE_INSENSITIVE,
  711. NULL,
  712. NULL
  713. );
  714. status = ZwOpenKey(
  715. &keyHandle,
  716. KEY_QUERY_VALUE,
  717. &objAttributes
  718. );
  719. if ( !NT_SUCCESS(status) ) {
  720. return FALSE;
  721. }
  722. status = ZwQueryValueKey(
  723. keyHandle,
  724. &unicodeKeyName,
  725. KeyValueFullInformation,
  726. NULL,
  727. 0,
  728. &lengthNeeded
  729. );
  730. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  731. NtClose( keyHandle );
  732. return FALSE;
  733. }
  734. infoBuffer = ALLOCATE_NONPAGED_POOL( lengthNeeded, BlockTypeDataBuffer );
  735. if ( infoBuffer == NULL ) {
  736. NtClose( keyHandle );
  737. return FALSE;
  738. }
  739. status = ZwQueryValueKey(
  740. keyHandle,
  741. &unicodeKeyName,
  742. KeyValueFullInformation,
  743. infoBuffer,
  744. lengthNeeded,
  745. &lengthNeeded
  746. );
  747. NtClose( keyHandle );
  748. if( NT_SUCCESS(status) )
  749. {
  750. if( infoBuffer->DataLength == sizeof(DWORD) )
  751. {
  752. if( *((LPDWORD)(((PBYTE)infoBuffer)+infoBuffer->DataOffset)) )
  753. {
  754. DEALLOCATE_NONPAGED_POOL( infoBuffer );
  755. return TRUE;
  756. }
  757. }
  758. }
  759. DEALLOCATE_NONPAGED_POOL( infoBuffer );
  760. return FALSE;
  761. }
  762. VOID
  763. SrvFillInFileSystemName (
  764. IN PSHARE Share,
  765. IN PWSTR FileSystemName,
  766. IN ULONG FileSystemNameLength
  767. )
  768. /*++
  769. Routine Description:
  770. This function fills in the stores the given file system name into the
  771. share block.
  772. Arguments:
  773. Share - Address of share
  774. FileSystemName - A string containing the name of the file system
  775. FileSystemNameLength - Length of the above string
  776. Return Value:
  777. None.
  778. --*/
  779. {
  780. PAGED_CODE( );
  781. //
  782. // If we have a FATxx filesystem, we need to return FAT back to the clients,
  783. // else they will not believe they can create long names. I know, I know....
  784. //
  785. if( (FileSystemNameLength > 3 * sizeof( WCHAR ) ) &&
  786. (FileSystemName[0] == L'F' || FileSystemName[0] == L'f') &&
  787. (FileSystemName[1] == L'A' || FileSystemName[0] == L'a') &&
  788. (FileSystemName[2] == L'T' || FileSystemName[0] == L't') ) {
  789. FileSystemNameLength = 3 * sizeof( WCHAR );
  790. FileSystemName[3] = UNICODE_NULL;
  791. }
  792. #ifdef INCLUDE_SMB_PERSISTENT
  793. if( (FileSystemNameLength >= 3 * sizeof( WCHAR ) ) &&
  794. (FileSystemName[0] == L'F' || FileSystemName[0] == L'f') &&
  795. (FileSystemName[1] == L'A' || FileSystemName[0] == L'a') &&
  796. (FileSystemName[2] == L'T' || FileSystemName[0] == L't') ) {
  797. //
  798. // persistent handles are not allowed for fat volumes
  799. //
  800. Share->AllowPersistentHandles = FALSE;
  801. }
  802. #endif
  803. if( (FileSystemNameLength == 4*sizeof(WCHAR)) &&
  804. !STRNICMP(FileSystemName,L"NTFS",4) )
  805. {
  806. if( SrvCheckNtfsForUniqueFiles() )
  807. {
  808. Share->UniqueNames = TRUE;
  809. }
  810. }
  811. //
  812. // Allocate enough storage for the ANSI and Unicode representations.
  813. //
  814. Share->Type.FileSystem.Name.Length = (USHORT)FileSystemNameLength;
  815. Share->Type.FileSystem.Name.MaximumLength =
  816. (USHORT)(FileSystemNameLength + sizeof( UNICODE_NULL ));
  817. Share->Type.FileSystem.Name.Buffer = FileSystemName;
  818. Share->Type.FileSystem.OemName.MaximumLength =
  819. (USHORT)RtlUnicodeStringToOemSize( &Share->Type.FileSystem.Name );
  820. Share->Type.FileSystem.Name.Buffer =
  821. ALLOCATE_HEAP(
  822. Share->Type.FileSystem.Name.MaximumLength +
  823. Share->Type.FileSystem.OemName.MaximumLength,
  824. BlockTypeFSName
  825. );
  826. if ( Share->Type.FileSystem.Name.Buffer == NULL) {
  827. return;
  828. }
  829. RtlCopyMemory(
  830. Share->Type.FileSystem.Name.Buffer,
  831. FileSystemName,
  832. FileSystemNameLength
  833. );
  834. //
  835. // Generate the OEM version of the string to return to non-unicode
  836. // clients.
  837. //
  838. Share->Type.FileSystem.OemName.Buffer =
  839. (PCHAR)Share->Type.FileSystem.Name.Buffer +
  840. Share->Type.FileSystem.Name.MaximumLength;
  841. RtlUnicodeStringToOemString(
  842. &Share->Type.FileSystem.OemName,
  843. &Share->Type.FileSystem.Name,
  844. FALSE
  845. );
  846. //
  847. // Append a NUL character to the strings.
  848. //
  849. {
  850. PCHAR endOfBuffer;
  851. endOfBuffer = (PCHAR)Share->Type.FileSystem.Name.Buffer +
  852. Share->Type.FileSystem.Name.Length;
  853. *(PWCH)endOfBuffer = UNICODE_NULL;
  854. Share->Type.FileSystem.Name.Length += sizeof( UNICODE_NULL );
  855. }
  856. Share->Type.FileSystem.OemName.Length++;
  857. return;
  858. } // SrvFillInFileSystemName
  859. NTSTATUS
  860. SrvGetShareRootHandle (
  861. IN PSHARE Share
  862. )
  863. /*++
  864. Routine Description:
  865. This routine returns the root handle for a given share. If the
  866. root has been opened, return the existing handle. If not, open
  867. the share root directory and return the handle obtained.
  868. Arguments:
  869. Share - The share for which the root directory handle is to be returned.
  870. Return Value:
  871. Status of request.
  872. --*/
  873. {
  874. NTSTATUS status = STATUS_SUCCESS;
  875. PAGED_CODE( );
  876. if ( Share->ShareType != ShareTypeDisk ) {
  877. return STATUS_INVALID_DEVICE_REQUEST;
  878. }
  879. if ( Share->Removable ) {
  880. ACQUIRE_LOCK( &SrvShareLock );
  881. ++Share->CurrentRootHandleReferences;
  882. //
  883. // This is the first open
  884. //
  885. if ( Share->CurrentRootHandleReferences == 1 ) {
  886. ASSERT( Share->RootDirectoryHandle == NULL );
  887. //
  888. // Make sure we have a good handle to the media
  889. //
  890. SrvRefreshShareRootHandle( Share, &status );
  891. if( NT_SUCCESS( status ) ) {
  892. SrvReferenceShare( Share );
  893. if ( Share->QueryNamePrefixLength == -1 ) {
  894. //
  895. // Query the name associated with the share root directory.
  896. // The prefix is removed whenever the name of a file in the
  897. // share is queried. (The logical root must be preserved
  898. // for remote clients.)
  899. //
  900. GetShareQueryNamePrefix( Share );
  901. }
  902. } else {
  903. IF_DEBUG(ERRORS) {
  904. KdPrint(( "SrvGetShareRootHandle: NtOpenFile failed %x.\n",
  905. status ));
  906. }
  907. Share->CurrentRootHandleReferences--;
  908. }
  909. }
  910. RELEASE_LOCK( &SrvShareLock );
  911. }
  912. return status;
  913. } // SrvGetShareRootHandle
  914. BOOLEAN
  915. SrvRefreshShareRootHandle (
  916. IN PSHARE Share,
  917. OUT PNTSTATUS Status
  918. )
  919. /*++
  920. Routine Description:
  921. This routine tries to obtain a fresh share root handle, replacing the
  922. one that was there. The handle will need to be refreshed if, for instance,
  923. the volume has been dismounted and remounted.
  924. Arguments:
  925. Share - The share for which the root directory handle is to be refreshed.
  926. Returns:
  927. TRUE - if a new handle was generated
  928. FALSE - if a new handle was not generated
  929. --*/
  930. {
  931. HANDLE h;
  932. OBJECT_ATTRIBUTES objectAttributes;
  933. IO_STATUS_BLOCK iosb;
  934. PFILE_OBJECT fileObject;
  935. PDEVICE_OBJECT deviceObject;
  936. PAGED_CODE();
  937. *Status = STATUS_SUCCESS;
  938. if( Share->ShareType != ShareTypeDisk ) {
  939. return FALSE;
  940. }
  941. //
  942. // Open the root directory of the share. Future opens of files within
  943. // the share will be relative to the root of the share.
  944. //
  945. SrvInitializeObjectAttributes_U(
  946. &objectAttributes,
  947. &Share->NtPathName,
  948. OBJ_CASE_INSENSITIVE,
  949. NULL,
  950. NULL
  951. );
  952. *Status = NtOpenFile(
  953. &h,
  954. FILE_TRAVERSE,
  955. &objectAttributes,
  956. &iosb,
  957. FILE_SHARE_READ | FILE_SHARE_WRITE,
  958. FILE_DIRECTORY_FILE
  959. );
  960. if( !NT_SUCCESS( *Status ) ) {
  961. return FALSE;
  962. }
  963. //
  964. // Check the irp stack size needed to access this share.
  965. // If it is bigger than what we have allocated, fail
  966. // this share.
  967. //
  968. *Status = SrvVerifyDeviceStackSize(
  969. h,
  970. FALSE,
  971. &fileObject,
  972. &deviceObject,
  973. NULL
  974. );
  975. if ( !NT_SUCCESS( *Status )) {
  976. INTERNAL_ERROR(
  977. ERROR_LEVEL_EXPECTED,
  978. "SrvReferenceShareForTreeConnect: Verify Device Stack Size failed: %X\n",
  979. *Status,
  980. NULL
  981. );
  982. NtClose( h );
  983. return FALSE;
  984. }
  985. //
  986. // This handle looks suitable for use. Set it to be the handle
  987. // for this share
  988. //
  989. h = (PRFCB)InterlockedExchangePointer( &Share->RootDirectoryHandle, h );
  990. //
  991. // If we have picked up a different handle, we need to close it
  992. //
  993. if( h != 0 ) {
  994. NtClose( h );
  995. }
  996. return TRUE;
  997. }
  998. VOID
  999. GetShareQueryNamePrefix (
  1000. IN PSHARE Share
  1001. )
  1002. /*++
  1003. Routine Description:
  1004. This routine queries the name associated with the share root
  1005. directory. The prefix is removed whenever the name of a file in the
  1006. share is queried. (The logical root must be preserved for remote
  1007. clients.) For example, if the root of the share X is c:\shares\x,
  1008. then for a query of \\server\x\y, the file system will return
  1009. \shares\x\y, and we need to remove \shares\x and return just \y.
  1010. It is not sufficient to just remove the local path (e.g.,
  1011. \shares\x), because the file system may have a different idea of the
  1012. name of the root directory. For example, the Netware client
  1013. redirector prefixes the name with volume information from the
  1014. Netware server. So we have to query the filesystem's idea of the
  1015. name of the root to know what to strip off.
  1016. Arguments:
  1017. Share - The share for which the query name prefix length is desired.
  1018. Return Value:
  1019. None.
  1020. --*/
  1021. {
  1022. NTSTATUS status;
  1023. IO_STATUS_BLOCK iosb;
  1024. ULONG localBuffer[ (FIELD_OFFSET(FILE_NAME_INFORMATION,FileName) + 20) / sizeof( ULONG ) ];
  1025. PFILE_NAME_INFORMATION nameInfo;
  1026. ULONG nameInfoLength;
  1027. PAGED_CODE( );
  1028. //
  1029. // Do a short query to get the length of the name. This query will
  1030. // fail with STATUS_BUFFER_OVERFLOW unless the path to the share
  1031. // root is short (10 characters or less).
  1032. //
  1033. nameInfo = (PFILE_NAME_INFORMATION)localBuffer;
  1034. nameInfoLength = sizeof(localBuffer);
  1035. status = NtQueryInformationFile(
  1036. Share->RootDirectoryHandle,
  1037. &iosb,
  1038. nameInfo,
  1039. nameInfoLength,
  1040. FileNameInformation
  1041. );
  1042. if ( status == STATUS_BUFFER_OVERFLOW ) {
  1043. //
  1044. // We got an expected buffer overflow error. Allocate a buffer
  1045. // to hold the entire file name and redo the query.
  1046. //
  1047. nameInfoLength = sizeof(FILE_NAME_INFORMATION) + nameInfo->FileNameLength;
  1048. nameInfo = ALLOCATE_HEAP( nameInfoLength, BlockTypeNameInfo );
  1049. if ( nameInfo == NULL ) {
  1050. status = STATUS_INSUFF_SERVER_RESOURCES;
  1051. } else {
  1052. status = NtQueryInformationFile(
  1053. Share->RootDirectoryHandle,
  1054. &iosb,
  1055. nameInfo,
  1056. nameInfoLength,
  1057. FileNameInformation
  1058. );
  1059. }
  1060. }
  1061. if ( NT_SUCCESS(status) ) {
  1062. //
  1063. // We have the name. The length of this name is the length we
  1064. // want to strip from each query, unless the last character of
  1065. // the name is \, in which case we need to strip up to, but not
  1066. // including, the \.
  1067. //
  1068. Share->QueryNamePrefixLength = nameInfo->FileNameLength;
  1069. if ( nameInfo->FileName[nameInfo->FileNameLength/sizeof(WCHAR) - 1] == L'\\') {
  1070. Share->QueryNamePrefixLength -= sizeof(WCHAR);
  1071. }
  1072. } else {
  1073. //
  1074. // An unexpected error occurred. Just set the prefix length to 0.
  1075. //
  1076. Share->QueryNamePrefixLength = 0;
  1077. }
  1078. //
  1079. // If we allocated a temporary buffer, free it now.
  1080. //
  1081. if ( (nameInfo != NULL) && (nameInfo != (PFILE_NAME_INFORMATION)localBuffer) ) {
  1082. FREE_HEAP( nameInfo );
  1083. }
  1084. return;
  1085. } // GetShareQueryNamePrefix