Windows NT 4.0 source code leak
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.

1286 lines
30 KiB

4 years ago
  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. #pragma hdrstop
  14. #define BugCheckFileId SRV_FILE_BLKSHARE
  15. VOID
  16. GetShareQueryNamePrefix (
  17. PSHARE Share
  18. );
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text( PAGE, SrvAllocateShare )
  21. #pragma alloc_text( PAGE, SrvCheckAndReferenceShare )
  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, GetShareQueryNamePrefix )
  31. #endif
  32. VOID
  33. SrvAllocateShare (
  34. OUT PSHARE *Share,
  35. IN PUNICODE_STRING ShareName,
  36. IN PUNICODE_STRING NtPathName,
  37. IN PUNICODE_STRING DosPathName,
  38. IN PUNICODE_STRING Remark,
  39. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  40. IN PSECURITY_DESCRIPTOR FileSecurityDescriptor OPTIONAL,
  41. IN SHARE_TYPE ShareType
  42. )
  43. /*++
  44. Routine Description:
  45. This function allocates a Share Block from the FSP heap.
  46. Arguments:
  47. Share - Returns a pointer to the share block, or NULL if no
  48. heap space was available.
  49. ShareName - Supplies the name of the share.
  50. NtPathName - Supplies a fully qualified directory path in NT format
  51. to the share.
  52. DosPathName - Supplies a fully qualified directory path in DOS
  53. format to the share.
  54. Remark - a comment to store with the share.
  55. SecurityDescriptor - security descriptor used for determining whether
  56. a user can connect to this share.
  57. FileSecurityDescriptor - security descriptor used for determining the
  58. permissions of clients on files in this share.
  59. ShareType - Enumerated type indicating type of resource.
  60. Return Value:
  61. None.
  62. --*/
  63. {
  64. CLONG blockSize;
  65. PSHARE share;
  66. ULONG securityDescriptorLength;
  67. ULONG fileSdLength;
  68. PAGED_CODE( );
  69. //
  70. // Attempt to allocate from the heap. Note that space for the
  71. // remark (if any) is allocated separately. Allocate extra space
  72. // for the security descriptor since it must be longword aligned,
  73. // and there may be padding between the DOS path name and the
  74. // security descriptor.
  75. //
  76. securityDescriptorLength = RtlLengthSecurityDescriptor( SecurityDescriptor );
  77. blockSize = sizeof(SHARE) +
  78. ShareName->Length + sizeof(WCHAR) +
  79. NtPathName->Length + sizeof(WCHAR) +
  80. DosPathName->Length + sizeof(WCHAR) +
  81. securityDescriptorLength + sizeof(ULONG);
  82. share = ALLOCATE_HEAP( blockSize, BlockTypeShare );
  83. *Share = share;
  84. if ( share == NULL ) {
  85. INTERNAL_ERROR(
  86. ERROR_LEVEL_EXPECTED,
  87. "SrvAllocateShare: Unable to allocate %d bytes from heap.",
  88. blockSize,
  89. NULL
  90. );
  91. return;
  92. }
  93. IF_DEBUG(HEAP) {
  94. SrvPrint1( "SrvAllocateShare: Allocated share at %lx\n", share );
  95. }
  96. RtlZeroMemory( share, blockSize );
  97. SET_BLOCK_TYPE_STATE_SIZE( share, BlockTypeShare, BlockStateActive, blockSize );
  98. share->BlockHeader.ReferenceCount = 2; // allow for Active status
  99. // and caller's pointer
  100. //
  101. // Save the share type.
  102. //
  103. share->ShareType = ShareType;
  104. //
  105. // Indicate that we've haven't determined the share's query name prefix yet.
  106. //
  107. share->QueryNamePrefixLength = -1;
  108. //
  109. // Put the share name after the share block.
  110. //
  111. share->ShareName.Buffer = (PWSTR)(share + 1);
  112. share->ShareName.Length = ShareName->Length;
  113. share->ShareName.MaximumLength =
  114. (SHORT)(ShareName->Length + sizeof(WCHAR));
  115. RtlCopyMemory(
  116. share->ShareName.Buffer,
  117. ShareName->Buffer,
  118. ShareName->Length
  119. );
  120. //
  121. // Put the NT path name after share name. If no NT path name was
  122. // specified, just set the path name string to NULL.
  123. //
  124. share->NtPathName.Buffer = (PWSTR)((PCHAR)share->ShareName.Buffer +
  125. share->ShareName.MaximumLength);
  126. share->NtPathName.Length = NtPathName->Length;
  127. share->NtPathName.MaximumLength = (SHORT)(NtPathName->Length +
  128. sizeof(WCHAR));
  129. RtlCopyMemory(
  130. share->NtPathName.Buffer,
  131. NtPathName->Buffer,
  132. NtPathName->Length
  133. );
  134. //
  135. // Put the DOS path name after share name. If no DOS path name was
  136. // specified, just set the path name string to NULL.
  137. //
  138. share->DosPathName.Buffer = (PWSTR)((PCHAR)share->NtPathName.Buffer +
  139. share->NtPathName.MaximumLength);
  140. share->DosPathName.Length = DosPathName->Length;
  141. share->DosPathName.MaximumLength = (SHORT)(DosPathName->Length +
  142. sizeof(WCHAR));
  143. RtlCopyMemory(
  144. share->DosPathName.Buffer,
  145. DosPathName->Buffer,
  146. DosPathName->Length
  147. );
  148. //
  149. // Allocate space for the remark and copy over the remark. We
  150. // cannot put the remark after the share block because the remark is
  151. // settable by NetShareSetInfo. It is possible for the storage
  152. // required for the remark to increase.
  153. //
  154. // If no remark was passed in, do not allocate space. Just set up
  155. // a null string to describe it.
  156. //
  157. if ( ARGUMENT_PRESENT( Remark ) ) {
  158. share->Remark.Buffer = ALLOCATE_HEAP(
  159. Remark->Length + sizeof(*Remark->Buffer),
  160. BlockTypeDataBuffer
  161. );
  162. if ( share->Remark.Buffer == NULL ) {
  163. INTERNAL_ERROR(
  164. ERROR_LEVEL_EXPECTED,
  165. "SrvAllocateShare: Unable to allocate %d bytes from heap.",
  166. blockSize,
  167. NULL
  168. );
  169. SrvFreeShare( share );
  170. *Share = NULL;
  171. return;
  172. }
  173. share->Remark.Length = Remark->Length;
  174. share->Remark.MaximumLength =
  175. (SHORT)(Remark->Length + sizeof(*Remark->Buffer));
  176. RtlCopyMemory(
  177. share->Remark.Buffer,
  178. Remark->Buffer,
  179. Remark->Length
  180. );
  181. *(PWCH)((PCHAR)share->Remark.Buffer + share->Remark.Length) = 0;
  182. } else {
  183. RtlInitUnicodeString( &share->Remark, NULL );
  184. }
  185. //
  186. // Set up the security descriptor for the share. It must be longword-
  187. // aligned to be used in various calls.
  188. //
  189. share->SecurityDescriptor =
  190. (PSECURITY_DESCRIPTOR)( ((ULONG)share->DosPathName.Buffer +
  191. share->DosPathName.MaximumLength + 3) & ~3);
  192. RtlCopyMemory(
  193. share->SecurityDescriptor,
  194. SecurityDescriptor,
  195. securityDescriptorLength
  196. );
  197. //
  198. // Set up the file security descriptor for the share. We did not allocate
  199. // space for the file SD because this is settable and thus cannot have
  200. // preallocated space.
  201. //
  202. ASSERT( share->FileSecurityDescriptor == NULL );
  203. if ( ARGUMENT_PRESENT( FileSecurityDescriptor) ) {
  204. fileSdLength = RtlLengthSecurityDescriptor( FileSecurityDescriptor );
  205. share->FileSecurityDescriptor = ALLOCATE_HEAP(
  206. fileSdLength,
  207. BlockTypeDataBuffer
  208. );
  209. if ( share->FileSecurityDescriptor == NULL ) {
  210. INTERNAL_ERROR(
  211. ERROR_LEVEL_EXPECTED,
  212. "SrvAllocateShare: Unable to allocate %d bytes from heap.",
  213. fileSdLength,
  214. NULL
  215. );
  216. SrvFreeShare( share );
  217. *Share = NULL;
  218. return;
  219. }
  220. RtlCopyMemory(
  221. share->FileSecurityDescriptor,
  222. FileSecurityDescriptor,
  223. fileSdLength
  224. );
  225. }
  226. //
  227. // Initialize the share's tree connect list.
  228. //
  229. InitializeListHead( &share->TreeConnectList );
  230. INITIALIZE_REFERENCE_HISTORY( share );
  231. INCREMENT_DEBUG_STAT( SrvDbgStatistics.ShareInfo.Allocations );
  232. return;
  233. } // SrvAllocateShare
  234. BOOLEAN
  235. SrvCheckAndReferenceShare (
  236. PSHARE Share
  237. )
  238. /*++
  239. Routine Description:
  240. This function atomically verifies that a share is active and
  241. increments the reference count on the share if it is.
  242. Arguments:
  243. Share - Address of share
  244. Return Value:
  245. BOOLEAN - Returns TRUE if the share is active, FALSE otherwise.
  246. --*/
  247. {
  248. PAGED_CODE( );
  249. //
  250. // Acquire the lock that guards the share's state field.
  251. //
  252. ACQUIRE_LOCK( &SrvShareLock );
  253. //
  254. // If the share is active, reference it and return TRUE.
  255. //
  256. if ( GET_BLOCK_STATE(Share) == BlockStateActive ) {
  257. SrvReferenceShare( Share );
  258. RELEASE_LOCK( &SrvShareLock );
  259. return TRUE;
  260. }
  261. //
  262. // The share isn't active. Return FALSE.
  263. //
  264. RELEASE_LOCK( &SrvShareLock );
  265. return FALSE;
  266. } // SrvCheckAndReferenceShare
  267. VOID
  268. SrvCloseShare (
  269. IN PSHARE Share
  270. )
  271. /*++
  272. Routine Description:
  273. This function closes a share.
  274. Arguments:
  275. Share - Supplies a pointer to a share Block
  276. Return Value:
  277. None.
  278. --*/
  279. {
  280. PAGED_CODE( );
  281. ACQUIRE_LOCK( &SrvShareLock );
  282. //
  283. // If the share hasn't already been closed, do so now.
  284. //
  285. if ( GET_BLOCK_STATE(Share) == BlockStateActive ) {
  286. IF_DEBUG(BLOCK1) SrvPrint1( "Closing share at %lx\n", Share );
  287. SET_BLOCK_STATE( Share, BlockStateClosing );
  288. RELEASE_LOCK( &SrvShareLock );
  289. //
  290. // Close all the tree connects on this share.
  291. //
  292. SrvCloseTreeConnectsOnShare( Share );
  293. //
  294. // Dereference the share--this will cause it to be freed when
  295. // all other references are closed.
  296. //
  297. SrvDereferenceShare( Share );
  298. INCREMENT_DEBUG_STAT( SrvDbgStatistics.ShareInfo.Closes );
  299. } else {
  300. RELEASE_LOCK( &SrvShareLock );
  301. }
  302. return;
  303. } // SrvCloseShare
  304. VOID
  305. SrvDereferenceShare (
  306. IN PSHARE Share
  307. )
  308. /*++
  309. Routine Description:
  310. This function decrements the reference count on a share. If the
  311. reference count goes to zero, the share block is deleted.
  312. Arguments:
  313. Share - Address of share
  314. Return Value:
  315. None.
  316. --*/
  317. {
  318. PAGED_CODE( );
  319. //
  320. // Enter a critical section and decrement the reference count on the
  321. // block.
  322. //
  323. ACQUIRE_LOCK( &SrvShareLock );
  324. IF_DEBUG(REFCNT) {
  325. SrvPrint2( "Dereferencing share %lx; old refcnt %lx\n",
  326. Share, Share->BlockHeader.ReferenceCount );
  327. }
  328. ASSERT( GET_BLOCK_TYPE(Share) == BlockTypeShare );
  329. ASSERT( (LONG)Share->BlockHeader.ReferenceCount > 0 );
  330. UPDATE_REFERENCE_HISTORY( Share, TRUE );
  331. if ( --Share->BlockHeader.ReferenceCount == 0 ) {
  332. //
  333. // The new reference count is 0, meaning that it's time to
  334. // delete this block.
  335. //
  336. ASSERT( Share->CurrentUses == 0 );
  337. ASSERT( GET_BLOCK_STATE( Share ) != BlockStateActive );
  338. RELEASE_LOCK( &SrvShareLock );
  339. //
  340. // Remove the block from the global list.
  341. //
  342. SrvRemoveShare( Share );
  343. //
  344. // Free the share block.
  345. //
  346. SrvFreeShare( Share );
  347. } else {
  348. RELEASE_LOCK( &SrvShareLock );
  349. }
  350. return;
  351. } // SrvDereferenceShare
  352. VOID
  353. SrvDereferenceShareForTreeConnect (
  354. PSHARE Share
  355. )
  356. /*++
  357. Routine Description:
  358. This function decrements the reference count on a share block for
  359. the referenced pointer in a tree connect block. If this is the last
  360. reference by a tree connect to the share, the share root directory
  361. is closed.
  362. Arguments:
  363. Share - Address of share
  364. Return Value:
  365. None.
  366. --*/
  367. {
  368. PAGED_CODE( );
  369. ACQUIRE_LOCK( &SrvShareLock );
  370. //
  371. // Update the count of tree connects on the share.
  372. //
  373. ASSERT( Share->CurrentUses > 0 );
  374. Share->CurrentUses--;
  375. //
  376. // If this is the last reference by a tree connect to the share and
  377. // this is a disk share, close the share root directory handle.
  378. //
  379. if ( Share->CurrentUses == 0 && Share->ShareType == ShareTypeDisk ) {
  380. if ( !Share->Removable ) {
  381. SRVDBG_RELEASE_HANDLE( Share->RootDirectoryHandle, "RTD", 5, Share );
  382. SrvNtClose( Share->RootDirectoryHandle, FALSE );
  383. }
  384. Share->RootDirectoryHandle = NULL;
  385. }
  386. //
  387. // Dereference the share and return.
  388. //
  389. SrvDereferenceShare( Share );
  390. RELEASE_LOCK( &SrvShareLock );
  391. return;
  392. } // SrvDereferenceShareForTreeConnect
  393. VOID
  394. SrvFreeShare (
  395. IN PSHARE Share
  396. )
  397. /*++
  398. Routine Description:
  399. This function returns a Share Block to the FSP heap.
  400. Arguments:
  401. Share - Address of share
  402. Return Value:
  403. None.
  404. --*/
  405. {
  406. PAGED_CODE( );
  407. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Share, BlockTypeGarbage, BlockStateDead, -1 );
  408. DEBUG Share->BlockHeader.ReferenceCount = (ULONG)-1;
  409. TERMINATE_REFERENCE_HISTORY( Share );
  410. //
  411. // Remove storage for the remark, if any.
  412. //
  413. if ( Share->Remark.Buffer != NULL ) {
  414. FREE_HEAP( Share->Remark.Buffer );
  415. }
  416. //
  417. // Remove storage for the file security descriptor, if any.
  418. //
  419. if ( Share->FileSecurityDescriptor != NULL ) {
  420. FREE_HEAP( Share->FileSecurityDescriptor );
  421. }
  422. //
  423. // Remove storage for the filesystem name
  424. //
  425. if ( Share->Type.FileSystem.Name.Buffer != NULL ) {
  426. FREE_HEAP( Share->Type.FileSystem.Name.Buffer );
  427. }
  428. FREE_HEAP( Share );
  429. IF_DEBUG(HEAP) {
  430. SrvPrint1( "SrvFreeShare: Freed share block at %lx\n", Share );
  431. }
  432. INCREMENT_DEBUG_STAT( SrvDbgStatistics.ShareInfo.Frees );
  433. return;
  434. } // SrvFreeShare
  435. VOID
  436. SrvReferenceShare (
  437. PSHARE Share
  438. )
  439. /*++
  440. Routine Description:
  441. This function increments the reference count on a share block.
  442. Arguments:
  443. Share - Address of share
  444. Return Value:
  445. None.
  446. --*/
  447. {
  448. PAGED_CODE( );
  449. //
  450. // Enter a critical section and increment the reference count on the
  451. // share.
  452. //
  453. ACQUIRE_LOCK( &SrvShareLock );
  454. ASSERT( (LONG)Share->BlockHeader.ReferenceCount > 0 );
  455. ASSERT( GET_BLOCK_TYPE(Share) == BlockTypeShare );
  456. // ASSERT( GET_BLOCK_STATE(Share) == BlockStateActive );
  457. UPDATE_REFERENCE_HISTORY( Share, FALSE );
  458. Share->BlockHeader.ReferenceCount++;
  459. IF_DEBUG(REFCNT) {
  460. SrvPrint2( "Referencing share %lx; new refcnt %lx\n",
  461. Share, Share->BlockHeader.ReferenceCount );
  462. }
  463. RELEASE_LOCK( &SrvShareLock );
  464. return;
  465. } // SrvReferenceShare
  466. NTSTATUS
  467. SrvReferenceShareForTreeConnect (
  468. PSHARE Share
  469. )
  470. /*++
  471. Routine Description:
  472. This function increments the reference count on a share block for
  473. the referenced pointer in a tree connect block. If this is the
  474. first tree connect to reference the share, the share root directory
  475. is opened.
  476. Arguments:
  477. Share - Address of share
  478. Return Value:
  479. None.
  480. --*/
  481. {
  482. NTSTATUS status;
  483. OBJECT_ATTRIBUTES objectAttributes;
  484. IO_STATUS_BLOCK iosb;
  485. PFILE_FS_ATTRIBUTE_INFORMATION attributeInfo;
  486. CHAR buffer[ FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) + 32 ];
  487. PVOID allocatedBuffer = NULL;
  488. PFILE_OBJECT fileObject;
  489. PDEVICE_OBJECT deviceObject;
  490. PAGED_CODE( );
  491. ACQUIRE_LOCK( &SrvShareLock );
  492. //
  493. // Update the count of tree connects on the share.
  494. //
  495. Share->CurrentUses++;
  496. //
  497. // Check if this is the first tree connect to the share.
  498. //
  499. if ( Share->CurrentUses > 1 ) {
  500. //
  501. // There are already open tree connects on the share. Just
  502. // reference the share and return.
  503. //
  504. SrvReferenceShare( Share );
  505. goto done;
  506. }
  507. //
  508. // If this is not a disk share, then we do not need to open the
  509. // share root directory, so reference the share and return.
  510. //
  511. if ( Share->ShareType != ShareTypeDisk || Share->Removable ) {
  512. SrvReferenceShare( Share );
  513. goto done;
  514. }
  515. //
  516. // This is the first tree connect, so we need to open the share root
  517. // directory. Open the root directory of the share. Future opens
  518. // of files within the share will be relative to the root of the
  519. // share.
  520. //
  521. SrvInitializeObjectAttributes_U(
  522. &objectAttributes,
  523. &Share->NtPathName,
  524. OBJ_CASE_INSENSITIVE,
  525. NULL,
  526. NULL
  527. );
  528. status = NtOpenFile(
  529. &Share->RootDirectoryHandle,
  530. FILE_TRAVERSE,
  531. &objectAttributes,
  532. &iosb,
  533. FILE_SHARE_READ | FILE_SHARE_WRITE,
  534. FILE_DIRECTORY_FILE
  535. );
  536. if ( NT_SUCCESS(status) ) {
  537. SRVDBG_CLAIM_HANDLE( Share->RootDirectoryHandle, "RTD", 2, Share );
  538. //
  539. // Check the irp stack size needed to access this share.
  540. // If it is bigger than what we have allocated, fail
  541. // this share.
  542. //
  543. status = SrvVerifyDeviceStackSize(
  544. Share->RootDirectoryHandle,
  545. FALSE,
  546. &fileObject,
  547. &deviceObject,
  548. NULL
  549. );
  550. if ( !NT_SUCCESS( status )) {
  551. INTERNAL_ERROR(
  552. ERROR_LEVEL_EXPECTED,
  553. "SrvReferenceShareForTreeConnect: Verify Device Stack Size failed: %X\n",
  554. status,
  555. NULL
  556. );
  557. SRVDBG_RELEASE_HANDLE( Share->RootDirectoryHandle, "RTD", 6, Share );
  558. SrvNtClose( Share->RootDirectoryHandle, FALSE );
  559. } else if ( Share->QueryNamePrefixLength == -1 ) {
  560. //
  561. // Query the name associated with the share root directory.
  562. // The prefix is removed whenever the name of a file in the
  563. // share is queried. (The logical root must be preserved
  564. // for remote clients.)
  565. //
  566. GetShareQueryNamePrefix( Share );
  567. }
  568. }
  569. //
  570. // If the open was successful, reference the share.
  571. //
  572. if ( NT_SUCCESS(status) ) {
  573. SrvReferenceShare( Share );
  574. } else {
  575. Share->RootDirectoryHandle = NULL;
  576. Share->CurrentUses--;
  577. }
  578. //
  579. // Now extract the name of the file system, so that it can be returned
  580. // in the TreeConnectAndX response.
  581. //
  582. // Since, from the user's perspective, the share has been successfully
  583. // created, if the attempt fails do not report the failure.
  584. //
  585. if ( !NT_SUCCESS( status ) || Share->Type.FileSystem.Name.Buffer != NULL ) {
  586. RELEASE_LOCK( &SrvShareLock );
  587. return status;
  588. }
  589. attributeInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)buffer;
  590. status = NtQueryVolumeInformationFile(
  591. Share->RootDirectoryHandle,
  592. &iosb,
  593. attributeInfo,
  594. sizeof( buffer ),
  595. FileFsAttributeInformation
  596. );
  597. if ( status == STATUS_BUFFER_OVERFLOW ) {
  598. //
  599. // The file system information was too large to fit in our small
  600. // stack buffer. Allocate an ample buffer and try again.
  601. //
  602. allocatedBuffer = ALLOCATE_HEAP(
  603. FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION,FileSystemName) +
  604. attributeInfo->FileSystemNameLength,
  605. BlockTypeDataBuffer
  606. );
  607. if ( allocatedBuffer == NULL ) {
  608. //
  609. // Couldn't allocate the buffer. Give up.
  610. //
  611. goto done;
  612. }
  613. status = NtQueryVolumeInformationFile(
  614. Share->RootDirectoryHandle,
  615. &iosb,
  616. allocatedBuffer,
  617. FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) +
  618. attributeInfo->FileSystemNameLength,
  619. FileFsAttributeInformation
  620. );
  621. if ( !NT_SUCCESS( status ) ) {
  622. goto done;
  623. }
  624. attributeInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)allocatedBuffer;
  625. } else if ( !NT_SUCCESS( status ) ) {
  626. //
  627. // Some other, unexpected error occured. Give up.
  628. //
  629. goto done;
  630. }
  631. //
  632. // Fill in the file system name
  633. //
  634. SrvFillInFileSystemName(
  635. Share,
  636. attributeInfo->FileSystemName,
  637. attributeInfo->FileSystemNameLength
  638. );
  639. done:
  640. if ( allocatedBuffer != NULL ) {
  641. FREE_HEAP( allocatedBuffer );
  642. }
  643. RELEASE_LOCK( &SrvShareLock );
  644. return STATUS_SUCCESS;
  645. } // SrvReferenceShareForTreeConnect
  646. VOID
  647. SrvFillInFileSystemName (
  648. IN PSHARE Share,
  649. IN PWSTR FileSystemName,
  650. IN ULONG FileSystemNameLength
  651. )
  652. /*++
  653. Routine Description:
  654. This function fills in the stores the given file system name into the
  655. share block.
  656. Arguments:
  657. Share - Address of share
  658. FileSystemName - A string containing the name of the file system
  659. FileSystemNameLength - Length of the above string
  660. Return Value:
  661. None.
  662. --*/
  663. {
  664. PAGED_CODE( );
  665. //
  666. // Allocate enough storage for the ANSI and Unicode representations.
  667. //
  668. Share->Type.FileSystem.Name.Length = (USHORT)FileSystemNameLength;
  669. Share->Type.FileSystem.Name.MaximumLength =
  670. (USHORT)(FileSystemNameLength + sizeof( UNICODE_NULL ));
  671. Share->Type.FileSystem.Name.Buffer = FileSystemName;
  672. Share->Type.FileSystem.OemName.MaximumLength =
  673. (USHORT)RtlUnicodeStringToOemSize( &Share->Type.FileSystem.Name );
  674. Share->Type.FileSystem.Name.Buffer =
  675. ALLOCATE_HEAP(
  676. Share->Type.FileSystem.Name.MaximumLength +
  677. Share->Type.FileSystem.OemName.MaximumLength,
  678. BlockTypeDataBuffer
  679. );
  680. if ( Share->Type.FileSystem.Name.Buffer == NULL) {
  681. return;
  682. }
  683. RtlCopyMemory(
  684. Share->Type.FileSystem.Name.Buffer,
  685. FileSystemName,
  686. FileSystemNameLength
  687. );
  688. //
  689. // Generate the OEM version of the string to return to non-unicode
  690. // clients.
  691. //
  692. Share->Type.FileSystem.OemName.Buffer =
  693. (PCHAR)Share->Type.FileSystem.Name.Buffer +
  694. Share->Type.FileSystem.Name.MaximumLength;
  695. RtlUnicodeStringToOemString(
  696. &Share->Type.FileSystem.OemName,
  697. &Share->Type.FileSystem.Name,
  698. FALSE
  699. );
  700. //
  701. // Append a NUL character to the strings.
  702. //
  703. {
  704. PCHAR endOfBuffer;
  705. endOfBuffer = (PCHAR)Share->Type.FileSystem.Name.Buffer +
  706. Share->Type.FileSystem.Name.Length;
  707. *(PWCH)endOfBuffer = UNICODE_NULL;
  708. Share->Type.FileSystem.Name.Length += sizeof( UNICODE_NULL );
  709. }
  710. Share->Type.FileSystem.OemName.Length++;
  711. return;
  712. } // SrvFillInFileSystemName
  713. NTSTATUS
  714. SrvGetShareRootHandle (
  715. IN PSHARE Share
  716. )
  717. /*++
  718. Routine Description:
  719. This routine returns the root handle for a given share. If the
  720. root has been opened, return the existing handle. If not, open
  721. the share root directory and return the handle obtained.
  722. Arguments:
  723. Share - The share for which the root directory handle is to be returned.
  724. Return Value:
  725. Status of request.
  726. --*/
  727. {
  728. OBJECT_ATTRIBUTES objectAttributes;
  729. IO_STATUS_BLOCK iosb;
  730. NTSTATUS status = STATUS_SUCCESS;
  731. PFILE_OBJECT fileObject;
  732. PDEVICE_OBJECT deviceObject;
  733. PAGED_CODE( );
  734. if ( Share->ShareType != ShareTypeDisk ) {
  735. return STATUS_INVALID_DEVICE_REQUEST;
  736. }
  737. if ( Share->Removable ) {
  738. ACQUIRE_LOCK( &SrvShareLock );
  739. ++Share->CurrentRootHandleReferences;
  740. //
  741. // This is the first open
  742. //
  743. if ( Share->CurrentRootHandleReferences == 1 ) {
  744. ASSERT( Share->RootDirectoryHandle == NULL );
  745. //
  746. // Reference this share to account for the fact that the
  747. // current root handle is being used.
  748. //
  749. SrvReferenceShare( Share );
  750. SrvInitializeObjectAttributes_U(
  751. &objectAttributes,
  752. &Share->NtPathName,
  753. OBJ_CASE_INSENSITIVE,
  754. NULL,
  755. NULL
  756. );
  757. status = NtOpenFile(
  758. &Share->RootDirectoryHandle,
  759. FILE_TRAVERSE,
  760. &objectAttributes,
  761. &iosb,
  762. FILE_SHARE_READ | FILE_SHARE_WRITE,
  763. FILE_DIRECTORY_FILE
  764. );
  765. if ( NT_SUCCESS(status) ) {
  766. SRVDBG_CLAIM_HANDLE( Share->RootDirectoryHandle, "RTD", 30, Share );
  767. //
  768. // Check the irp stack size needed to access this share.
  769. // If it is bigger than what we have allocated, fail
  770. // this share.
  771. //
  772. status = SrvVerifyDeviceStackSize(
  773. Share->RootDirectoryHandle,
  774. FALSE,
  775. &fileObject,
  776. &deviceObject,
  777. NULL
  778. );
  779. if ( !NT_SUCCESS( status )) {
  780. INTERNAL_ERROR(
  781. ERROR_LEVEL_EXPECTED,
  782. "SrvGetShareRootHandle: Verify Device Stack Size failed: %X\n",
  783. status,
  784. NULL
  785. );
  786. SRVDBG_RELEASE_HANDLE( Share->RootDirectoryHandle, "RTD", 49, Share );
  787. SrvNtClose( Share->RootDirectoryHandle, FALSE );
  788. } else if ( Share->QueryNamePrefixLength == -1 ) {
  789. //
  790. // Query the name associated with the share root directory.
  791. // The prefix is removed whenever the name of a file in the
  792. // share is queried. (The logical root must be preserved
  793. // for remote clients.)
  794. //
  795. GetShareQueryNamePrefix( Share );
  796. }
  797. }
  798. if ( !NT_SUCCESS(status) ) {
  799. IF_DEBUG(ERRORS) {
  800. KdPrint(( "SrvGetShareRootHandle: NtOpenFile failed %x.\n",
  801. status ));
  802. }
  803. Share->CurrentRootHandleReferences--;
  804. Share->RootDirectoryHandle = NULL;
  805. SrvDereferenceShare( Share );
  806. }
  807. }
  808. RELEASE_LOCK( &SrvShareLock );
  809. }
  810. return status;
  811. } // SrvGetShareRootHandle
  812. VOID
  813. GetShareQueryNamePrefix (
  814. IN PSHARE Share
  815. )
  816. /*++
  817. Routine Description:
  818. This routine queries the name associated with the share root
  819. directory. The prefix is removed whenever the name of a file in the
  820. share is queried. (The logical root must be preserved for remote
  821. clients.) For example, if the root of the share X is c:\shares\x,
  822. then for a query of \\server\x\y, the file system will return
  823. \shares\x\y, and we need to remove \shares\x and return just \y.
  824. It is not sufficient to just remove the local path (e.g.,
  825. \shares\x), because the file system may have a different idea of the
  826. name of the root directory. For example, the Netware client
  827. redirector prefixes the name with volume information from the
  828. Netware server. So we have to query the filesystem's idea of the
  829. name of the root to know what to strip off.
  830. Arguments:
  831. Share - The share for which the query name prefix length is desired.
  832. Return Value:
  833. None.
  834. --*/
  835. {
  836. NTSTATUS status;
  837. IO_STATUS_BLOCK iosb;
  838. ULONG localBuffer[ (FIELD_OFFSET(FILE_NAME_INFORMATION,FileName) + 20) / sizeof( ULONG ) ];
  839. PFILE_NAME_INFORMATION nameInfo;
  840. ULONG nameInfoLength;
  841. PAGED_CODE( );
  842. //
  843. // Do a short query to get the length of the name. This query will
  844. // fail with STATUS_BUFFER_OVERFLOW unless the path to the share
  845. // root is short (10 characters or less).
  846. //
  847. nameInfo = (PFILE_NAME_INFORMATION)localBuffer;
  848. nameInfoLength = sizeof(localBuffer);
  849. status = NtQueryInformationFile(
  850. Share->RootDirectoryHandle,
  851. &iosb,
  852. nameInfo,
  853. nameInfoLength,
  854. FileNameInformation
  855. );
  856. if ( status == STATUS_BUFFER_OVERFLOW ) {
  857. //
  858. // We got an expected buffer overflow error. Allocate a buffer
  859. // to hold the entire file name and redo the query.
  860. //
  861. nameInfoLength = sizeof(FILE_NAME_INFORMATION) + nameInfo->FileNameLength;
  862. nameInfo = ALLOCATE_HEAP( nameInfoLength, BlockTypeDataBuffer );
  863. if ( nameInfo == NULL ) {
  864. status = STATUS_INSUFF_SERVER_RESOURCES;
  865. } else {
  866. status = NtQueryInformationFile(
  867. Share->RootDirectoryHandle,
  868. &iosb,
  869. nameInfo,
  870. nameInfoLength,
  871. FileNameInformation
  872. );
  873. }
  874. }
  875. if ( NT_SUCCESS(status) ) {
  876. //
  877. // We have the name. The length of this name is the length we
  878. // want to strip from each query, unless the last character of
  879. // the name is \, in which case we need to strip up to, but not
  880. // including, the \.
  881. //
  882. Share->QueryNamePrefixLength = nameInfo->FileNameLength;
  883. if ( nameInfo->FileName[nameInfo->FileNameLength/sizeof(WCHAR) - 1] == L'\\') {
  884. Share->QueryNamePrefixLength -= sizeof(WCHAR);
  885. }
  886. } else {
  887. //
  888. // An unexpected error occurred. Just set the prefix length to 0.
  889. //
  890. Share->QueryNamePrefixLength = 0;
  891. }
  892. //
  893. // If we allocated a temporary buffer, free it now.
  894. //
  895. if ( (nameInfo != NULL) && (nameInfo != (PFILE_NAME_INFORMATION)localBuffer) ) {
  896. FREE_HEAP( nameInfo );
  897. }
  898. return;
  899. } // GetShareQueryNamePrefix