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.

1387 lines
35 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. share->ShareVolumeHandle = NULL;
  321. share->RelativePath.Length = share->RelativePath.MaximumLength = 0;
  322. share->RelativePath.Buffer = NULL;
  323. share->SnapShotEpic = -1;
  324. INITIALIZE_REFERENCE_HISTORY( share );
  325. INCREMENT_DEBUG_STAT( SrvDbgStatistics.ShareInfo.Allocations );
  326. #ifdef SRVCATCH
  327. SrvIsMonitoredShare( share );
  328. #endif
  329. return;
  330. } // SrvAllocateShare
  331. VOID
  332. SrvCloseShare (
  333. IN PSHARE Share
  334. )
  335. /*++
  336. Routine Description:
  337. This function closes a share.
  338. Arguments:
  339. Share - Supplies a pointer to a share Block
  340. Return Value:
  341. None.
  342. --*/
  343. {
  344. PAGED_CODE( );
  345. ACQUIRE_LOCK( &SrvShareLock );
  346. //
  347. // If the share hasn't already been closed, do so now.
  348. //
  349. if ( GET_BLOCK_STATE(Share) == BlockStateActive ) {
  350. IF_DEBUG(BLOCK1) SrvPrint1( "Closing share at %p\n", Share );
  351. SET_BLOCK_STATE( Share, BlockStateClosing );
  352. RELEASE_LOCK( &SrvShareLock );
  353. //
  354. // Close all the tree connects on this share.
  355. //
  356. SrvCloseTreeConnectsOnShare( Share );
  357. //
  358. // Dereference the share--this will cause it to be freed when
  359. // all other references are closed.
  360. //
  361. SrvDereferenceShare( Share );
  362. INCREMENT_DEBUG_STAT( SrvDbgStatistics.ShareInfo.Closes );
  363. } else {
  364. RELEASE_LOCK( &SrvShareLock );
  365. }
  366. return;
  367. } // SrvCloseShare
  368. VOID
  369. SrvDereferenceShare (
  370. IN PSHARE Share
  371. )
  372. /*++
  373. Routine Description:
  374. This function decrements the reference count on a share. If the
  375. reference count goes to zero, the share block is deleted.
  376. Arguments:
  377. Share - Address of share
  378. Return Value:
  379. None.
  380. --*/
  381. {
  382. PAGED_CODE( );
  383. //
  384. // Enter a critical section and decrement the reference count on the
  385. // block.
  386. //
  387. ACQUIRE_LOCK( &SrvShareLock );
  388. IF_DEBUG(REFCNT) {
  389. SrvPrint2( "Dereferencing share %p; old refcnt %lx\n",
  390. Share, Share->BlockHeader.ReferenceCount );
  391. }
  392. ASSERT( GET_BLOCK_TYPE(Share) == BlockTypeShare );
  393. ASSERT( (LONG)Share->BlockHeader.ReferenceCount > 0 );
  394. UPDATE_REFERENCE_HISTORY( Share, TRUE );
  395. if ( --Share->BlockHeader.ReferenceCount == 0 ) {
  396. //
  397. // The new reference count is 0, meaning that it's time to
  398. // delete this block.
  399. //
  400. ASSERT( Share->CurrentUses == 0 );
  401. ASSERT( GET_BLOCK_STATE( Share ) != BlockStateActive );
  402. RELEASE_LOCK( &SrvShareLock );
  403. //
  404. // Remove the block from the global list.
  405. //
  406. SrvRemoveShare( Share );
  407. //
  408. // Free the share block.
  409. //
  410. SrvFreeShare( Share );
  411. } else {
  412. RELEASE_LOCK( &SrvShareLock );
  413. }
  414. return;
  415. } // SrvDereferenceShare
  416. VOID
  417. SrvDereferenceShareForTreeConnect (
  418. PSHARE Share
  419. )
  420. /*++
  421. Routine Description:
  422. This function decrements the reference count on a share block for
  423. the referenced pointer in a tree connect block. If this is the last
  424. reference by a tree connect to the share, the share root directory
  425. is closed.
  426. Arguments:
  427. Share - Address of share
  428. Return Value:
  429. None.
  430. --*/
  431. {
  432. PAGED_CODE( );
  433. ACQUIRE_LOCK( &SrvShareLock );
  434. //
  435. // Update the count of tree connects on the share.
  436. //
  437. ASSERT( Share->CurrentUses > 0 );
  438. Share->CurrentUses--;
  439. //
  440. // If this is the last reference by a tree connect to the share and
  441. // this is a disk share, close the share root directory handle.
  442. //
  443. if ( Share->CurrentUses == 0 && Share->ShareType == ShareTypeDisk ) {
  444. if ( !Share->Removable ) {
  445. SRVDBG_RELEASE_HANDLE( Share->RootDirectoryHandle, "RTD", 5, Share );
  446. SrvNtClose( Share->RootDirectoryHandle, FALSE );
  447. }
  448. Share->RootDirectoryHandle = NULL;
  449. }
  450. //
  451. // Dereference the share and return.
  452. //
  453. SrvDereferenceShare( Share );
  454. RELEASE_LOCK( &SrvShareLock );
  455. return;
  456. } // SrvDereferenceShareForTreeConnect
  457. VOID
  458. SrvFreeShare (
  459. IN PSHARE Share
  460. )
  461. /*++
  462. Routine Description:
  463. This function returns a Share Block to the FSP heap.
  464. Arguments:
  465. Share - Address of share
  466. Return Value:
  467. None.
  468. --*/
  469. {
  470. PLIST_ENTRY shareList;
  471. PAGED_CODE( );
  472. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Share, BlockTypeGarbage, BlockStateDead, -1 );
  473. DEBUG Share->BlockHeader.ReferenceCount = (ULONG)-1;
  474. TERMINATE_REFERENCE_HISTORY( Share );
  475. // Delete all the SnapShot shares
  476. shareList = Share->SnapShots.Flink;
  477. while( shareList != &Share->SnapShots )
  478. {
  479. PSHARE_SNAPSHOT snapShare = CONTAINING_RECORD( shareList, SHARE_SNAPSHOT, SnapShotList );
  480. shareList = shareList->Flink;
  481. SrvSnapRemoveShare( snapShare );
  482. }
  483. if( Share->ShareVolumeHandle != NULL )
  484. {
  485. NtClose( Share->ShareVolumeHandle );
  486. Share->ShareVolumeHandle = NULL;
  487. }
  488. //
  489. // Remove storage for the remark, if any.
  490. //
  491. if ( Share->Remark.Buffer != NULL ) {
  492. FREE_HEAP( Share->Remark.Buffer );
  493. }
  494. //
  495. // Remove storage for the file security descriptor, if any.
  496. //
  497. if ( Share->FileSecurityDescriptor != NULL ) {
  498. FREE_HEAP( Share->FileSecurityDescriptor );
  499. }
  500. //
  501. // Cleanup the file security descriptor lock
  502. //
  503. if( Share->SecurityDescriptorLock )
  504. {
  505. DELETE_LOCK( Share->SecurityDescriptorLock );
  506. DEALLOCATE_NONPAGED_POOL( Share->SecurityDescriptorLock );
  507. }
  508. //
  509. // Cleanup the SnapShot lock
  510. //
  511. if( Share->SnapShotLock )
  512. {
  513. DELETE_LOCK( Share->SnapShotLock );
  514. DEALLOCATE_NONPAGED_POOL( Share->SnapShotLock );
  515. }
  516. //
  517. // Remove storage for the filesystem name
  518. //
  519. if ( Share->Type.FileSystem.Name.Buffer != NULL ) {
  520. FREE_HEAP( Share->Type.FileSystem.Name.Buffer );
  521. }
  522. FREE_HEAP( Share );
  523. IF_DEBUG(HEAP) {
  524. SrvPrint1( "SrvFreeShare: Freed share block at %p\n", Share );
  525. }
  526. INCREMENT_DEBUG_STAT( SrvDbgStatistics.ShareInfo.Frees );
  527. return;
  528. } // SrvFreeShare
  529. VOID
  530. SrvReferenceShare (
  531. PSHARE Share
  532. )
  533. /*++
  534. Routine Description:
  535. This function increments the reference count on a share block.
  536. Arguments:
  537. Share - Address of share
  538. Return Value:
  539. None.
  540. --*/
  541. {
  542. PAGED_CODE( );
  543. //
  544. // Enter a critical section and increment the reference count on the
  545. // share.
  546. //
  547. ACQUIRE_LOCK( &SrvShareLock );
  548. ASSERT( (LONG)Share->BlockHeader.ReferenceCount > 0 );
  549. ASSERT( GET_BLOCK_TYPE(Share) == BlockTypeShare );
  550. // ASSERT( GET_BLOCK_STATE(Share) == BlockStateActive );
  551. UPDATE_REFERENCE_HISTORY( Share, FALSE );
  552. Share->BlockHeader.ReferenceCount++;
  553. IF_DEBUG(REFCNT) {
  554. SrvPrint2( "Referencing share %p; new refcnt %lx\n",
  555. Share, Share->BlockHeader.ReferenceCount );
  556. }
  557. RELEASE_LOCK( &SrvShareLock );
  558. return;
  559. } // SrvReferenceShare
  560. NTSTATUS
  561. SrvReferenceShareForTreeConnect (
  562. PSHARE Share
  563. )
  564. /*++
  565. Routine Description:
  566. This function increments the reference count on a share block for
  567. the referenced pointer in a tree connect block. If this is the
  568. first tree connect to reference the share, the share root directory
  569. is opened.
  570. Arguments:
  571. Share - Address of share
  572. Return Value:
  573. None.
  574. --*/
  575. {
  576. NTSTATUS status;
  577. OBJECT_ATTRIBUTES objectAttributes;
  578. IO_STATUS_BLOCK iosb;
  579. PFILE_FS_ATTRIBUTE_INFORMATION attributeInfo;
  580. CHAR buffer[ FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) + 32 ];
  581. PVOID allocatedBuffer = NULL;
  582. PFILE_OBJECT fileObject;
  583. PDEVICE_OBJECT deviceObject;
  584. PAGED_CODE( );
  585. ACQUIRE_LOCK( &SrvShareLock );
  586. //
  587. // Update the count of tree connects on the share.
  588. //
  589. Share->CurrentUses++;
  590. //
  591. // Check if this is the first tree connect to the share.
  592. //
  593. if ( Share->CurrentUses > 1 ) {
  594. //
  595. // There are already open tree connects on the share. Just
  596. // reference the share and return.
  597. //
  598. SrvReferenceShare( Share );
  599. goto done;
  600. }
  601. //
  602. // If this is not a disk share, then we do not need to open the
  603. // share root directory, so reference the share and return.
  604. //
  605. if ( Share->ShareType != ShareTypeDisk || Share->Removable ) {
  606. SrvReferenceShare( Share );
  607. goto done;
  608. }
  609. //
  610. // This is the first tree connect, so we need to open the share root
  611. // directory. Future opens of files within the share will be relative
  612. // to the root of the share.
  613. //
  614. Share->RootDirectoryHandle = NULL;
  615. if( SrvRefreshShareRootHandle( Share, &status ) == FALSE ) {
  616. Share->CurrentUses--;
  617. RELEASE_LOCK( &SrvShareLock );
  618. return status;
  619. }
  620. //
  621. // All is well -- we are now going to return STATUS_SUCCESS no matter what!
  622. //
  623. SrvReferenceShare( Share );
  624. if ( Share->QueryNamePrefixLength == -1 ) {
  625. //
  626. // Query the name associated with the share root directory.
  627. // The prefix is removed whenever the name of a file in the
  628. // share is queried. (The logical root must be preserved
  629. // for remote clients.)
  630. //
  631. GetShareQueryNamePrefix( Share );
  632. }
  633. //
  634. // Now extract the name of the file system, so that it can be returned
  635. // in the TreeConnectAndX response.
  636. //
  637. //
  638. if ( Share->Type.FileSystem.Name.Buffer == NULL ) {
  639. attributeInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)buffer;
  640. status = NtQueryVolumeInformationFile(
  641. Share->RootDirectoryHandle,
  642. &iosb,
  643. attributeInfo,
  644. sizeof( buffer ),
  645. FileFsAttributeInformation
  646. );
  647. if ( status == STATUS_BUFFER_OVERFLOW ) {
  648. //
  649. // The file system information was too large to fit in our small
  650. // stack buffer. Allocate an ample buffer and try again.
  651. //
  652. allocatedBuffer = ALLOCATE_HEAP(
  653. FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION,FileSystemName) +
  654. attributeInfo->FileSystemNameLength,
  655. BlockTypeVolumeInformation
  656. );
  657. if ( allocatedBuffer == NULL ) {
  658. //
  659. // Couldn't allocate the buffer. Give up.
  660. //
  661. goto done;
  662. }
  663. status = NtQueryVolumeInformationFile(
  664. Share->RootDirectoryHandle,
  665. &iosb,
  666. allocatedBuffer,
  667. FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) +
  668. attributeInfo->FileSystemNameLength,
  669. FileFsAttributeInformation
  670. );
  671. if ( !NT_SUCCESS( status ) ) {
  672. goto done;
  673. }
  674. attributeInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)allocatedBuffer;
  675. } else if ( !NT_SUCCESS( status ) ) {
  676. //
  677. // Some other, unexpected error occured. Give up.
  678. //
  679. goto done;
  680. }
  681. //
  682. // Fill in the file system name
  683. //
  684. SrvFillInFileSystemName(
  685. Share,
  686. attributeInfo->FileSystemName,
  687. attributeInfo->FileSystemNameLength
  688. );
  689. }
  690. done:
  691. if ( allocatedBuffer != NULL ) {
  692. FREE_HEAP( allocatedBuffer );
  693. }
  694. RELEASE_LOCK( &SrvShareLock );
  695. return STATUS_SUCCESS;
  696. } // SrvReferenceShareForTreeConnect
  697. VOID
  698. SrvFillInFileSystemName (
  699. IN PSHARE Share,
  700. IN PWSTR FileSystemName,
  701. IN ULONG FileSystemNameLength
  702. )
  703. /*++
  704. Routine Description:
  705. This function fills in the stores the given file system name into the
  706. share block.
  707. Arguments:
  708. Share - Address of share
  709. FileSystemName - A string containing the name of the file system
  710. FileSystemNameLength - Length of the above string
  711. Return Value:
  712. None.
  713. --*/
  714. {
  715. PAGED_CODE( );
  716. //
  717. // If we have a FATxx filesystem, we need to return FAT back to the clients,
  718. // else they will not believe they can create long names. I know, I know....
  719. //
  720. if( (FileSystemNameLength > 3 * sizeof( WCHAR ) ) &&
  721. (FileSystemName[0] == L'F' || FileSystemName[0] == L'f') &&
  722. (FileSystemName[1] == L'A' || FileSystemName[0] == L'a') &&
  723. (FileSystemName[2] == L'T' || FileSystemName[0] == L't') ) {
  724. FileSystemNameLength = 3 * sizeof( WCHAR );
  725. FileSystemName[3] = UNICODE_NULL;
  726. }
  727. //
  728. // Allocate enough storage for the ANSI and Unicode representations.
  729. //
  730. Share->Type.FileSystem.Name.Length = (USHORT)FileSystemNameLength;
  731. Share->Type.FileSystem.Name.MaximumLength =
  732. (USHORT)(FileSystemNameLength + sizeof( UNICODE_NULL ));
  733. Share->Type.FileSystem.Name.Buffer = FileSystemName;
  734. Share->Type.FileSystem.OemName.MaximumLength =
  735. (USHORT)RtlUnicodeStringToOemSize( &Share->Type.FileSystem.Name );
  736. Share->Type.FileSystem.Name.Buffer =
  737. ALLOCATE_HEAP(
  738. Share->Type.FileSystem.Name.MaximumLength +
  739. Share->Type.FileSystem.OemName.MaximumLength,
  740. BlockTypeFSName
  741. );
  742. if ( Share->Type.FileSystem.Name.Buffer == NULL) {
  743. return;
  744. }
  745. RtlCopyMemory(
  746. Share->Type.FileSystem.Name.Buffer,
  747. FileSystemName,
  748. FileSystemNameLength
  749. );
  750. //
  751. // Generate the OEM version of the string to return to non-unicode
  752. // clients.
  753. //
  754. Share->Type.FileSystem.OemName.Buffer =
  755. (PCHAR)Share->Type.FileSystem.Name.Buffer +
  756. Share->Type.FileSystem.Name.MaximumLength;
  757. RtlUnicodeStringToOemString(
  758. &Share->Type.FileSystem.OemName,
  759. &Share->Type.FileSystem.Name,
  760. FALSE
  761. );
  762. //
  763. // Append a NUL character to the strings.
  764. //
  765. {
  766. PCHAR endOfBuffer;
  767. endOfBuffer = (PCHAR)Share->Type.FileSystem.Name.Buffer +
  768. Share->Type.FileSystem.Name.Length;
  769. *(PWCH)endOfBuffer = UNICODE_NULL;
  770. Share->Type.FileSystem.Name.Length += sizeof( UNICODE_NULL );
  771. }
  772. Share->Type.FileSystem.OemName.Length++;
  773. return;
  774. } // SrvFillInFileSystemName
  775. NTSTATUS
  776. SrvGetShareRootHandle (
  777. IN PSHARE Share
  778. )
  779. /*++
  780. Routine Description:
  781. This routine returns the root handle for a given share. If the
  782. root has been opened, return the existing handle. If not, open
  783. the share root directory and return the handle obtained.
  784. Arguments:
  785. Share - The share for which the root directory handle is to be returned.
  786. Return Value:
  787. Status of request.
  788. --*/
  789. {
  790. NTSTATUS status = STATUS_SUCCESS;
  791. PAGED_CODE( );
  792. if ( Share->ShareType != ShareTypeDisk ) {
  793. return STATUS_INVALID_DEVICE_REQUEST;
  794. }
  795. if ( Share->Removable ) {
  796. ACQUIRE_LOCK( &SrvShareLock );
  797. ++Share->CurrentRootHandleReferences;
  798. //
  799. // This is the first open
  800. //
  801. if ( Share->CurrentRootHandleReferences == 1 ) {
  802. ASSERT( Share->RootDirectoryHandle == NULL );
  803. //
  804. // Make sure we have a good handle to the media
  805. //
  806. SrvRefreshShareRootHandle( Share, &status );
  807. if( NT_SUCCESS( status ) ) {
  808. SrvReferenceShare( Share );
  809. if ( Share->QueryNamePrefixLength == -1 ) {
  810. //
  811. // Query the name associated with the share root directory.
  812. // The prefix is removed whenever the name of a file in the
  813. // share is queried. (The logical root must be preserved
  814. // for remote clients.)
  815. //
  816. GetShareQueryNamePrefix( Share );
  817. }
  818. } else {
  819. IF_DEBUG(ERRORS) {
  820. KdPrint(( "SrvGetShareRootHandle: NtOpenFile failed %x.\n",
  821. status ));
  822. }
  823. Share->CurrentRootHandleReferences--;
  824. }
  825. }
  826. RELEASE_LOCK( &SrvShareLock );
  827. }
  828. return status;
  829. } // SrvGetShareRootHandle
  830. BOOLEAN
  831. SrvRefreshShareRootHandle (
  832. IN PSHARE Share,
  833. OUT PNTSTATUS Status
  834. )
  835. /*++
  836. Routine Description:
  837. This routine tries to obtain a fresh share root handle, replacing the
  838. one that was there. The handle will need to be refreshed if, for instance,
  839. the volume has been dismounted and remounted.
  840. Arguments:
  841. Share - The share for which the root directory handle is to be refreshed.
  842. Returns:
  843. TRUE - if a new handle was generated
  844. FALSE - if a new handle was not generated
  845. --*/
  846. {
  847. HANDLE h;
  848. OBJECT_ATTRIBUTES objectAttributes;
  849. IO_STATUS_BLOCK iosb;
  850. PFILE_OBJECT fileObject;
  851. PDEVICE_OBJECT deviceObject;
  852. PAGED_CODE();
  853. *Status = STATUS_SUCCESS;
  854. if( Share->ShareType != ShareTypeDisk ) {
  855. return FALSE;
  856. }
  857. //
  858. // Open the root directory of the share. Future opens of files within
  859. // the share will be relative to the root of the share.
  860. //
  861. SrvInitializeObjectAttributes_U(
  862. &objectAttributes,
  863. &Share->NtPathName,
  864. OBJ_CASE_INSENSITIVE,
  865. NULL,
  866. NULL
  867. );
  868. *Status = NtOpenFile(
  869. &h,
  870. FILE_TRAVERSE,
  871. &objectAttributes,
  872. &iosb,
  873. FILE_SHARE_READ | FILE_SHARE_WRITE,
  874. FILE_DIRECTORY_FILE
  875. );
  876. if( !NT_SUCCESS( *Status ) ) {
  877. return FALSE;
  878. }
  879. //
  880. // Check the irp stack size needed to access this share.
  881. // If it is bigger than what we have allocated, fail
  882. // this share.
  883. //
  884. *Status = SrvVerifyDeviceStackSize(
  885. h,
  886. FALSE,
  887. &fileObject,
  888. &deviceObject,
  889. NULL
  890. );
  891. if ( !NT_SUCCESS( *Status )) {
  892. INTERNAL_ERROR(
  893. ERROR_LEVEL_EXPECTED,
  894. "SrvReferenceShareForTreeConnect: Verify Device Stack Size failed: %X\n",
  895. *Status,
  896. NULL
  897. );
  898. NtClose( h );
  899. return FALSE;
  900. }
  901. //
  902. // This handle looks suitable for use. Set it to be the handle
  903. // for this share
  904. //
  905. h = (PRFCB)InterlockedExchangePointer( &Share->RootDirectoryHandle, h );
  906. //
  907. // If we have picked up a different handle, we need to close it
  908. //
  909. if( h != 0 ) {
  910. NtClose( h );
  911. }
  912. return TRUE;
  913. }
  914. VOID
  915. GetShareQueryNamePrefix (
  916. IN PSHARE Share
  917. )
  918. /*++
  919. Routine Description:
  920. This routine queries the name associated with the share root
  921. directory. The prefix is removed whenever the name of a file in the
  922. share is queried. (The logical root must be preserved for remote
  923. clients.) For example, if the root of the share X is c:\shares\x,
  924. then for a query of \\server\x\y, the file system will return
  925. \shares\x\y, and we need to remove \shares\x and return just \y.
  926. It is not sufficient to just remove the local path (e.g.,
  927. \shares\x), because the file system may have a different idea of the
  928. name of the root directory. For example, the Netware client
  929. redirector prefixes the name with volume information from the
  930. Netware server. So we have to query the filesystem's idea of the
  931. name of the root to know what to strip off.
  932. Arguments:
  933. Share - The share for which the query name prefix length is desired.
  934. Return Value:
  935. None.
  936. --*/
  937. {
  938. NTSTATUS status;
  939. IO_STATUS_BLOCK iosb;
  940. ULONG localBuffer[ (FIELD_OFFSET(FILE_NAME_INFORMATION,FileName) + 20) / sizeof( ULONG ) ];
  941. PFILE_NAME_INFORMATION nameInfo;
  942. ULONG nameInfoLength;
  943. PAGED_CODE( );
  944. //
  945. // Do a short query to get the length of the name. This query will
  946. // fail with STATUS_BUFFER_OVERFLOW unless the path to the share
  947. // root is short (10 characters or less).
  948. //
  949. nameInfo = (PFILE_NAME_INFORMATION)localBuffer;
  950. nameInfoLength = sizeof(localBuffer);
  951. status = NtQueryInformationFile(
  952. Share->RootDirectoryHandle,
  953. &iosb,
  954. nameInfo,
  955. nameInfoLength,
  956. FileNameInformation
  957. );
  958. if ( status == STATUS_BUFFER_OVERFLOW ) {
  959. //
  960. // We got an expected buffer overflow error. Allocate a buffer
  961. // to hold the entire file name and redo the query.
  962. //
  963. nameInfoLength = sizeof(FILE_NAME_INFORMATION) + nameInfo->FileNameLength;
  964. nameInfo = ALLOCATE_HEAP( nameInfoLength, BlockTypeNameInfo );
  965. if ( nameInfo == NULL ) {
  966. status = STATUS_INSUFF_SERVER_RESOURCES;
  967. } else {
  968. status = NtQueryInformationFile(
  969. Share->RootDirectoryHandle,
  970. &iosb,
  971. nameInfo,
  972. nameInfoLength,
  973. FileNameInformation
  974. );
  975. }
  976. }
  977. if ( NT_SUCCESS(status) ) {
  978. //
  979. // We have the name. The length of this name is the length we
  980. // want to strip from each query, unless the last character of
  981. // the name is \, in which case we need to strip up to, but not
  982. // including, the \.
  983. //
  984. Share->QueryNamePrefixLength = nameInfo->FileNameLength;
  985. if ( nameInfo->FileName[nameInfo->FileNameLength/sizeof(WCHAR) - 1] == L'\\') {
  986. Share->QueryNamePrefixLength -= sizeof(WCHAR);
  987. }
  988. } else {
  989. //
  990. // An unexpected error occurred. Just set the prefix length to 0.
  991. //
  992. Share->QueryNamePrefixLength = 0;
  993. }
  994. //
  995. // If we allocated a temporary buffer, free it now.
  996. //
  997. if ( (nameInfo != NULL) && (nameInfo != (PFILE_NAME_INFORMATION)localBuffer) ) {
  998. FREE_HEAP( nameInfo );
  999. }
  1000. return;
  1001. } // GetShareQueryNamePrefix