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.

3337 lines
104 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbsrch.c
  5. Abstract:
  6. This module contains routines for processing the find 2 SMBs:
  7. Find 2 (First/Next/Rewind)
  8. Find 2 Close
  9. Author:
  10. David Treadwell (davidtr) 13-Feb-1990
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "smbfind.tmh"
  15. #pragma hdrstop
  16. #define BugCheckFileId SRV_FILE_SMBFIND
  17. VOID SRVFASTCALL
  18. BlockingFindFirst2 (
  19. IN PWORK_CONTEXT WorkContext
  20. );
  21. SMB_TRANS_STATUS
  22. DoFindFirst2 (
  23. IN PWORK_CONTEXT WorkContext
  24. );
  25. VOID SRVFASTCALL
  26. BlockingFindNext2 (
  27. IN PWORK_CONTEXT WorkContext
  28. );
  29. SMB_TRANS_STATUS
  30. DoFindNext2 (
  31. IN PWORK_CONTEXT WorkContext
  32. );
  33. NTSTATUS
  34. SrvFind2Loop (
  35. IN PWORK_CONTEXT WorkContext,
  36. IN BOOLEAN IsFirstCall,
  37. IN PULONG ResumeFileIndex OPTIONAL,
  38. IN USHORT Flags,
  39. IN USHORT InformationLevel,
  40. IN PTRANSACTION Transaction,
  41. IN PSRV_DIRECTORY_INFORMATION DirectoryInformation,
  42. IN CLONG BufferSize,
  43. IN USHORT SearchAttributes,
  44. IN PUNICODE_STRING FileName OPTIONAL,
  45. IN USHORT MaxCount,
  46. IN PRESP_FIND_NEXT2 Response,
  47. OUT PSEARCH Search
  48. );
  49. VOID
  50. ConvertFileInfo (
  51. IN PFILE_DIRECTORY_INFORMATION File,
  52. IN PWCH FileName,
  53. IN BOOLEAN Directory,
  54. IN BOOLEAN ClientIsUnicode,
  55. OUT PSMB_FIND_BUFFER FindBuffer
  56. );
  57. #ifdef ALLOC_PRAGMA
  58. #pragma alloc_text( PAGE, SrvSmbFindFirst2 )
  59. #pragma alloc_text( PAGE, BlockingFindFirst2 )
  60. #pragma alloc_text( PAGE, DoFindFirst2 )
  61. #pragma alloc_text( PAGE, SrvSmbFindNext2 )
  62. #pragma alloc_text( PAGE, BlockingFindNext2 )
  63. #pragma alloc_text( PAGE, DoFindNext2 )
  64. #pragma alloc_text( PAGE, SrvFind2Loop )
  65. #pragma alloc_text( PAGE, ConvertFileInfo )
  66. #pragma alloc_text( PAGE, SrvSmbFindClose2 )
  67. #endif
  68. SMB_TRANS_STATUS
  69. SrvSmbFindFirst2 (
  70. IN OUT PWORK_CONTEXT WorkContext
  71. )
  72. /*++
  73. Routine Description:
  74. Processes the Find First2 request. This request arrives in a
  75. Transaction2 SMB.
  76. Arguments:
  77. WorkContext - Supplies the address of a Work Context Block
  78. describing the current request. See smbtypes.h for a more
  79. complete description of the valid fields.
  80. Return Value:
  81. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  82. smbtypes.h for a more complete description.
  83. --*/
  84. {
  85. PREQ_FIND_FIRST2 request;
  86. PTRANSACTION transaction;
  87. SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
  88. PAGED_CODE( );
  89. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  90. WorkContext->PreviousSMB = EVENT_TYPE_SMB_FIND_FIRST2;
  91. SrvWmiStartContext(WorkContext);
  92. //
  93. // If the infomation level is QUERY_EAS_FROM_LIST, and we
  94. // are not in a blocking thread, requeue the request to a blocking
  95. // thread.
  96. //
  97. // We can't process the SMB in a non blocking thread because this
  98. // info level requires opening the file, which may be oplocked,
  99. // so the open operation may block.
  100. //
  101. transaction = WorkContext->Parameters.Transaction;
  102. request = (PREQ_FIND_FIRST2)transaction->InParameters;
  103. if ( transaction->ParameterCount >= sizeof(REQ_FIND_FIRST2) &&
  104. SmbGetUshort( &request->InformationLevel ) == SMB_INFO_QUERY_EAS_FROM_LIST ) {
  105. WorkContext->FspRestartRoutine = BlockingFindFirst2;
  106. SrvQueueWorkToBlockingThread(WorkContext);
  107. SmbStatus = SmbTransStatusInProgress;
  108. }
  109. else {
  110. SmbStatus = DoFindFirst2(WorkContext);
  111. }
  112. SrvWmiEndContext(WorkContext);
  113. return SmbStatus;
  114. } // SrvSmbFindFirst2
  115. VOID SRVFASTCALL
  116. BlockingFindFirst2 (
  117. IN OUT PWORK_CONTEXT WorkContext
  118. )
  119. /*++
  120. Routine Description:
  121. Processes the Find First2 request. This request arrives in a
  122. Transaction2 SMB.
  123. Arguments:
  124. WorkContext - Supplies the address of a Work Context Block
  125. describing the current request. See smbtypes.h for a more
  126. complete description of the valid fields.
  127. Return Value:
  128. None.
  129. --*/
  130. {
  131. SMB_TRANS_STATUS smbStatus = SmbTransStatusInProgress;
  132. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  133. WorkContext->PreviousSMB = EVENT_TYPE_SMB_FIND_FIRST2;
  134. SrvWmiStartContext(WorkContext);
  135. smbStatus = DoFindFirst2( WorkContext );
  136. if ( smbStatus != SmbTransStatusInProgress ) {
  137. SrvCompleteExecuteTransaction( WorkContext, smbStatus );
  138. }
  139. SrvWmiEndContext(WorkContext);
  140. return;
  141. } // BlockingFindFirst2
  142. SMB_TRANS_STATUS
  143. DoFindFirst2 (
  144. IN OUT PWORK_CONTEXT WorkContext
  145. )
  146. /*++
  147. Routine Description:
  148. Processes the Find First2 request. This request arrives in a
  149. Transaction2 SMB.
  150. Arguments:
  151. WorkContext - Supplies the address of a Work Context Block
  152. describing the current request. See smbtypes.h for a more
  153. complete description of the valid fields.
  154. Return Value:
  155. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  156. smbtypes.h for a more complete description.
  157. --*/
  158. {
  159. PREQ_FIND_FIRST2 request;
  160. PRESP_FIND_FIRST2 response;
  161. PTRANSACTION transaction;
  162. PCONNECTION connection;
  163. NTSTATUS status,TableStatus;
  164. UNICODE_STRING fileName;
  165. PTABLE_ENTRY entry = NULL;
  166. PTABLE_HEADER searchTable;
  167. SHORT sidIndex = 0;
  168. USHORT sequence;
  169. USHORT maxCount;
  170. USHORT flags;
  171. USHORT informationLevel;
  172. BOOLEAN isUnicode;
  173. PSRV_DIRECTORY_INFORMATION directoryInformation;
  174. CLONG nonPagedBufferSize;
  175. PSEARCH search = NULL;
  176. PAGED_CODE( );
  177. transaction = WorkContext->Parameters.Transaction;
  178. IF_SMB_DEBUG(SEARCH1) {
  179. SrvPrint1( "Find First2 entered; transaction 0x%p\n", transaction );
  180. }
  181. request = (PREQ_FIND_FIRST2)transaction->InParameters;
  182. response = (PRESP_FIND_FIRST2)transaction->OutParameters;
  183. //
  184. // Verify that enough parameter bytes were sent and that we're allowed
  185. // to return enough parameter bytes.
  186. //
  187. if ( (transaction->ParameterCount < sizeof(REQ_FIND_FIRST2)) ||
  188. (transaction->MaxParameterCount < sizeof(RESP_FIND_FIRST2)) ) {
  189. //
  190. // Not enough parameter bytes were sent.
  191. //
  192. IF_SMB_DEBUG(SEARCH2) {
  193. SrvPrint2( "DoFindFirst2: bad parameter byte counts: "
  194. "%ld %ld\n",
  195. transaction->ParameterCount,
  196. transaction->MaxParameterCount );
  197. }
  198. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  199. return SmbTransStatusErrorWithoutData;
  200. }
  201. //
  202. // Make sure this really is a disk type share
  203. //
  204. if( transaction->TreeConnect->Share->ShareType != ShareTypeDisk ) {
  205. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  206. return SmbTransStatusErrorWithoutData;
  207. }
  208. //
  209. // Make sure the client is allowed to do this, if we have an Admin share
  210. //
  211. status = SrvIsAllowedOnAdminShare( WorkContext, transaction->TreeConnect->Share );
  212. if( !NT_SUCCESS( status ) ) {
  213. SrvSetSmbError( WorkContext, status );
  214. return SmbTransStatusErrorWithoutData;
  215. }
  216. //
  217. // Initialize the string containing the search name specification.
  218. //
  219. isUnicode = SMB_IS_UNICODE( WorkContext );
  220. status = SrvCanonicalizePathName(
  221. WorkContext,
  222. transaction->TreeConnect->Share,
  223. NULL,
  224. request->Buffer,
  225. END_OF_TRANSACTION_PARAMETERS( transaction ),
  226. FALSE,
  227. isUnicode,
  228. &fileName
  229. );
  230. if( !NT_SUCCESS( status ) ) {
  231. SrvSetSmbError( WorkContext, status );
  232. return SmbTransStatusErrorWithoutData;
  233. }
  234. //
  235. // Get parameters from the request SMB.
  236. //
  237. maxCount = SmbGetUshort( &request->SearchCount );
  238. flags = SmbGetUshort( &request->Flags );
  239. //
  240. // Make sure that the informationLevel is supported.
  241. //
  242. informationLevel = SmbGetUshort( &request->InformationLevel );
  243. switch ( informationLevel ) {
  244. case SMB_INFO_STANDARD:
  245. case SMB_INFO_QUERY_EA_SIZE:
  246. case SMB_INFO_QUERY_EAS_FROM_LIST:
  247. case SMB_FIND_FILE_DIRECTORY_INFO:
  248. case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
  249. case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
  250. case SMB_FIND_FILE_NAMES_INFO:
  251. case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
  252. case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
  253. break;
  254. default:
  255. IF_DEBUG(SMB_ERRORS) {
  256. SrvPrint1( "DoFindFirst2: Bad info level: %ld\n",
  257. informationLevel );
  258. }
  259. if ( !isUnicode ) {
  260. RtlFreeUnicodeString( &fileName );
  261. }
  262. SrvSetSmbError( WorkContext, STATUS_OS2_INVALID_LEVEL );
  263. return SmbTransStatusErrorWithoutData;
  264. }
  265. //
  266. // Allocate a search block on the assumption that a search table
  267. // entry will be available when needed.
  268. //
  269. SrvAllocateSearch( &search, &fileName, FALSE );
  270. if ( search == NULL ) {
  271. IF_DEBUG(ERRORS) {
  272. SrvPrint0( "DoFindFirst2: unable to allocate search block.\n" );
  273. }
  274. if ( !isUnicode ) {
  275. RtlFreeUnicodeString( &fileName );
  276. }
  277. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  278. return SmbTransStatusErrorWithoutData;
  279. }
  280. search->SearchStorageType = SmbGetUlong(&request->SearchStorageType);
  281. //
  282. // Allocate an SID for the search. The SID is used to locate the
  283. // search block on FindNexts. If there are no free entries in the
  284. // table, attempt to grow the table. If we are unable to grow the table,
  285. // attempt to timeout a search block using the shorter timeout period.
  286. // If this fails, reject the request.
  287. //
  288. connection = WorkContext->Connection;
  289. searchTable = &connection->PagedConnection->SearchTable;
  290. ACQUIRE_LOCK( &connection->Lock );
  291. //
  292. // Before inserting this search block, make sure the session and tree
  293. // connect is still active. If this gets inserted after the session
  294. // is closed, the search might not be cleaned up properly.
  295. //
  296. if (GET_BLOCK_STATE(WorkContext->Session) != BlockStateActive) {
  297. IF_DEBUG(ERRORS) {
  298. SrvPrint0( "DoFindFirst2: Session Closing.\n" );
  299. }
  300. RELEASE_LOCK( &connection->Lock );
  301. FREE_HEAP( search );
  302. if ( !isUnicode ) {
  303. RtlFreeUnicodeString( &fileName );
  304. }
  305. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_UID );
  306. return SmbTransStatusErrorWithoutData;
  307. } else if (GET_BLOCK_STATE(WorkContext->TreeConnect) != BlockStateActive) {
  308. IF_DEBUG(ERRORS) {
  309. SrvPrint0( "DoFindFirst2: Tree Connect Closing.\n" );
  310. }
  311. RELEASE_LOCK( &connection->Lock );
  312. FREE_HEAP( search );
  313. if ( !isUnicode ) {
  314. RtlFreeUnicodeString( &fileName );
  315. }
  316. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_TID );
  317. return SmbTransStatusErrorWithoutData;
  318. }
  319. //
  320. // Set up referenced session and tree connect pointers and increment
  321. // the count of open files on the session. This prevents an idle
  322. // session with an open search from being autodisconnected.
  323. //
  324. search->Session = WorkContext->Session;
  325. SrvReferenceSession( WorkContext->Session );
  326. search->TreeConnect = WorkContext->TreeConnect;
  327. SrvReferenceTreeConnect( WorkContext->TreeConnect );
  328. WorkContext->Session->CurrentSearchOpenCount++;
  329. if ( searchTable->FirstFreeEntry == -1
  330. &&
  331. SrvGrowTable(
  332. searchTable,
  333. SrvInitialSearchTableSize,
  334. SrvMaxSearchTableSize,
  335. &TableStatus ) == FALSE
  336. &&
  337. SrvTimeoutSearches(
  338. NULL,
  339. connection,
  340. TRUE ) == 0
  341. ) {
  342. IF_DEBUG(ERRORS) {
  343. SrvPrint0( "DoFindFirst2: Connection SearchTable full.\n" );
  344. }
  345. //
  346. // Decrement the counts of open searches.
  347. //
  348. WorkContext->Session->CurrentSearchOpenCount--;
  349. RELEASE_LOCK( &connection->Lock );
  350. SrvDereferenceTreeConnect( search->TreeConnect );
  351. SrvDereferenceSession( search->Session );
  352. FREE_HEAP( search );
  353. if ( !isUnicode ) {
  354. RtlFreeUnicodeString( &fileName );
  355. }
  356. if( TableStatus == STATUS_INSUFF_SERVER_RESOURCES )
  357. {
  358. SrvLogTableFullError( SRV_TABLE_SEARCH);
  359. SrvSetSmbError( WorkContext, STATUS_OS2_NO_MORE_SIDS );
  360. }
  361. else {
  362. SrvSetSmbError( WorkContext, STATUS_INSUFFICIENT_RESOURCES );
  363. }
  364. return SmbTransStatusErrorWithoutData;
  365. }
  366. sidIndex = searchTable->FirstFreeEntry;
  367. //
  368. // A free SID was found. Remove it from the free list and set
  369. // its owner and sequence number.
  370. //
  371. entry = &searchTable->Table[sidIndex];
  372. searchTable->FirstFreeEntry = entry->NextFreeEntry;
  373. DEBUG entry->NextFreeEntry = -2;
  374. if ( searchTable->LastFreeEntry == sidIndex ) {
  375. searchTable->LastFreeEntry = -1;
  376. }
  377. INCREMENT_SID_SEQUENCE( entry->SequenceNumber );
  378. //
  379. // SID = sequence | sidIndex == 0 is illegal. If this is
  380. // the current value, increment the sequence.
  381. //
  382. if ( entry->SequenceNumber == 0 && sidIndex == 0 ) {
  383. INCREMENT_SID_SEQUENCE( entry->SequenceNumber );
  384. }
  385. sequence = entry->SequenceNumber;
  386. entry->Owner = search;
  387. RELEASE_LOCK( &connection->Lock );
  388. //
  389. // Fill in other fields of the search block.
  390. //
  391. search->SearchAttributes = SmbGetUshort( &request->SearchAttributes );
  392. search->TableIndex = sidIndex;
  393. //
  394. // Store the Flags2 field of the smb in the search block. This is
  395. // used as a workaround for an OS/2 client side bug where the
  396. // findfirst and findnext flags2 bits are inconsistent.
  397. //
  398. search->Flags2 = SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 );
  399. if ( search->Flags2 & SMB_FLAGS2_KNOWS_LONG_NAMES ) {
  400. search->Flags2 |= SMB_FLAGS2_KNOWS_EAS;
  401. }
  402. //
  403. // A buffer of nonpaged pool is required by SrvQueryDirectoryFile.
  404. // We need to use the SMB buffer for found file names and information,
  405. // so allocate a buffer from nonpaged pool.
  406. //
  407. // If we don't need to return many files, we don't need to allocate
  408. // a large buffer. The buffer size is the configurable size or
  409. // enough to hold two more then the number of files we need to
  410. // return. We get space to hold two extra files in case some
  411. // files do not meet the search criteria (eg directories).
  412. //
  413. if ( maxCount > MAX_FILES_FOR_MED_FIND2 ) {
  414. nonPagedBufferSize = MAX_SEARCH_BUFFER_SIZE;
  415. } else if ( maxCount > MAX_FILES_FOR_MIN_FIND2 ) {
  416. nonPagedBufferSize = MED_SEARCH_BUFFER_SIZE;
  417. } else {
  418. nonPagedBufferSize = MIN_SEARCH_BUFFER_SIZE;
  419. }
  420. directoryInformation = ALLOCATE_NONPAGED_POOL(
  421. nonPagedBufferSize,
  422. BlockTypeDataBuffer
  423. );
  424. if ( directoryInformation == NULL ) {
  425. INTERNAL_ERROR(
  426. ERROR_LEVEL_EXPECTED,
  427. "DoFindFirst2: could not allocate nonpaged pool.",
  428. NULL,
  429. NULL
  430. );
  431. SrvCloseSearch( search );
  432. SrvDereferenceSearch( search );
  433. if ( !isUnicode ) {
  434. RtlFreeUnicodeString( &fileName );
  435. }
  436. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  437. return SmbTransStatusErrorWithoutData;
  438. }
  439. directoryInformation->DirectoryHandle = 0;
  440. IF_SMB_DEBUG(SEARCH2) {
  441. SrvPrint2( "Allocated buffer space of %ld bytes at 0x%p\n",
  442. nonPagedBufferSize, directoryInformation );
  443. }
  444. //
  445. // Call SrvFind2Loop to fill the data section of the transaction with
  446. // file entries. It writes into the response parameters section
  447. // of the SMB information relating to the results of the search.
  448. // The information is the same as the response parameters for
  449. // a FindNext2, so that structure is used. The FindFirst2 parameters
  450. // are identical to the FindNext2 parameters except for the Sid
  451. // at the beginning of the FindFirst2 response.
  452. //
  453. status = SrvFind2Loop(
  454. WorkContext,
  455. TRUE,
  456. NULL,
  457. flags,
  458. informationLevel,
  459. transaction,
  460. directoryInformation,
  461. nonPagedBufferSize,
  462. search->SearchAttributes,
  463. &fileName,
  464. maxCount,
  465. (PRESP_FIND_NEXT2)( &response->SearchCount ),
  466. search
  467. );
  468. if ( !isUnicode ) {
  469. RtlFreeUnicodeString( &fileName );
  470. }
  471. //
  472. // Map the error, if necessary
  473. //
  474. if ( !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
  475. if ( status == STATUS_NO_SUCH_FILE ) {
  476. status = STATUS_NO_MORE_FILES;
  477. }
  478. }
  479. if ( !NT_SUCCESS(status) && SmbGetUshort( &response->SearchCount ) == 0 ) {
  480. //
  481. // If an error was encountered on a find first, we close the search
  482. // block.
  483. //
  484. search->DirectoryHandle = NULL;
  485. SrvCloseSearch( search );
  486. SrvDereferenceSearch( search );
  487. SrvCloseQueryDirectory( directoryInformation );
  488. DEALLOCATE_NONPAGED_POOL( directoryInformation );
  489. SrvSetSmbError2( WorkContext, status, TRUE );
  490. transaction->SetupCount = 0;
  491. transaction->ParameterCount = sizeof(RESP_FIND_FIRST2);
  492. SmbPutUshort( &response->Sid, 0 );
  493. return SmbTransStatusErrorWithData;
  494. }
  495. //
  496. // If the client told us to close the search after this request, or
  497. // close at end-of-search, or this no files were found, close the
  498. // search block and call SrvCloseQueryDirectory. Otherwise, store
  499. // information in the search block.
  500. //
  501. if ( ( flags & SMB_FIND_CLOSE_AFTER_REQUEST ) != 0 ||
  502. ( status == STATUS_NO_MORE_FILES &&
  503. ( flags & SMB_FIND_CLOSE_AT_EOS ) != 0 ) ) {
  504. IF_SMB_DEBUG(SEARCH2) {
  505. SrvPrint1( "Closing search at %p\n", search );
  506. }
  507. search->DirectoryHandle = NULL;
  508. SrvCloseSearch( search );
  509. SrvCloseQueryDirectory( directoryInformation );
  510. } else {
  511. search->DirectoryHandle = directoryInformation->DirectoryHandle;
  512. search->Wildcards = directoryInformation->Wildcards;
  513. }
  514. //
  515. // Free the buffer used for the search and dereference our pointer to
  516. // the search block.
  517. //
  518. DEALLOCATE_NONPAGED_POOL( directoryInformation );
  519. search->InUse = FALSE;
  520. SrvDereferenceSearch( search );
  521. //
  522. // Build the output parameter and data structures.
  523. //
  524. transaction->SetupCount = 0;
  525. transaction->ParameterCount = sizeof(RESP_FIND_FIRST2);
  526. SmbPutUshort( &response->Sid, MAKE_SID( sidIndex, sequence ) );
  527. return SmbTransStatusSuccess;
  528. } // DoFindFirst2
  529. SMB_TRANS_STATUS
  530. SrvSmbFindNext2 (
  531. IN OUT PWORK_CONTEXT WorkContext
  532. )
  533. /*++
  534. Routine Description:
  535. Processes the Find Next2 request. This request arrives in a
  536. Transaction2 SMB.
  537. Arguments:
  538. WorkContext - Supplies the address of a Work Context Block
  539. describing the current request. See smbtypes.h for a more
  540. complete description of the valid fields.
  541. Return Value:
  542. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  543. smbtypes.h for a more complete description.
  544. --*/
  545. {
  546. SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
  547. PTRANSACTION transaction;
  548. PAGED_CODE( );
  549. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  550. WorkContext->PreviousSMB = EVENT_TYPE_SMB_FIND_NEXT2;
  551. SrvWmiStartContext(WorkContext);
  552. //
  553. // If the infomation level is QUERY_EAS_FROM_LIST, and we
  554. // are not in a blocking thread, requeue the request to a blocking
  555. // thread.
  556. //
  557. // We can't process the SMB in a non blocking thread because this
  558. // info level requires opening the file, which may be oplocked,
  559. // so the open operation may block.
  560. //
  561. transaction = WorkContext->Parameters.Transaction;
  562. if( transaction->ParameterCount >= sizeof(REQ_FIND_NEXT2) ) {
  563. PREQ_FIND_NEXT2 request = (PREQ_FIND_NEXT2)transaction->InParameters;
  564. USHORT informationLevel = SmbGetUshort( &request->InformationLevel );
  565. if ( informationLevel == SMB_INFO_QUERY_EAS_FROM_LIST ) {
  566. WorkContext->FspRestartRoutine = BlockingFindNext2;
  567. SrvQueueWorkToBlockingThread( WorkContext );
  568. SmbStatus = SmbTransStatusInProgress;
  569. goto Cleanup;
  570. }
  571. }
  572. SmbStatus = DoFindNext2( WorkContext );
  573. Cleanup:
  574. SrvWmiEndContext(WorkContext);
  575. return SmbStatus;
  576. } // SrvSmbFindNext2
  577. VOID SRVFASTCALL
  578. BlockingFindNext2 (
  579. IN OUT PWORK_CONTEXT WorkContext
  580. )
  581. /*++
  582. Routine Description:
  583. Processes the Find Next2 request. This request arrives in a
  584. Transaction2 SMB.
  585. Arguments:
  586. WorkContext - Supplies the address of a Work Context Block
  587. describing the current request. See smbtypes.h for a more
  588. complete description of the valid fields.
  589. Return Value:
  590. None.
  591. --*/
  592. {
  593. SMB_TRANS_STATUS smbStatus = SmbTransStatusInProgress;
  594. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  595. WorkContext->PreviousSMB = EVENT_TYPE_SMB_FIND_NEXT2;
  596. SrvWmiStartContext(WorkContext);
  597. smbStatus = DoFindNext2( WorkContext );
  598. if ( smbStatus != SmbTransStatusInProgress ) {
  599. SrvCompleteExecuteTransaction( WorkContext, smbStatus );
  600. }
  601. SrvWmiEndContext(WorkContext);
  602. return;
  603. } // BlockingFindNext2
  604. SMB_TRANS_STATUS
  605. DoFindNext2 (
  606. IN OUT PWORK_CONTEXT WorkContext
  607. )
  608. /*++
  609. Routine Description:
  610. Processes the Find First2 request. This request arrives in a
  611. Transaction2 SMB.
  612. Arguments:
  613. WorkContext - Supplies the address of a Work Context Block
  614. describing the current request. See smbtypes.h for a more
  615. complete description of the valid fields.
  616. Return Value:
  617. SMB_TRANS_STATUS - Indicates whether an error occurred. See
  618. smbtypes.h for a more complete description.
  619. --*/
  620. {
  621. PREQ_FIND_NEXT2 request;
  622. PRESP_FIND_NEXT2 response;
  623. PTRANSACTION transaction;
  624. NTSTATUS status;
  625. USHORT i;
  626. PCHAR ansiChar;
  627. PWCH unicodeChar;
  628. ULONG maxIndex;
  629. BOOLEAN illegalPath;
  630. BOOLEAN freeFileName;
  631. UNICODE_STRING fileName;
  632. PTABLE_ENTRY entry = NULL;
  633. USHORT maxCount;
  634. USHORT informationLevel;
  635. PSRV_DIRECTORY_INFORMATION directoryInformation;
  636. CLONG nonPagedBufferSize;
  637. ULONG resumeFileIndex;
  638. USHORT flags;
  639. USHORT sid;
  640. PSEARCH search = NULL;
  641. PAGED_CODE( );
  642. transaction = WorkContext->Parameters.Transaction;
  643. IF_SMB_DEBUG(SEARCH1) {
  644. SrvPrint1( "Find Next2 entered; transaction %p\n", transaction );
  645. }
  646. request = (PREQ_FIND_NEXT2)transaction->InParameters;
  647. response = (PRESP_FIND_NEXT2)transaction->OutParameters;
  648. //
  649. // Verify that enough parameter bytes were sent and that we're allowed
  650. // to return enough parameter bytes.
  651. //
  652. if ( (transaction->ParameterCount <
  653. sizeof(REQ_FIND_NEXT2)) ||
  654. (transaction->MaxParameterCount <
  655. sizeof(RESP_FIND_NEXT2)) ) {
  656. //
  657. // Not enough parameter bytes were sent.
  658. //
  659. IF_DEBUG(SMB_ERRORS) {
  660. SrvPrint2( "DoFindNext2: bad parameter byte counts: %ld %ld\n",
  661. transaction->ParameterCount,
  662. transaction->MaxParameterCount );
  663. }
  664. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  665. return SmbTransStatusErrorWithoutData;
  666. }
  667. //
  668. // Get parameters from the request SMB.
  669. //
  670. maxCount = SmbGetUshort( &request->SearchCount );
  671. resumeFileIndex = SmbGetUlong( &request->ResumeKey );
  672. flags = SmbGetUshort( &request->Flags );
  673. //
  674. // Make sure that the informationLevel is supported.
  675. //
  676. informationLevel = SmbGetUshort( &request->InformationLevel );
  677. switch ( informationLevel ) {
  678. case SMB_INFO_STANDARD:
  679. case SMB_INFO_QUERY_EA_SIZE:
  680. case SMB_INFO_QUERY_EAS_FROM_LIST:
  681. case SMB_FIND_FILE_DIRECTORY_INFO:
  682. case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
  683. case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
  684. case SMB_FIND_FILE_NAMES_INFO:
  685. case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
  686. case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
  687. break;
  688. default:
  689. IF_DEBUG(SMB_ERRORS) {
  690. SrvPrint1( "DoFindNext2: Bad info level: %ld\n",
  691. informationLevel );
  692. }
  693. SrvSetSmbError( WorkContext, STATUS_OS2_INVALID_LEVEL );
  694. return SmbTransStatusErrorWithoutData;
  695. }
  696. //
  697. // A buffer of nonpaged pool is required by SrvQueryDirectoryFile.
  698. // We need to use the SMB buffer for found file names and information,
  699. // so allocate a buffer from nonpaged pool.
  700. //
  701. // If we don't need to return many files, we don't need to allocate
  702. // a large buffer. The buffer size is the configurable size or
  703. // enough to hold two more then the number of files we need to
  704. // return. We get space to hold two extra files in case some
  705. // files do not meet the search criteria (eg directories).
  706. //
  707. if ( maxCount > MAX_FILES_FOR_MED_FIND2 ) {
  708. nonPagedBufferSize = MAX_SEARCH_BUFFER_SIZE;
  709. } else if ( maxCount > MAX_FILES_FOR_MIN_FIND2 ) {
  710. nonPagedBufferSize = MED_SEARCH_BUFFER_SIZE;
  711. } else {
  712. nonPagedBufferSize = MIN_SEARCH_BUFFER_SIZE;
  713. }
  714. directoryInformation = ALLOCATE_NONPAGED_POOL(
  715. nonPagedBufferSize,
  716. BlockTypeDataBuffer
  717. );
  718. if ( directoryInformation == NULL ) {
  719. INTERNAL_ERROR(
  720. ERROR_LEVEL_EXPECTED,
  721. "DoFindFirst2: unable to allocate nonpaged pool.",
  722. NULL,
  723. NULL
  724. );
  725. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  726. return SmbTransStatusErrorWithoutData;
  727. }
  728. IF_SMB_DEBUG(SEARCH2) {
  729. SrvPrint2( "Allocated buffer space of %ld bytes at 0x%p\n",
  730. nonPagedBufferSize, directoryInformation );
  731. }
  732. //
  733. // Get the search block corresponding to this SID. SrvVerifySid
  734. // references the search block and fills in fields of
  735. // directoryInformation so it is ready to be used by
  736. // SrvQueryDirectoryFile.
  737. //
  738. sid = SmbGetUshort( &request->Sid );
  739. search = SrvVerifySid(
  740. WorkContext,
  741. SID_INDEX2( sid ),
  742. SID_SEQUENCE2( sid ),
  743. directoryInformation,
  744. nonPagedBufferSize
  745. );
  746. if ( search == NULL ) {
  747. IF_DEBUG(SMB_ERRORS) {
  748. SrvPrint1( "DoFindNext2: Invalid SID: %lx.\n", sid );
  749. }
  750. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  751. DEALLOCATE_NONPAGED_POOL( directoryInformation );
  752. return SmbTransStatusErrorWithoutData;
  753. }
  754. //
  755. // Initialize the string containing the resume name specification.
  756. // If the client requested that we resume from the last file returned,
  757. // use the file name and index stored in the search block.
  758. //
  759. if ( ( flags & SMB_FIND_CONTINUE_FROM_LAST ) == 0 ) {
  760. //
  761. // Test and use the information passed by the client. A file
  762. // name may not be longer than MAXIMUM_FILENAME_LENGTH characters,
  763. // and it should not contain any directory information.
  764. //
  765. illegalPath = FALSE;
  766. freeFileName = FALSE;
  767. if ( SMB_IS_UNICODE( WorkContext ) ) {
  768. fileName.Buffer = ALIGN_SMB_WSTR( (PWCH)request->Buffer );
  769. maxIndex = (ULONG)((END_OF_REQUEST_SMB( WorkContext ) -
  770. (PUCHAR)fileName.Buffer) / sizeof(WCHAR));
  771. for ( i = 0, unicodeChar = fileName.Buffer;
  772. (i < MAXIMUM_FILENAME_LENGTH) && (i < maxIndex);
  773. i++, unicodeChar++ ) {
  774. if ( *unicodeChar == '\0' ) {
  775. break;
  776. }
  777. if ( IS_UNICODE_PATH_SEPARATOR( *unicodeChar ) ) {
  778. IF_DEBUG(SMB_ERRORS) {
  779. SrvPrint1( "DoFindNext2: illegal path name: %ws\n",
  780. fileName.Buffer );
  781. }
  782. illegalPath = TRUE;
  783. break;
  784. }
  785. }
  786. fileName.Length = (USHORT) (i * sizeof(WCHAR));
  787. fileName.MaximumLength = fileName.Length;
  788. } else {
  789. ansiChar = (PCHAR)request->Buffer;
  790. maxIndex = (ULONG)(END_OF_REQUEST_SMB( WorkContext ) - ansiChar);
  791. for ( i = 0;
  792. (i < MAXIMUM_FILENAME_LENGTH) && (i < maxIndex);
  793. i++, ansiChar++ ) {
  794. if ( *ansiChar == '\0' ) {
  795. break;
  796. }
  797. if ( IS_ANSI_PATH_SEPARATOR( *ansiChar ) ) {
  798. IF_DEBUG(SMB_ERRORS) {
  799. SrvPrint1( "DoFindNext2: illegal path name: %s\n",
  800. request->Buffer );
  801. }
  802. illegalPath = TRUE;
  803. break;
  804. }
  805. }
  806. if ( !illegalPath ) {
  807. status = SrvMakeUnicodeString(
  808. FALSE,
  809. &fileName,
  810. request->Buffer,
  811. &i
  812. );
  813. if ( !NT_SUCCESS(status) ) {
  814. IF_DEBUG(SMB_ERRORS) {
  815. SrvPrint0( "DoFindNext2: unable to allocate Unicode string\n" );
  816. }
  817. search->InUse = FALSE;
  818. SrvDereferenceSearch( search );
  819. DEALLOCATE_NONPAGED_POOL( directoryInformation );
  820. SrvSetSmbError2(
  821. WorkContext,
  822. STATUS_OBJECT_PATH_SYNTAX_BAD,
  823. TRUE
  824. );
  825. return SmbTransStatusErrorWithoutData;
  826. }
  827. freeFileName = TRUE;
  828. }
  829. }
  830. if ( illegalPath ) {
  831. search->InUse = FALSE;
  832. SrvDereferenceSearch( search );
  833. DEALLOCATE_NONPAGED_POOL( directoryInformation );
  834. SrvSetSmbError( WorkContext, STATUS_OBJECT_PATH_SYNTAX_BAD );
  835. return SmbTransStatusErrorWithoutData;
  836. }
  837. } else {
  838. //
  839. // Use the information in the search block.
  840. //
  841. fileName = search->LastFileNameReturned;
  842. freeFileName = FALSE;
  843. resumeFileIndex = search->LastFileIndexReturned;
  844. }
  845. //
  846. // Call SrvFind2Loop to fill the SMB buffer and set output parameters.
  847. //
  848. // !!! The NULL that might get passed for the resume file index is
  849. // a real hack. I doubt it is necessary, but it could prevent
  850. // a server crash if we somehow failed to store the resume file
  851. // name.
  852. status = SrvFind2Loop(
  853. WorkContext,
  854. FALSE,
  855. fileName.Buffer != NULL ? &resumeFileIndex : NULL,
  856. flags,
  857. informationLevel,
  858. transaction,
  859. directoryInformation,
  860. nonPagedBufferSize,
  861. search->SearchAttributes,
  862. &fileName,
  863. maxCount,
  864. response,
  865. search
  866. );
  867. if ( freeFileName ) {
  868. RtlFreeUnicodeString( &fileName );
  869. }
  870. if ( !NT_SUCCESS(status) && status != STATUS_NO_MORE_FILES ) {
  871. search->InUse = FALSE;
  872. SrvDereferenceSearch( search );
  873. DEALLOCATE_NONPAGED_POOL( directoryInformation );
  874. transaction->SetupCount = 0;
  875. transaction->ParameterCount = sizeof(RESP_FIND_NEXT2);
  876. SrvSetSmbError2( WorkContext, status, TRUE );
  877. return SmbTransStatusErrorWithData;
  878. }
  879. //
  880. // If the client told us to close the search after this request,
  881. // or close at end-of-search, close the search block and call
  882. // SrvCloseQueryDirectory.
  883. //
  884. if ( ( flags & SMB_FIND_CLOSE_AFTER_REQUEST ) != 0 ||
  885. ( status == STATUS_NO_MORE_FILES &&
  886. ( flags & SMB_FIND_CLOSE_AT_EOS ) != 0 ) ) {
  887. search->DirectoryHandle = NULL;
  888. SrvCloseSearch( search );
  889. SrvCloseQueryDirectory( directoryInformation );
  890. }
  891. //
  892. // Dereference our pointer to the search block and free the buffer.
  893. //
  894. DEALLOCATE_NONPAGED_POOL( directoryInformation );
  895. search->InUse = FALSE;
  896. SrvDereferenceSearch( search );
  897. //
  898. // Build the output parameter and data structures.
  899. //
  900. transaction->SetupCount = 0;
  901. transaction->ParameterCount = sizeof(RESP_FIND_NEXT2);
  902. return SmbTransStatusSuccess;
  903. } // DoFindNext2
  904. NTSTATUS
  905. SrvFind2Loop (
  906. IN PWORK_CONTEXT WorkContext,
  907. IN BOOLEAN IsFirstCall,
  908. IN PULONG ResumeFileIndex OPTIONAL,
  909. IN USHORT Flags,
  910. IN USHORT InformationLevel,
  911. IN PTRANSACTION Transaction,
  912. IN PSRV_DIRECTORY_INFORMATION DirectoryInformation,
  913. IN CLONG BufferSize,
  914. IN USHORT SearchAttributes,
  915. IN PUNICODE_STRING FileName OPTIONAL,
  916. IN USHORT MaxCount,
  917. IN PRESP_FIND_NEXT2 Response,
  918. OUT PSEARCH Search
  919. )
  920. /*++
  921. Routine Description:
  922. This routine does the looping necessary to get files and put them
  923. into an SMB buffer for the Find First2 and Find Next2 transaction
  924. protocols.
  925. Arguments:
  926. WorkContext -
  927. IsFirstCall - TRUE if this is a Find First and this is the first call
  928. to SrvQueryDirectoryFile.
  929. ResumeFileIndex - if non-NULL, a pointer to the file index to resume
  930. from.
  931. Flags - the Flags field of the request SMB.
  932. InformationLevel - the InformationLevel field of the request SMB. The
  933. validity of this value should be verified by the calling routine.
  934. Transaction - a pointer to the transaction block to use.
  935. DirectoryInformation - a pointer to the SRV_DIRECTORY_INFORMATION
  936. structure to use.
  937. BufferSize - size of the DirectoryInformation buffer.
  938. SearchAttributes - the SMB-style attributes to pass to
  939. SrvQueryDirectoryFile.
  940. FileName - if non-NULL the file name to resume the search from.
  941. MaxCount - the maximum number of files to get.
  942. Response - a pointer to the response field of the SMB. If this is
  943. a Find First2, it is a pointer to the SearchCount field of the
  944. response SMB--Find First2 and Find Next2 response formats are
  945. identical from this point on.
  946. Search - a pointer to the search block to use.
  947. Return Value:
  948. NTSTATUS indicating results.
  949. --*/
  950. {
  951. NTSTATUS status;
  952. PCHAR bufferLocation;
  953. BOOLEAN resumeKeysRequested;
  954. BOOLEAN allowExtraLongNames;
  955. BOOLEAN isUnicode;
  956. USHORT count = 0;
  957. PCHAR lastEntry;
  958. CLONG totalBytesWritten;
  959. OEM_STRING oemString;
  960. UNICODE_STRING unicodeString;
  961. UNICODE_STRING lastFileName;
  962. ULONG lastFileIndex = (ULONG)0xFFFFFFFF;
  963. HANDLE fileHandle;
  964. PFILE_GET_EA_INFORMATION ntGetEa;
  965. ULONG ntGetEaLength;
  966. USHORT eaErrorOffset = 0;
  967. BOOLEAN filterLongNames;
  968. BOOLEAN errorOnFileOpen;
  969. BOOLEAN findWithBackupIntent;
  970. IO_STATUS_BLOCK ioStatusBlock;
  971. OBJECT_ATTRIBUTES objectAttributes;
  972. BOOLEAN createNullEas;
  973. PAGED_CODE( );
  974. //
  975. // If the client is requesting an NT info level for search information,
  976. // do not return resume keys outside the actual file entry. Resume
  977. // keys (aka FileIndex) are part of every NT info structure.
  978. //
  979. // Also, for NT info levels we can return file names longer than 255
  980. // bytes, because the NT info levels have name length fields that
  981. // are four bytes wide, whereas the downlevel info levels only have
  982. // one-byte name length fields.
  983. //
  984. if ( InformationLevel == SMB_FIND_FILE_DIRECTORY_INFO ||
  985. InformationLevel == SMB_FIND_FILE_FULL_DIRECTORY_INFO ||
  986. InformationLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO ||
  987. InformationLevel == SMB_FIND_FILE_NAMES_INFO ||
  988. InformationLevel == SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO ||
  989. InformationLevel == SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO
  990. ) {
  991. resumeKeysRequested = FALSE;
  992. allowExtraLongNames = TRUE;
  993. } else {
  994. resumeKeysRequested =
  995. (BOOLEAN)((Flags & SMB_FIND_RETURN_RESUME_KEYS) != 0 ? TRUE : FALSE);
  996. allowExtraLongNames = FALSE;
  997. }
  998. //
  999. // Is this for backup intent?
  1000. //
  1001. if ( (Flags & SMB_FIND_WITH_BACKUP_INTENT) != 0 ) {
  1002. findWithBackupIntent = TRUE;
  1003. } else {
  1004. findWithBackupIntent = FALSE;
  1005. }
  1006. //
  1007. // Is this request in Unicode?
  1008. //
  1009. isUnicode = SMB_IS_UNICODE( WorkContext );
  1010. //
  1011. // Initialize count of files found.
  1012. //
  1013. SmbPutUshort( &Response->SearchCount, 0 );
  1014. //
  1015. // If this a request to return EAs, convert the OS/2 1.2 EA list
  1016. // to NT format. This routine allocates space for the NT list
  1017. // which must be deallocated before we exit.
  1018. //
  1019. if ( InformationLevel == SMB_INFO_QUERY_EAS_FROM_LIST ) {
  1020. PGEALIST geaList = (PGEALIST)Transaction->InData;
  1021. if (Transaction->DataCount < sizeof(GEALIST) ||
  1022. SmbGetUshort(&geaList->cbList) < sizeof(GEALIST) ||
  1023. SmbGetUshort(&geaList->cbList) > Transaction->DataCount) {
  1024. SmbPutUshort( &Response->SearchCount, 0 );
  1025. SmbPutUshort( &Response->EndOfSearch, 0 );
  1026. SmbPutUshort( &Response->EaErrorOffset, 0 );
  1027. SmbPutUshort( &Response->LastNameOffset, 0 );
  1028. Transaction->DataCount = 0;
  1029. return STATUS_OS2_EA_LIST_INCONSISTENT;
  1030. }
  1031. status = SrvOs2GeaListToNt(
  1032. geaList,
  1033. &ntGetEa,
  1034. &ntGetEaLength,
  1035. &eaErrorOffset
  1036. );
  1037. if ( !NT_SUCCESS(status) ) {
  1038. IF_DEBUG(ERRORS) {
  1039. SrvPrint1( "SrvFind2Loop: SrvOs2GeaListToNt failed, "
  1040. "status = %X\n", status );
  1041. }
  1042. SmbPutUshort( &Response->SearchCount, 0 );
  1043. SmbPutUshort( &Response->EndOfSearch, 0 );
  1044. SmbPutUshort( &Response->EaErrorOffset, eaErrorOffset );
  1045. SmbPutUshort( &Response->LastNameOffset, 0 );
  1046. Transaction->DataCount = 0;
  1047. return status;
  1048. }
  1049. }
  1050. //
  1051. // Determine whether long filenames (non-8.3) should be filtered out
  1052. // or returned to the client.
  1053. //
  1054. // There is a bug in the LanMan21 that makes the redir forget that
  1055. // he knows about long names.
  1056. if ( ( ( Search->Flags2 & SMB_FLAGS2_KNOWS_LONG_NAMES ) != 0 ) &&
  1057. !IS_DOS_DIALECT( WorkContext->Connection->SmbDialect ) ) {
  1058. filterLongNames = FALSE;
  1059. } else {
  1060. filterLongNames = TRUE;
  1061. }
  1062. //
  1063. // If the client says he doesn't know about long names and this is
  1064. // a request for any info level other than SMB_INFO_STANDARD, we
  1065. // need to fail the request.
  1066. //
  1067. if ( filterLongNames && InformationLevel != SMB_INFO_STANDARD ) {
  1068. IF_DEBUG(ERRORS) {
  1069. SrvPrint0( "SrvFind2Loop: client doesn't know long names.\n" );
  1070. }
  1071. SmbPutUshort( &Response->SearchCount, 0 );
  1072. SmbPutUshort( &Response->EndOfSearch, 0 );
  1073. SmbPutUshort( &Response->EaErrorOffset, 0 );
  1074. SmbPutUshort( &Response->LastNameOffset, 0 );
  1075. Transaction->DataCount = 0;
  1076. return STATUS_INVALID_PARAMETER;
  1077. }
  1078. //
  1079. // Loop calling SrvQueryDirectoryFile to get files. We do this until
  1080. // one of the following conditions is met:
  1081. //
  1082. // 1) There are no more files to return.
  1083. // 2) We have obtained as many files as were requested.
  1084. // 3) We have put in as much data as MaxDataCount allows.
  1085. //
  1086. bufferLocation = Transaction->OutData;
  1087. lastEntry = bufferLocation;
  1088. totalBytesWritten = 0;
  1089. do {
  1090. //
  1091. // The ff fields have the same offsets in the three directory
  1092. // information structures:
  1093. // NextEntryOffset
  1094. // FileIndex
  1095. // CreationTime
  1096. // LastAccessTime
  1097. // LastWriteTime
  1098. // ChangeTime
  1099. // EndOfFile
  1100. // AllocationSize
  1101. // FileAttributes
  1102. // FileNameLength
  1103. //
  1104. PFILE_DIRECTORY_INFORMATION fileBasic;
  1105. PFILE_FULL_DIR_INFORMATION fileFull;
  1106. PFILE_BOTH_DIR_INFORMATION fileBoth;
  1107. PFILE_ID_FULL_DIR_INFORMATION fileIdFull;
  1108. PFILE_ID_BOTH_DIR_INFORMATION fileIdBoth;
  1109. ULONG ntInformationLevel;
  1110. //
  1111. // Make sure these asserts hold.
  1112. //
  1113. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, NextEntryOffset ) ==
  1114. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, NextEntryOffset ) );
  1115. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileIndex ) ==
  1116. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileIndex ) );
  1117. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, CreationTime ) ==
  1118. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, CreationTime ) );
  1119. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, LastAccessTime ) ==
  1120. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, LastAccessTime ) );
  1121. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, LastWriteTime ) ==
  1122. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, LastWriteTime ) );
  1123. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, ChangeTime ) ==
  1124. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, ChangeTime ) );
  1125. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, EndOfFile ) ==
  1126. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, EndOfFile ) );
  1127. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, AllocationSize ) ==
  1128. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, AllocationSize ) );
  1129. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileAttributes ) ==
  1130. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileAttributes ) );
  1131. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileNameLength ) ==
  1132. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileNameLength ) );
  1133. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, NextEntryOffset ) ==
  1134. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, NextEntryOffset ) );
  1135. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileIndex ) ==
  1136. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileIndex ) );
  1137. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, CreationTime ) ==
  1138. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, CreationTime ) );
  1139. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, LastAccessTime ) ==
  1140. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, LastAccessTime ) );
  1141. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, LastWriteTime ) ==
  1142. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, LastWriteTime ) );
  1143. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, ChangeTime ) ==
  1144. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, ChangeTime ) );
  1145. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, EndOfFile ) ==
  1146. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, EndOfFile ) );
  1147. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, AllocationSize ) ==
  1148. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, AllocationSize ) );
  1149. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileAttributes ) ==
  1150. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileAttributes ) );
  1151. C_ASSERT( FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileNameLength ) ==
  1152. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileNameLength ) );
  1153. //
  1154. // Set the info level to be used for the NT call. If
  1155. // SMB_FIND_FILE_NAMES_INFO is the info level, use
  1156. // FileDirectoryInformation as it returns all the correct
  1157. // information and works with SrvQueryDirectoryFile.
  1158. //
  1159. if ( InformationLevel == SMB_INFO_QUERY_EA_SIZE ||
  1160. InformationLevel == SMB_FIND_FILE_FULL_DIRECTORY_INFO ) {
  1161. ntInformationLevel = FileFullDirectoryInformation;
  1162. } else if ( InformationLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO ||
  1163. InformationLevel == SMB_INFO_STANDARD ) {
  1164. ntInformationLevel = FileBothDirectoryInformation;
  1165. } else if ( InformationLevel == SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO ) {
  1166. ntInformationLevel = FileIdFullDirectoryInformation;
  1167. } else if ( InformationLevel == SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO ) {
  1168. ntInformationLevel = FileIdBothDirectoryInformation;
  1169. }
  1170. else {
  1171. //
  1172. // SMB_INFO_QUERY_EAS_FROM_LIST
  1173. // SMB_FIND_NAMES_INFO
  1174. // SMB_FIND_FILE_DIRECTORY_INFO
  1175. //
  1176. ntInformationLevel = FileDirectoryInformation;
  1177. }
  1178. //
  1179. // Call SrvQueryDirectoryFile to get a file.
  1180. //
  1181. status = SrvQueryDirectoryFile(
  1182. WorkContext,
  1183. IsFirstCall,
  1184. filterLongNames,
  1185. findWithBackupIntent,
  1186. ntInformationLevel,
  1187. Search->SearchStorageType,
  1188. FileName,
  1189. ResumeFileIndex,
  1190. SearchAttributes,
  1191. DirectoryInformation,
  1192. BufferSize // !!! optimizations?
  1193. );
  1194. //
  1195. // If the client requested EA information, open the file.
  1196. //
  1197. // If the found file is '.' (current directory) or '..' (parent
  1198. // directory) do not open the file. This is because we do not want
  1199. // to perform any operations on these files at this point (don't
  1200. // return EA size, etc.).
  1201. //
  1202. fileBasic = DirectoryInformation->CurrentEntry;
  1203. fileBoth = (PFILE_BOTH_DIR_INFORMATION)DirectoryInformation->CurrentEntry;
  1204. fileFull = (PFILE_FULL_DIR_INFORMATION)DirectoryInformation->CurrentEntry;
  1205. fileIdBoth = (PFILE_ID_BOTH_DIR_INFORMATION)DirectoryInformation->CurrentEntry;
  1206. fileIdFull = (PFILE_ID_FULL_DIR_INFORMATION)DirectoryInformation->CurrentEntry;
  1207. errorOnFileOpen = FALSE;
  1208. createNullEas = FALSE;
  1209. if ( NT_SUCCESS( status ) &&
  1210. InformationLevel == SMB_INFO_QUERY_EAS_FROM_LIST &&
  1211. !( ( fileBasic->FileNameLength == sizeof(WCHAR) &&
  1212. fileBasic->FileName[0] == '.' )
  1213. ||
  1214. ( fileBasic->FileNameLength == 2*sizeof(WCHAR) &&
  1215. fileBasic->FileName[0] == '.' &&
  1216. fileBasic->FileName[1] == '.' ) )
  1217. ) {
  1218. UNICODE_STRING fileName;
  1219. //
  1220. // Set up local variables for the filename to open.
  1221. //
  1222. fileName.Length = (SHORT)fileBasic->FileNameLength;
  1223. fileName.MaximumLength = fileName.Length;
  1224. fileName.Buffer = (PWCH)fileBasic->FileName;
  1225. //
  1226. // Set up the object attributes structure for SrvIoCreateFile.
  1227. //
  1228. SrvInitializeObjectAttributes_U(
  1229. &objectAttributes,
  1230. &fileName,
  1231. (WorkContext->RequestHeader->Flags &
  1232. SMB_FLAGS_CASE_INSENSITIVE ||
  1233. WorkContext->Session->UsingUppercasePaths) ?
  1234. OBJ_CASE_INSENSITIVE : 0L,
  1235. DirectoryInformation->DirectoryHandle,
  1236. NULL
  1237. );
  1238. IF_DEBUG(SEARCH) {
  1239. SrvPrint1( "SrvQueryDirectoryFile: Opening file %wZ\n", &fileName );
  1240. }
  1241. //
  1242. // Attempt to open the file, using the client's security
  1243. // profile to check access. (We call SrvIoCreateFile, rather than
  1244. // NtOpenFile, in order to get user-mode access checking.)
  1245. //
  1246. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  1247. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
  1248. status = SrvIoCreateFile(
  1249. WorkContext,
  1250. &fileHandle,
  1251. FILE_READ_EA,
  1252. &objectAttributes,
  1253. &ioStatusBlock,
  1254. NULL, // AllocationSize
  1255. 0, // FileAttributes
  1256. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1257. FILE_OPEN, // Disposition
  1258. 0, // FILE_COMPLETE_IF_OPLOCKED, // CreateOptions
  1259. NULL, // EaBuffer
  1260. 0, // EaLength
  1261. CreateFileTypeNone, // File type
  1262. NULL, // ExtraCreateParameters
  1263. IO_FORCE_ACCESS_CHECK, // Options
  1264. NULL
  1265. );
  1266. if ( NT_SUCCESS(status) ) {
  1267. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 29, Search );
  1268. } else if( RtlCompareUnicodeString( &fileName, &SrvEaFileName, TRUE ) == 0 ) {
  1269. //
  1270. // They were trying to open up the EA data file. We expect this
  1271. // failure and skip past it. This file has no EAs
  1272. //
  1273. IF_DEBUG(SEARCH) {
  1274. SrvPrint1( "SrvQueryDirectoryFile: Skipping file %wZ\n", &fileName );
  1275. }
  1276. status = STATUS_SUCCESS;
  1277. goto skipit;
  1278. }
  1279. //
  1280. // If the user didn't have this permission, update the statistics
  1281. // database.
  1282. //
  1283. if ( status == STATUS_ACCESS_DENIED ) {
  1284. SrvStatistics.AccessPermissionErrors++;
  1285. }
  1286. //
  1287. // If the file is oplocked, wait for the oplock to break
  1288. // synchronously.
  1289. //
  1290. #if 1
  1291. ASSERT( status != STATUS_OPLOCK_BREAK_IN_PROGRESS );
  1292. #else
  1293. if ( status == STATUS_OPLOCK_BREAK_IN_PROGRESS ) {
  1294. status = SrvWaitForOplockBreak( WorkContext, fileHandle );
  1295. if ( !NT_SUCCESS(status) ) {
  1296. SRVDBG_RELEASE_HANDLE( fileHandle, "FIL", 45, Search );
  1297. SrvNtClose( fileHandle, TRUE );
  1298. }
  1299. }
  1300. #endif
  1301. if ( !NT_SUCCESS(status) ) {
  1302. errorOnFileOpen = TRUE;
  1303. fileHandle = NULL;
  1304. IF_DEBUG(ERRORS) {
  1305. SrvPrint2( "Find2Loop: SrvIoCreateFile for file %wZ "
  1306. "failed: %X\n",
  1307. &fileName, status );
  1308. }
  1309. } else {
  1310. SrvStatistics.TotalFilesOpened++;
  1311. }
  1312. } else {
  1313. skipit:
  1314. createNullEas = TRUE;
  1315. fileHandle = NULL;
  1316. }
  1317. //
  1318. // If SrvQueryDirectoryFile returns an error, break out of the
  1319. // loop. If the error occurred in opening the file for one of
  1320. // the higher info levels, then we want to return the files we
  1321. // have obtained so far.
  1322. //
  1323. // If the error occurred on the file open *and* we haven't
  1324. // returned any files yet, then we want to return this file
  1325. // along with the code ERROR_EA_ACCESS_DENIED.
  1326. //
  1327. if ( !NT_SUCCESS(status) ) {
  1328. if ( count == 0 && errorOnFileOpen ) {
  1329. IF_DEBUG(ERRORS) {
  1330. SrvPrint1( "EA access denied on first file of search (%x).\n",
  1331. status );
  1332. }
  1333. fileHandle = NULL;
  1334. status = STATUS_OS2_EA_ACCESS_DENIED;
  1335. break;
  1336. } else if ( status == STATUS_NO_MORE_FILES && count == 0 ) {
  1337. SmbPutUshort( &Response->SearchCount, 0 );
  1338. SmbPutUshort( &Response->EndOfSearch, 0 );
  1339. SmbPutUshort( &Response->EaErrorOffset, 0 );
  1340. SmbPutUshort( &Response->LastNameOffset, 0 );
  1341. Transaction->DataCount = 0;
  1342. return status;
  1343. } else {
  1344. break;
  1345. }
  1346. }
  1347. //
  1348. // Since it is no longer the first call to SrvQueryDirectoryFile,
  1349. // reset the isFirstCall local variable. If necessary, we already
  1350. // rewound the search, so set the ResumeFileIndex to NULL.
  1351. //
  1352. IsFirstCall = FALSE;
  1353. ResumeFileIndex = NULL;
  1354. IF_SMB_DEBUG(SEARCH2) {
  1355. UNICODE_STRING nameString;
  1356. switch (ntInformationLevel) {
  1357. case FileFullDirectoryInformation:
  1358. nameString.Buffer = fileFull->FileName;
  1359. nameString.Length = (USHORT)fileFull->FileNameLength;
  1360. break;
  1361. case FileBothDirectoryInformation:
  1362. nameString.Buffer = fileBoth->FileName;
  1363. nameString.Length = (USHORT)fileBoth->FileNameLength;
  1364. break;
  1365. default:
  1366. nameString.Buffer = fileBasic->FileName;
  1367. nameString.Length = (USHORT)fileBasic->FileNameLength;
  1368. break;
  1369. }
  1370. SrvPrint4( "SrvQueryDirectoryFile(%ld)-- %p, length=%ld, "
  1371. "status=%X\n", count,
  1372. &nameString,
  1373. nameString.Length,
  1374. status );
  1375. }
  1376. //
  1377. // Downlevel info levels have no provision for file names longer
  1378. // than 8 bits, while the NT info levels return 32 bits. If the
  1379. // file name is too long, skip it.
  1380. //
  1381. if ( !allowExtraLongNames ) {
  1382. if ( isUnicode ) {
  1383. if ( fileBasic->FileNameLength > 255 ) {
  1384. continue;
  1385. }
  1386. } else {
  1387. if ( fileBasic->FileNameLength > 255*sizeof(WCHAR) ) {
  1388. continue;
  1389. }
  1390. }
  1391. }
  1392. //
  1393. // If the client has requested that resume keys (really file
  1394. // indices for the purposes of this protocol), put in the
  1395. // four bytes just before the actual file information.
  1396. //
  1397. // Make sure that we don't write beyond the buffer when we do
  1398. // this. The fact that the buffer is full will be caught later.
  1399. //
  1400. if ( resumeKeysRequested &&
  1401. ( (CLONG)( (bufferLocation+4) - Transaction->OutData ) <
  1402. Transaction->MaxDataCount ) ) {
  1403. SmbPutUlong( (PSMB_ULONG)bufferLocation, fileBasic->FileIndex );
  1404. bufferLocation += 4;
  1405. }
  1406. //
  1407. // Convert the information from NT style to the SMB protocol format,
  1408. // which is identical to the OS/2 1.2 semantics. Use an if
  1409. // statement rather than a switch so that a break will cause
  1410. // termination of the do loop.
  1411. //
  1412. if ( InformationLevel == SMB_INFO_STANDARD ) {
  1413. PSMB_FIND_BUFFER findBuffer = (PSMB_FIND_BUFFER)bufferLocation;
  1414. ULONG fileNameLength;
  1415. UNICODE_STRING fileName;
  1416. //
  1417. // Find the file name. If a short name is present, and the
  1418. // redirector ask for short names only, use it. Otherwise
  1419. // use the full file name.
  1420. //
  1421. if ( filterLongNames &&
  1422. fileBoth->ShortNameLength != 0 ) {
  1423. fileName.Buffer = fileBoth->ShortName;
  1424. fileName.Length = fileBoth->ShortNameLength;
  1425. fileName.MaximumLength = fileBoth->ShortNameLength;
  1426. } else {
  1427. fileName.Buffer = fileBoth->FileName;
  1428. fileName.Length = (USHORT)fileBoth->FileNameLength;
  1429. fileName.MaximumLength = (USHORT)fileBoth->FileNameLength;
  1430. }
  1431. //
  1432. // Find the new buffer location. This is not used until the
  1433. // next pass through the loop, but we do it here in order to
  1434. // check if there is enough space for the current file entry in
  1435. // the buffer. The +1 is for the zero terminator on the file
  1436. // name.
  1437. //
  1438. if ( isUnicode ) {
  1439. bufferLocation = ALIGN_SMB_WSTR( findBuffer->FileName );
  1440. bufferLocation += fileName.Length + sizeof(WCHAR);
  1441. } else {
  1442. unicodeString.Buffer = fileName.Buffer;
  1443. unicodeString.Length = fileName.Length;
  1444. unicodeString.MaximumLength = unicodeString.Length;
  1445. fileNameLength = RtlUnicodeStringToOemSize( &unicodeString );
  1446. bufferLocation = (PCHAR)(findBuffer->FileName + fileNameLength);
  1447. }
  1448. //
  1449. // Make sure that there is enough space in the buffer before
  1450. // writing the filename.
  1451. //
  1452. if ( (CLONG)(bufferLocation - Transaction->OutData) >
  1453. Transaction->MaxDataCount ) {
  1454. status = STATUS_BUFFER_OVERFLOW;
  1455. bufferLocation = (PCHAR)findBuffer;
  1456. break;
  1457. }
  1458. //
  1459. // Put information about the file into the SMB buffer.
  1460. //
  1461. ConvertFileInfo(
  1462. fileBasic,
  1463. fileName.Buffer,
  1464. (BOOLEAN)((fileBoth->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0),
  1465. isUnicode,
  1466. findBuffer
  1467. );
  1468. //
  1469. // Put the file name in the buffer, in Unicode or ANSI
  1470. // depending what was negotiated.
  1471. //
  1472. if ( isUnicode ) {
  1473. PWCH buffer = ALIGN_SMB_WSTR( findBuffer->FileName );
  1474. //
  1475. // We need to upper case the name if the client does
  1476. // not understand long names. This is done for compatibility
  1477. // reasons (FAT upper cases names).
  1478. //
  1479. if ( filterLongNames ) {
  1480. (VOID)RtlUpcaseUnicodeString(
  1481. &fileName,
  1482. &fileName,
  1483. FALSE
  1484. );
  1485. }
  1486. RtlCopyMemory(
  1487. buffer,
  1488. fileName.Buffer,
  1489. fileName.Length
  1490. );
  1491. ASSERT(fileName.Length <= 255);
  1492. findBuffer->FileNameLength = (UCHAR)fileName.Length;
  1493. } else {
  1494. oemString.MaximumLength = (USHORT)fileNameLength;
  1495. oemString.Buffer = (PCHAR)findBuffer->FileName;
  1496. //
  1497. // We need to upper case the name if the client does
  1498. // not understand long names. This is done for compatibility
  1499. // reasons (FAT upper cases names).
  1500. //
  1501. if ( filterLongNames ) {
  1502. status = RtlUpcaseUnicodeStringToOemString(
  1503. &oemString,
  1504. &unicodeString,
  1505. FALSE
  1506. );
  1507. } else {
  1508. status = RtlUnicodeStringToOemString(
  1509. &oemString,
  1510. &unicodeString,
  1511. FALSE
  1512. );
  1513. }
  1514. ASSERT( NT_SUCCESS(status) );
  1515. ASSERT(oemString.Length <= 255);
  1516. findBuffer->FileNameLength = (UCHAR)oemString.Length;
  1517. }
  1518. //
  1519. // The lastEntry variable holds a pointer to the last file entry
  1520. // that we wrote--an offset to this entry must be returned
  1521. // in the response SMB.
  1522. //
  1523. lastEntry = (PCHAR)findBuffer;
  1524. //
  1525. // The file name and index of the last file returned must be
  1526. // stored in the search block. Save the name pointer, length,
  1527. // and file index here.
  1528. //
  1529. lastFileName.Buffer = fileName.Buffer;
  1530. lastFileName.Length = (USHORT)fileName.Length;
  1531. lastFileName.MaximumLength = lastFileName.Length;
  1532. lastFileIndex = fileBoth->FileIndex;
  1533. } else if ( InformationLevel == SMB_INFO_QUERY_EA_SIZE ) {
  1534. PSMB_FIND_BUFFER2 findBuffer = (PSMB_FIND_BUFFER2)bufferLocation;
  1535. ULONG fileNameLength;
  1536. //
  1537. // Find the new buffer location. This is not used until the
  1538. // next pass through the loop, but we do it here in order to
  1539. // check if there is enough space for the current file entry in
  1540. // the buffer. The +1 is for the zero terminator on the file
  1541. // name.
  1542. //
  1543. if ( isUnicode ) {
  1544. bufferLocation =
  1545. (PCHAR)(findBuffer->FileName + fileFull->FileNameLength + 1);
  1546. } else {
  1547. unicodeString.Buffer = fileFull->FileName;
  1548. unicodeString.Length = (USHORT)fileFull->FileNameLength;
  1549. unicodeString.MaximumLength = unicodeString.Length;
  1550. fileNameLength = RtlUnicodeStringToOemSize( &unicodeString );
  1551. bufferLocation = (PCHAR)(findBuffer->FileName + fileNameLength);
  1552. }
  1553. //
  1554. // Make sure that there is enough space in the buffer before
  1555. // writing the filename.
  1556. //
  1557. if ( (CLONG)(bufferLocation - Transaction->OutData) >
  1558. Transaction->MaxDataCount ) {
  1559. status = STATUS_BUFFER_OVERFLOW;
  1560. bufferLocation = (PCHAR)findBuffer;
  1561. break;
  1562. }
  1563. //
  1564. // Put information about the file into the SMB buffer.
  1565. //
  1566. ConvertFileInfo(
  1567. fileBasic,
  1568. fileFull->FileName,
  1569. (BOOLEAN)((fileFull->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0),
  1570. isUnicode,
  1571. (PSMB_FIND_BUFFER)findBuffer
  1572. );
  1573. if ( isUnicode ) {
  1574. RtlCopyMemory(
  1575. findBuffer->FileName,
  1576. fileFull->FileName,
  1577. fileFull->FileNameLength
  1578. );
  1579. ASSERT(fileFull->FileNameLength <= 255);
  1580. findBuffer->FileNameLength = (UCHAR)fileFull->FileNameLength;
  1581. } else {
  1582. oemString.MaximumLength = (USHORT)fileNameLength;
  1583. oemString.Buffer = (PCHAR)(findBuffer->FileName);
  1584. status = RtlUnicodeStringToOemString(
  1585. &oemString,
  1586. &unicodeString,
  1587. FALSE
  1588. );
  1589. ASSERT( NT_SUCCESS(status) );
  1590. ASSERT(oemString.Length <= 255);
  1591. findBuffer->FileNameLength = (UCHAR)oemString.Length;
  1592. }
  1593. if ( fileFull->EaSize == 0) {
  1594. SmbPutUlong( &findBuffer->EaSize, 4 );
  1595. } else {
  1596. SmbPutUlong( &findBuffer->EaSize, fileFull->EaSize );
  1597. }
  1598. //
  1599. // The lastEntry variable holds a pointer to the last file entry
  1600. // that we wrote--an offset to this entry must be returned
  1601. // in the response SMB.
  1602. //
  1603. lastEntry = (PCHAR)findBuffer;
  1604. //
  1605. // The file name and index of the last file returned must be
  1606. // stored in the search block. Save the name pointer, length,
  1607. // and file index here.
  1608. //
  1609. lastFileName.Buffer = fileFull->FileName;
  1610. lastFileName.Length = (USHORT)fileFull->FileNameLength;
  1611. lastFileName.MaximumLength = lastFileName.Length;
  1612. lastFileIndex = fileFull->FileIndex;
  1613. } else if ( InformationLevel == SMB_INFO_QUERY_EAS_FROM_LIST ) {
  1614. PSMB_FIND_BUFFER2 findBuffer = (PSMB_FIND_BUFFER2)bufferLocation;
  1615. PFEALIST feaList;
  1616. PCHAR fileNameInfo;
  1617. ULONG fileNameLength;
  1618. //
  1619. // Find the new buffer location. This is not used until the
  1620. // next pass through the loop, but we do it here in order to
  1621. // check if there is enough space for the current file entry
  1622. // in the buffer. The +1 is for the zero terminator on the
  1623. // file name. A check is made later on to see if the EAs
  1624. // actually fit, and the bufferLocation variable is reset to
  1625. // account for the actual size of the EA.
  1626. //
  1627. if ( isUnicode ) {
  1628. bufferLocation =
  1629. (PCHAR)(findBuffer->FileName + fileBasic->FileNameLength + 1);
  1630. } else {
  1631. unicodeString.Buffer = fileBasic->FileName;
  1632. unicodeString.Length = (USHORT)fileBasic->FileNameLength;
  1633. unicodeString.MaximumLength = unicodeString.Length;
  1634. fileNameLength = RtlUnicodeStringToOemSize( &unicodeString );
  1635. bufferLocation =
  1636. (PCHAR)(findBuffer->FileName + fileNameLength + 1);
  1637. }
  1638. //
  1639. // Make sure that there is enough space in the buffer before
  1640. // writing the filename.
  1641. //
  1642. if ( (CLONG)(bufferLocation - Transaction->OutData) >
  1643. Transaction->MaxDataCount ) {
  1644. status = STATUS_BUFFER_OVERFLOW;
  1645. SRVDBG_RELEASE_HANDLE( fileHandle, "FIL", 46, Search );
  1646. SrvNtClose( fileHandle, TRUE );
  1647. fileHandle = NULL;
  1648. bufferLocation = (PCHAR)findBuffer;
  1649. break;
  1650. }
  1651. //
  1652. // Put information about the file into the SMB buffer.
  1653. //
  1654. ConvertFileInfo(
  1655. fileBasic,
  1656. fileBasic->FileName,
  1657. (BOOLEAN)((fileBasic->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0),
  1658. isUnicode,
  1659. (PSMB_FIND_BUFFER)findBuffer
  1660. );
  1661. //
  1662. // Get the EAs corresponding to the GEA list passed by the
  1663. // client.
  1664. //
  1665. feaList = (PFEALIST)&findBuffer->EaSize;
  1666. if ( ( fileHandle != NULL ) || createNullEas ) {
  1667. if ( fileHandle != NULL ) {
  1668. //
  1669. // Get the file's EAs. The buffer space available is
  1670. // the space remaining in the buffer less enough space
  1671. // to write the file name, name length, and zero
  1672. // terminator.
  1673. //
  1674. status = SrvQueryOs2FeaList(
  1675. fileHandle,
  1676. NULL,
  1677. ntGetEa,
  1678. ntGetEaLength,
  1679. feaList,
  1680. (Transaction->MaxDataCount -
  1681. (ULONG)( (PCHAR)feaList - Transaction->OutData ) -
  1682. fileBasic->FileNameLength - 2),
  1683. &eaErrorOffset
  1684. );
  1685. SRVDBG_RELEASE_HANDLE( fileHandle, "FIL", 47, Search );
  1686. SrvNtClose( fileHandle, TRUE );
  1687. } else {
  1688. //
  1689. // if file is . or .. or "EA DATA. SF"
  1690. //
  1691. status = SrvConstructNullOs2FeaList(
  1692. ntGetEa,
  1693. feaList,
  1694. (Transaction->MaxDataCount -
  1695. (ULONG)( (PCHAR)feaList - Transaction->OutData ) -
  1696. fileBasic->FileNameLength - 2)
  1697. );
  1698. }
  1699. if ( !NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW ) {
  1700. IF_DEBUG(ERRORS) {
  1701. SrvPrint1( "SrvQueryOs2FeaList failed, status = %X\n",
  1702. status );
  1703. }
  1704. //
  1705. // If this is the first file, return it anyway with
  1706. // an error code.
  1707. //
  1708. if ( status == STATUS_INVALID_EA_NAME ) {
  1709. SmbPutUshort( &Response->SearchCount, 0 );
  1710. SmbPutUshort( &Response->EndOfSearch, 0 );
  1711. SmbPutUshort( &Response->EaErrorOffset, eaErrorOffset );
  1712. SmbPutUshort( &Response->LastNameOffset, 0 );
  1713. Transaction->DataCount = 0;
  1714. return status;
  1715. }
  1716. if ( count == 0 ) {
  1717. status = STATUS_OS2_EA_ACCESS_DENIED;
  1718. SmbPutUlong( &findBuffer->EaSize, 0 );
  1719. } else {
  1720. break;
  1721. }
  1722. }
  1723. //
  1724. // We already checked to see if the information other
  1725. // than EAs would fit in the buffer. If the EAs didn't
  1726. // fit as well, and this is the first file, then return
  1727. // information on this file but no EAs. Return
  1728. // STATUS_OS2_EAS_DIDNT_FIT. The EA size of the file
  1729. // should be in the EaSize field of the output buffer,
  1730. // put there by SrvQueryOs2FeaList.
  1731. //
  1732. // Also do this if we couldn't get at the file's EAs.
  1733. //
  1734. if ( count == 0 &&
  1735. ( status == STATUS_BUFFER_OVERFLOW ||
  1736. status == STATUS_OS2_EA_ACCESS_DENIED ) ) {
  1737. IF_DEBUG(ERRORS) {
  1738. SrvPrint0( "First file's EAs would not fit.\n" );
  1739. }
  1740. count = 1;
  1741. //
  1742. // Write the file name information (length and name).
  1743. //
  1744. if ( isUnicode ) {
  1745. RtlCopyMemory(
  1746. (PVOID) (&findBuffer->FileNameLength + 1),
  1747. fileBasic->FileName,
  1748. fileBasic->FileNameLength
  1749. );
  1750. findBuffer->FileNameLength = (UCHAR)fileBasic->FileNameLength;
  1751. bufferLocation = (PCHAR)
  1752. (findBuffer->FileName + fileBasic->FileNameLength + 1);
  1753. } else {
  1754. NTSTATUS rtlStatus;
  1755. oemString.MaximumLength = (USHORT)fileNameLength;
  1756. oemString.Buffer =
  1757. (PUCHAR)(&findBuffer->FileNameLength + 1);
  1758. rtlStatus = RtlUnicodeStringToOemString(
  1759. &oemString,
  1760. &unicodeString,
  1761. FALSE
  1762. );
  1763. ASSERT( NT_SUCCESS(rtlStatus) );
  1764. findBuffer->FileNameLength = (UCHAR)oemString.Length;
  1765. bufferLocation = (PCHAR)
  1766. (findBuffer->FileName + oemString.Length + 1);
  1767. }
  1768. lastEntry = (PCHAR)findBuffer;
  1769. lastFileName.Buffer = fileBasic->FileName;
  1770. lastFileName.Length = (USHORT)fileBasic->FileNameLength;
  1771. lastFileName.MaximumLength = lastFileName.Length;
  1772. lastFileIndex = fileBasic->FileIndex;
  1773. if ( status == STATUS_BUFFER_OVERFLOW ) {
  1774. status = STATUS_OS2_EAS_DIDNT_FIT;
  1775. }
  1776. break;
  1777. }
  1778. } else {
  1779. SmbPutUlong( &feaList->cbList, sizeof(feaList->cbList) );
  1780. }
  1781. //
  1782. // Make sure that there is enough buffer space to write the
  1783. // file name and name size. The +2 is to account for the
  1784. // file name size field and the zero terminator.
  1785. //
  1786. fileNameInfo = (PCHAR)feaList->list +
  1787. SmbGetUlong( &feaList->cbList ) -
  1788. sizeof(feaList->cbList);
  1789. if ( isUnicode ) {
  1790. bufferLocation = fileNameInfo + fileBasic->FileNameLength + 2;
  1791. } else {
  1792. bufferLocation = fileNameInfo + fileNameLength + 1;
  1793. }
  1794. if ( (CLONG)(bufferLocation - Transaction->OutData) >
  1795. Transaction->MaxDataCount ) {
  1796. status = STATUS_BUFFER_OVERFLOW;
  1797. bufferLocation = (PCHAR)findBuffer;
  1798. break;
  1799. }
  1800. //
  1801. // Write the file name information (length and name).
  1802. //
  1803. if ( isUnicode ) {
  1804. RtlCopyMemory(
  1805. fileNameInfo + 1,
  1806. fileBasic->FileName,
  1807. fileBasic->FileNameLength
  1808. );
  1809. } else {
  1810. NTSTATUS rtlStatus;
  1811. oemString.MaximumLength = (USHORT)fileNameLength;
  1812. oemString.Buffer = fileNameInfo + 1;
  1813. rtlStatus = RtlUnicodeStringToOemString(
  1814. &oemString,
  1815. &unicodeString,
  1816. FALSE
  1817. );
  1818. ASSERT( NT_SUCCESS(rtlStatus) );
  1819. }
  1820. *fileNameInfo++ = (UCHAR)oemString.Length;
  1821. IF_SMB_DEBUG(SEARCH2) {
  1822. SrvPrint1( "EA size is %ld\n", SmbGetUlong( &feaList->cbList ) );
  1823. }
  1824. //
  1825. // The lastEntry variable holds a pointer to the last file entry
  1826. // that we wrote--an offset to this entry must be returned
  1827. // in the response SMB.
  1828. //
  1829. lastEntry = (PCHAR)findBuffer;
  1830. //
  1831. // The file name and index of the last file returned must be
  1832. // stored in the search block. Save the name pointer, length,
  1833. // and file index here.
  1834. //
  1835. lastFileName.Buffer = fileBasic->FileName;
  1836. lastFileName.Length = (USHORT)fileBasic->FileNameLength;
  1837. lastFileName.MaximumLength = lastFileName.Length;
  1838. lastFileIndex = fileBasic->FileIndex;
  1839. } else if ( InformationLevel == SMB_FIND_FILE_DIRECTORY_INFO ) {
  1840. FILE_DIRECTORY_INFORMATION UNALIGNED *findBuffer = (PVOID)bufferLocation;
  1841. ULONG fileNameLength;
  1842. //
  1843. // If the client is not speaking Unicode, we need to convert
  1844. // the file name to ANSI.
  1845. //
  1846. if ( isUnicode ) {
  1847. fileNameLength = fileBasic->FileNameLength;
  1848. } else {
  1849. unicodeString.Length = (USHORT)fileBasic->FileNameLength;
  1850. unicodeString.MaximumLength = unicodeString.Length;
  1851. unicodeString.Buffer = fileBasic->FileName;
  1852. fileNameLength = RtlUnicodeStringToOemSize( &unicodeString );
  1853. }
  1854. //
  1855. // Find the new buffer location. It won't be used until the
  1856. // next pass through the loop, but we need to make sure that
  1857. // this entry will fit.
  1858. //
  1859. bufferLocation = bufferLocation +
  1860. FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName ) +
  1861. fileNameLength;
  1862. bufferLocation = (PCHAR)(((ULONG_PTR)bufferLocation + 7) & ~7);
  1863. //
  1864. // Check whether this entry will fit in the output buffer.
  1865. //
  1866. if ( (CLONG)(bufferLocation - Transaction->OutData) >
  1867. Transaction->MaxDataCount ) {
  1868. status = STATUS_BUFFER_OVERFLOW;
  1869. bufferLocation = (PCHAR)findBuffer;
  1870. break;
  1871. }
  1872. //
  1873. // Copy over the information about the entry.
  1874. //
  1875. RtlCopyMemory(
  1876. findBuffer,
  1877. fileBasic,
  1878. FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName )
  1879. );
  1880. findBuffer->NextEntryOffset =
  1881. PTR_DIFF(bufferLocation, findBuffer);
  1882. findBuffer->FileNameLength = fileNameLength;
  1883. if ( isUnicode ) {
  1884. RtlCopyMemory(
  1885. findBuffer->FileName,
  1886. fileBasic->FileName,
  1887. fileBasic->FileNameLength
  1888. );
  1889. } else {
  1890. oemString.MaximumLength = (USHORT)fileNameLength;
  1891. oemString.Buffer = (PSZ)findBuffer->FileName;
  1892. status = RtlUnicodeStringToOemString(
  1893. &oemString,
  1894. &unicodeString,
  1895. FALSE
  1896. );
  1897. ASSERT( NT_SUCCESS(status) );
  1898. }
  1899. //
  1900. // The lastEntry variable holds a pointer to the last file entry
  1901. // that we wrote--an offset to this entry must be returned
  1902. // in the response SMB.
  1903. //
  1904. lastEntry = (PCHAR)findBuffer;
  1905. //
  1906. // The file name and index of the last file returned must be
  1907. // stored in the search block. Save the name pointer, length,
  1908. // and file index here.
  1909. //
  1910. lastFileName.Buffer = fileBasic->FileName;
  1911. lastFileName.Length = (USHORT)fileBasic->FileNameLength;
  1912. lastFileName.MaximumLength = lastFileName.Length;
  1913. lastFileIndex = fileBasic->FileIndex;
  1914. } else if ( InformationLevel == SMB_FIND_FILE_FULL_DIRECTORY_INFO ) {
  1915. FILE_FULL_DIR_INFORMATION UNALIGNED *findBuffer = (PVOID)bufferLocation;
  1916. ULONG fileNameLength;
  1917. //
  1918. // If the client is not speaking Unicode, we need to convert
  1919. // the file name to ANSI.
  1920. //
  1921. if ( isUnicode ) {
  1922. fileNameLength = fileFull->FileNameLength;
  1923. } else {
  1924. unicodeString.Length = (USHORT)fileFull->FileNameLength;
  1925. unicodeString.MaximumLength = unicodeString.Length;
  1926. unicodeString.Buffer = fileFull->FileName;
  1927. fileNameLength = RtlUnicodeStringToOemSize( &unicodeString );
  1928. }
  1929. //
  1930. // Find the new buffer location. It won't be used until the
  1931. // next pass through the loop, but we need to make sure that
  1932. // this entry will fit.
  1933. //
  1934. bufferLocation = bufferLocation +
  1935. FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName)+
  1936. fileNameLength;
  1937. bufferLocation = (PCHAR)(((ULONG_PTR)bufferLocation + 7) & ~7);
  1938. //
  1939. // Check whether this entry will fit in the output buffer.
  1940. //
  1941. if ( (CLONG)(bufferLocation - Transaction->OutData) >
  1942. Transaction->MaxDataCount ) {
  1943. status = STATUS_BUFFER_OVERFLOW;
  1944. bufferLocation = (PCHAR)findBuffer;
  1945. break;
  1946. }
  1947. //
  1948. // Copy over the information about the entry.
  1949. //
  1950. RtlCopyMemory(
  1951. findBuffer,
  1952. fileFull,
  1953. FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName )
  1954. );
  1955. findBuffer->NextEntryOffset =
  1956. PTR_DIFF(bufferLocation, findBuffer);
  1957. findBuffer->FileNameLength = fileNameLength;
  1958. if ( isUnicode ) {
  1959. RtlCopyMemory(
  1960. findBuffer->FileName,
  1961. fileFull->FileName,
  1962. fileFull->FileNameLength
  1963. );
  1964. } else {
  1965. oemString.MaximumLength = (USHORT)fileNameLength;
  1966. oemString.Buffer = (PSZ)findBuffer->FileName;
  1967. status = RtlUnicodeStringToOemString(
  1968. &oemString,
  1969. &unicodeString,
  1970. FALSE
  1971. );
  1972. ASSERT( NT_SUCCESS(status) );
  1973. }
  1974. //
  1975. // The lastEntry variable holds a pointer to the last file entry
  1976. // that we wrote--an offset to this entry must be returned
  1977. // in the response SMB.
  1978. //
  1979. lastEntry = (PCHAR)findBuffer;
  1980. //
  1981. // The file name and index of the last file returned must be
  1982. // stored in the search block. Save the name pointer, length,
  1983. // and file index here.
  1984. //
  1985. lastFileName.Buffer = fileFull->FileName;
  1986. lastFileName.Length = (USHORT)fileFull->FileNameLength;
  1987. lastFileName.MaximumLength = lastFileName.Length;
  1988. lastFileIndex = fileFull->FileIndex;
  1989. } else if ( InformationLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO ) {
  1990. FILE_BOTH_DIR_INFORMATION UNALIGNED *findBuffer = (PVOID)bufferLocation;
  1991. ULONG fileNameLength;
  1992. //
  1993. // If the client is not speaking Unicode, we need to convert
  1994. // the file name to ANSI.
  1995. //
  1996. if ( isUnicode ) {
  1997. fileNameLength = fileBoth->FileNameLength;
  1998. } else {
  1999. unicodeString.Length = (USHORT)fileBoth->FileNameLength;
  2000. unicodeString.MaximumLength = unicodeString.Length;
  2001. unicodeString.Buffer = fileBoth->FileName;
  2002. fileNameLength = RtlUnicodeStringToOemSize( &unicodeString );
  2003. }
  2004. //
  2005. // Find the new buffer location. It won't be used until the
  2006. // next pass through the loop, but we need to make sure that
  2007. // this entry will fit.
  2008. //
  2009. bufferLocation = bufferLocation +
  2010. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,FileName)+
  2011. fileNameLength;
  2012. bufferLocation = (PCHAR)(((ULONG_PTR)bufferLocation + 7) & ~7);
  2013. //
  2014. // Check whether this entry will fit in the output buffer.
  2015. //
  2016. if ( (CLONG)(bufferLocation - Transaction->OutData) >
  2017. Transaction->MaxDataCount ) {
  2018. status = STATUS_BUFFER_OVERFLOW;
  2019. bufferLocation = (PCHAR)findBuffer;
  2020. break;
  2021. }
  2022. //
  2023. // Copy over the information about the entry.
  2024. //
  2025. RtlCopyMemory(
  2026. findBuffer,
  2027. fileBoth,
  2028. FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName )
  2029. );
  2030. findBuffer->NextEntryOffset =
  2031. PTR_DIFF(bufferLocation, findBuffer);
  2032. findBuffer->FileNameLength = fileNameLength;
  2033. if ( isUnicode ) {
  2034. RtlCopyMemory(
  2035. findBuffer->FileName,
  2036. fileBoth->FileName,
  2037. fileBoth->FileNameLength
  2038. );
  2039. } else {
  2040. oemString.MaximumLength = (USHORT)fileNameLength;
  2041. oemString.Buffer = (PSZ)findBuffer->FileName;
  2042. status = RtlUnicodeStringToOemString(
  2043. &oemString,
  2044. &unicodeString,
  2045. FALSE
  2046. );
  2047. ASSERT( NT_SUCCESS(status) );
  2048. }
  2049. //
  2050. // The lastEntry variable holds a pointer to the last file entry
  2051. // that we wrote--an offset to this entry must be returned
  2052. // in the response SMB.
  2053. //
  2054. lastEntry = (PCHAR)findBuffer;
  2055. //
  2056. // The file name and index of the last file returned must be
  2057. // stored in the search block. Save the name pointer, length,
  2058. // and file index here.
  2059. //
  2060. lastFileName.Buffer = fileBoth->FileName;
  2061. lastFileName.Length = (USHORT)fileBoth->FileNameLength;
  2062. lastFileName.MaximumLength = lastFileName.Length;
  2063. lastFileIndex = fileBoth->FileIndex;
  2064. } else if ( InformationLevel == SMB_FIND_FILE_NAMES_INFO ) {
  2065. PFILE_NAMES_INFORMATION findBuffer = (PVOID)bufferLocation;
  2066. ULONG fileNameLength;
  2067. //
  2068. // If the client is not speaking Unicode, we need to convert
  2069. // the file name to ANSI.
  2070. //
  2071. if ( isUnicode ) {
  2072. fileNameLength = fileBasic->FileNameLength;
  2073. } else {
  2074. unicodeString.Length = (USHORT)fileBasic->FileNameLength;
  2075. unicodeString.MaximumLength = unicodeString.Length;
  2076. unicodeString.Buffer = fileBasic->FileName;
  2077. fileNameLength = RtlUnicodeStringToOemSize( &unicodeString );
  2078. }
  2079. //
  2080. // Find the new buffer location. It won't be used until the
  2081. // next pass through the loop, but we need to make sure that
  2082. // this entry will fit.
  2083. //
  2084. bufferLocation = bufferLocation +
  2085. FIELD_OFFSET(FILE_NAMES_INFORMATION,FileName) +
  2086. fileNameLength;
  2087. bufferLocation = (PCHAR)(((ULONG_PTR)bufferLocation + 7) & ~7);
  2088. //
  2089. // Check whether this entry will fit in the output buffer.
  2090. //
  2091. if ( (CLONG)(bufferLocation - Transaction->OutData) >
  2092. Transaction->MaxDataCount ) {
  2093. status = STATUS_BUFFER_OVERFLOW;
  2094. bufferLocation = (PCHAR)findBuffer;
  2095. break;
  2096. }
  2097. //
  2098. // Copy over the information about the entry.
  2099. //
  2100. findBuffer->FileIndex = fileBasic->FileIndex;
  2101. findBuffer->NextEntryOffset =
  2102. PTR_DIFF(bufferLocation, findBuffer);
  2103. findBuffer->FileNameLength = fileNameLength;
  2104. if ( isUnicode ) {
  2105. RtlCopyMemory(
  2106. findBuffer->FileName,
  2107. fileBasic->FileName,
  2108. fileBasic->FileNameLength
  2109. );
  2110. } else {
  2111. oemString.MaximumLength = (USHORT)fileNameLength;
  2112. oemString.Buffer = (PSZ)findBuffer->FileName;
  2113. status = RtlUnicodeStringToOemString(
  2114. &oemString,
  2115. &unicodeString,
  2116. FALSE
  2117. );
  2118. ASSERT( NT_SUCCESS(status) );
  2119. }
  2120. //
  2121. // The lastEntry variable holds a pointer to the last file entry
  2122. // that we wrote--an offset to this entry must be returned
  2123. // in the response SMB.
  2124. //
  2125. lastEntry = (PCHAR)findBuffer;
  2126. //
  2127. // The file name and index of the last file returned must be
  2128. // stored in the search block. Save the name pointer, length,
  2129. // and file index here.
  2130. //
  2131. lastFileName.Buffer = fileBasic->FileName;
  2132. lastFileName.Length = (USHORT)fileBasic->FileNameLength;
  2133. lastFileName.MaximumLength = lastFileName.Length;
  2134. lastFileIndex = fileBasic->FileIndex;
  2135. } else if ( InformationLevel == SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO ) {
  2136. FILE_ID_FULL_DIR_INFORMATION UNALIGNED *findBuffer = (PVOID)bufferLocation;
  2137. ULONG fileNameLength;
  2138. //
  2139. // If the client is not speaking Unicode, we need to convert
  2140. // the file name to ANSI.
  2141. //
  2142. if ( isUnicode ) {
  2143. fileNameLength = fileIdFull->FileNameLength;
  2144. } else {
  2145. unicodeString.Length = (USHORT)fileIdFull->FileNameLength;
  2146. unicodeString.MaximumLength = unicodeString.Length;
  2147. unicodeString.Buffer = fileIdFull->FileName;
  2148. fileNameLength = RtlUnicodeStringToOemSize( &unicodeString );
  2149. }
  2150. //
  2151. // Find the new buffer location. It won't be used until the
  2152. // next pass through the loop, but we need to make sure that
  2153. // this entry will fit.
  2154. //
  2155. bufferLocation = bufferLocation +
  2156. FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, FileName)+
  2157. fileNameLength;
  2158. bufferLocation = (PCHAR)(((ULONG_PTR)bufferLocation + 7) & ~7);
  2159. //
  2160. // Check whether this entry will fit in the output buffer.
  2161. //
  2162. if ( (CLONG)(bufferLocation - Transaction->OutData) >
  2163. Transaction->MaxDataCount ) {
  2164. status = STATUS_BUFFER_OVERFLOW;
  2165. bufferLocation = (PCHAR)findBuffer;
  2166. break;
  2167. }
  2168. //
  2169. // Copy over the information about the entry.
  2170. //
  2171. RtlCopyMemory(
  2172. findBuffer,
  2173. fileIdFull,
  2174. FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION, FileName )
  2175. );
  2176. findBuffer->NextEntryOffset =
  2177. PTR_DIFF(bufferLocation, findBuffer);
  2178. findBuffer->FileNameLength = fileNameLength;
  2179. if ( isUnicode ) {
  2180. RtlCopyMemory(
  2181. findBuffer->FileName,
  2182. fileIdFull->FileName,
  2183. fileIdFull->FileNameLength
  2184. );
  2185. } else {
  2186. oemString.MaximumLength = (USHORT)fileNameLength;
  2187. oemString.Buffer = (PSZ)findBuffer->FileName;
  2188. status = RtlUnicodeStringToOemString(
  2189. &oemString,
  2190. &unicodeString,
  2191. FALSE
  2192. );
  2193. ASSERT( NT_SUCCESS(status) );
  2194. }
  2195. //
  2196. // The lastEntry variable holds a pointer to the last file entry
  2197. // that we wrote--an offset to this entry must be returned
  2198. // in the response SMB.
  2199. //
  2200. lastEntry = (PCHAR)findBuffer;
  2201. //
  2202. // The file name and index of the last file returned must be
  2203. // stored in the search block. Save the name pointer, length,
  2204. // and file index here.
  2205. //
  2206. lastFileName.Buffer = fileIdFull->FileName;
  2207. lastFileName.Length = (USHORT)fileIdFull->FileNameLength;
  2208. lastFileName.MaximumLength = lastFileName.Length;
  2209. lastFileIndex = fileIdFull->FileIndex;
  2210. } else if ( InformationLevel == SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO ) {
  2211. FILE_ID_BOTH_DIR_INFORMATION UNALIGNED *findBuffer = (PVOID)bufferLocation;
  2212. ULONG fileNameLength;
  2213. //
  2214. // If the client is not speaking Unicode, we need to convert
  2215. // the file name to ANSI.
  2216. //
  2217. if ( isUnicode ) {
  2218. fileNameLength = fileIdBoth->FileNameLength;
  2219. } else {
  2220. unicodeString.Length = (USHORT)fileIdBoth->FileNameLength;
  2221. unicodeString.MaximumLength = unicodeString.Length;
  2222. unicodeString.Buffer = fileIdBoth->FileName;
  2223. fileNameLength = RtlUnicodeStringToOemSize( &unicodeString );
  2224. }
  2225. //
  2226. // Find the new buffer location. It won't be used until the
  2227. // next pass through the loop, but we need to make sure that
  2228. // this entry will fit.
  2229. //
  2230. bufferLocation = bufferLocation +
  2231. FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,FileName)+
  2232. fileNameLength;
  2233. bufferLocation = (PCHAR)(((ULONG_PTR)bufferLocation + 7) & ~7);
  2234. //
  2235. // Check whether this entry will fit in the output buffer.
  2236. //
  2237. if ( (CLONG)(bufferLocation - Transaction->OutData) >
  2238. Transaction->MaxDataCount ) {
  2239. status = STATUS_BUFFER_OVERFLOW;
  2240. bufferLocation = (PCHAR)findBuffer;
  2241. break;
  2242. }
  2243. //
  2244. // Copy over the information about the entry.
  2245. //
  2246. RtlCopyMemory(
  2247. findBuffer,
  2248. fileIdBoth,
  2249. FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION, FileName )
  2250. );
  2251. findBuffer->NextEntryOffset =
  2252. PTR_DIFF(bufferLocation, findBuffer);
  2253. findBuffer->FileNameLength = fileNameLength;
  2254. if ( isUnicode ) {
  2255. RtlCopyMemory(
  2256. findBuffer->FileName,
  2257. fileIdBoth->FileName,
  2258. fileIdBoth->FileNameLength
  2259. );
  2260. } else {
  2261. oemString.MaximumLength = (USHORT)fileNameLength;
  2262. oemString.Buffer = (PSZ)findBuffer->FileName;
  2263. status = RtlUnicodeStringToOemString(
  2264. &oemString,
  2265. &unicodeString,
  2266. FALSE
  2267. );
  2268. ASSERT( NT_SUCCESS(status) );
  2269. }
  2270. //
  2271. // The lastEntry variable holds a pointer to the last file entry
  2272. // that we wrote--an offset to this entry must be returned
  2273. // in the response SMB.
  2274. //
  2275. lastEntry = (PCHAR)findBuffer;
  2276. //
  2277. // The file name and index of the last file returned must be
  2278. // stored in the search block. Save the name pointer, length,
  2279. // and file index here.
  2280. //
  2281. lastFileName.Buffer = fileIdBoth->FileName;
  2282. lastFileName.Length = (USHORT)fileIdBoth->FileNameLength;
  2283. lastFileName.MaximumLength = lastFileName.Length;
  2284. lastFileIndex = fileIdBoth->FileIndex;
  2285. }
  2286. count++;
  2287. if ( status == STATUS_OS2_EA_ACCESS_DENIED ) {
  2288. break;
  2289. }
  2290. } while ( count < MaxCount );
  2291. IF_SMB_DEBUG(SEARCH2) {
  2292. SrvPrint0( "Stopped putting entries in buffer. Reason:\n" );
  2293. if ( !NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW ) {
  2294. SrvPrint1( " status = %X\n", status );
  2295. } else if ( count >= MaxCount ) {
  2296. SrvPrint2( " count = %ld, maxCount = %ld\n", count, MaxCount );
  2297. } else {
  2298. SrvPrint3( " buffer location = 0x%p, trans->OD = 0x%p, "
  2299. "trans->MaxOD = 0x%lx\n", bufferLocation,
  2300. Transaction->OutData, Transaction->MaxDataCount );
  2301. }
  2302. }
  2303. //
  2304. // Deallocate the pool used for the NT get EA list if this was the
  2305. // right information level.
  2306. //
  2307. if ( InformationLevel == SMB_INFO_QUERY_EAS_FROM_LIST ) {
  2308. DEALLOCATE_NONPAGED_POOL( ntGetEa );
  2309. }
  2310. //
  2311. // If we have not found any files and an error occurred, or the first
  2312. // file file we found had EAs to large to fit in the buffer, then return
  2313. // the error to the client. If an error occurred and we have found
  2314. // files, return what we have found.
  2315. //
  2316. if ( count == 0 && !NT_SUCCESS(status) ) {
  2317. IF_DEBUG(ERRORS) {
  2318. SrvPrint1( "Find2 processing error; status = %X\n", status );
  2319. }
  2320. SrvSetSmbError( WorkContext, status );
  2321. return status;
  2322. } else if ( count == 1 &&
  2323. ( status == STATUS_OS2_EAS_DIDNT_FIT ||
  2324. status == STATUS_OS2_EA_ACCESS_DENIED ) ) {
  2325. PVOID temp;
  2326. temp = WorkContext->ResponseParameters;
  2327. SrvSetSmbError( WorkContext, status );
  2328. WorkContext->ResponseParameters = temp;
  2329. status = STATUS_SUCCESS;
  2330. } else if ( !NT_SUCCESS(status) && status != STATUS_NO_MORE_FILES ) {
  2331. status = STATUS_SUCCESS;
  2332. }
  2333. //
  2334. // If this is a level for the SMB 4.0 protocol (NT), set the
  2335. // NextEntryOffset field of the last entry to zero.
  2336. //
  2337. if ( InformationLevel == SMB_FIND_FILE_DIRECTORY_INFO ||
  2338. InformationLevel == SMB_FIND_FILE_FULL_DIRECTORY_INFO ||
  2339. InformationLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO ||
  2340. InformationLevel == SMB_FIND_FILE_NAMES_INFO ||
  2341. InformationLevel == SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO ||
  2342. InformationLevel == SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO ) {
  2343. ((PFILE_DIRECTORY_INFORMATION)lastEntry)->NextEntryOffset = 0;
  2344. }
  2345. //
  2346. // At the end of the loop, bufferLocation points to the first location
  2347. // AFTER the last entry we wrote, so it may be used to find the total
  2348. // number of data bytes that we intend to return.
  2349. //
  2350. totalBytesWritten = PTR_DIFF(bufferLocation, Transaction->OutData);
  2351. //
  2352. // Free the buffer that holds the last file name if it was in use,
  2353. // then allocate a new one and store the name and index of the last
  2354. // file returned in the search block so that it can resume the search
  2355. // if the client requests.
  2356. //
  2357. if ( Search->LastFileNameReturned.Buffer != NULL ) {
  2358. FREE_HEAP( Search->LastFileNameReturned.Buffer );
  2359. }
  2360. Search->LastFileNameReturned.Buffer =
  2361. ALLOCATE_HEAP_COLD(
  2362. lastFileName.Length,
  2363. BlockTypeDataBuffer
  2364. );
  2365. if ( Search->LastFileNameReturned.Buffer == NULL ) {
  2366. INTERNAL_ERROR(
  2367. ERROR_LEVEL_EXPECTED,
  2368. "SrvFind2Loop: unable to allocate %d bytes from heap.",
  2369. lastFileName.Length,
  2370. NULL
  2371. );
  2372. return STATUS_INSUFF_SERVER_RESOURCES;
  2373. }
  2374. Search->LastFileNameReturned.Length = lastFileName.Length;
  2375. Search->LastFileNameReturned.MaximumLength = lastFileName.Length;
  2376. RtlCopyMemory(
  2377. Search->LastFileNameReturned.Buffer,
  2378. lastFileName.Buffer,
  2379. lastFileName.Length
  2380. );
  2381. Search->LastFileIndexReturned = lastFileIndex;
  2382. //
  2383. // Put data in the response SMB.
  2384. //
  2385. SmbPutUshort( &Response->SearchCount, count );
  2386. SmbPutUshort(
  2387. &Response->EndOfSearch,
  2388. (USHORT)(status == STATUS_NO_MORE_FILES)
  2389. );
  2390. SmbPutUshort( &Response->EaErrorOffset, eaErrorOffset );
  2391. SmbPutUshort(
  2392. &Response->LastNameOffset,
  2393. (USHORT)(lastEntry - Transaction->OutData)
  2394. );
  2395. Transaction->DataCount = totalBytesWritten;
  2396. return status;
  2397. } // SrvFind2Loop
  2398. VOID
  2399. ConvertFileInfo (
  2400. IN PFILE_DIRECTORY_INFORMATION File,
  2401. IN PWCH FileName,
  2402. IN BOOLEAN Directory,
  2403. IN BOOLEAN ClientIsUnicode,
  2404. OUT PSMB_FIND_BUFFER FindBuffer
  2405. )
  2406. /*++
  2407. Routine Description:
  2408. This routine does the looping necessary to get files and put them
  2409. into an SMB buffer for the Find First2 and Find Next2 transaction
  2410. protocols.
  2411. Arguments:
  2412. File - a pointer to the structure containing the information about
  2413. the file.
  2414. FileName - name of the file.
  2415. Directory - a boolean indicating whether it is a file or directory.
  2416. The existence of this field allows File to point to a
  2417. FILE_FULL_DIR_INFORMATION structure if necessary.
  2418. FileBuffer - where to write the results in OS/2 format.
  2419. Return Value:
  2420. None
  2421. --*/
  2422. {
  2423. SMB_DATE smbDate;
  2424. SMB_TIME smbTime;
  2425. USHORT smbFileAttributes;
  2426. UNICODE_STRING unicodeString;
  2427. PAGED_CODE( );
  2428. //
  2429. // Convert the various times from NT format to SMB format.
  2430. //
  2431. SrvTimeToDosTime( &File->CreationTime, &smbDate, &smbTime );
  2432. SmbPutDate( &FindBuffer->CreationDate, smbDate );
  2433. SmbPutTime( &FindBuffer->CreationTime, smbTime );
  2434. SrvTimeToDosTime( &File->LastAccessTime, &smbDate, &smbTime );
  2435. SmbPutDate( &FindBuffer->LastAccessDate, smbDate );
  2436. SmbPutTime( &FindBuffer->LastAccessTime, smbTime );
  2437. SrvTimeToDosTime( &File->LastWriteTime, &smbDate, &smbTime );
  2438. SmbPutDate( &FindBuffer->LastWriteDate, smbDate );
  2439. SmbPutTime( &FindBuffer->LastWriteTime, smbTime );
  2440. //
  2441. // SMB protocol only allows 32-bit file sizes. Only return the low
  2442. // 32 bits, and too bad if the file is larger.
  2443. //
  2444. SmbPutUlong( &FindBuffer->DataSize, File->EndOfFile.LowPart );
  2445. SmbPutUlong(
  2446. &FindBuffer->AllocationSize,
  2447. File->AllocationSize.LowPart
  2448. );
  2449. SRV_NT_ATTRIBUTES_TO_SMB(
  2450. File->FileAttributes,
  2451. Directory,
  2452. &smbFileAttributes
  2453. );
  2454. SmbPutUshort( &FindBuffer->Attributes, smbFileAttributes );
  2455. if ( ClientIsUnicode ) {
  2456. FindBuffer->FileNameLength = (UCHAR)(File->FileNameLength);
  2457. } else {
  2458. unicodeString.Buffer = FileName;
  2459. unicodeString.Length = (USHORT)File->FileNameLength;
  2460. unicodeString.MaximumLength = unicodeString.Length;
  2461. FindBuffer->FileNameLength =
  2462. (UCHAR)RtlUnicodeStringToOemSize( &unicodeString );
  2463. }
  2464. return;
  2465. } // ConvertFileInfo
  2466. SMB_PROCESSOR_RETURN_TYPE
  2467. SrvSmbFindClose2 (
  2468. SMB_PROCESSOR_PARAMETERS
  2469. )
  2470. /*++
  2471. Routine Description:
  2472. This routine processes the Find Close2 SMB. This SMB is used to
  2473. close a search started by a Find First2 transaction.
  2474. Arguments:
  2475. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  2476. of the parameters to SMB processor routines.
  2477. Return Value:
  2478. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  2479. --*/
  2480. {
  2481. PSEARCH search;
  2482. PSESSION session;
  2483. SRV_DIRECTORY_INFORMATION directoryInformation;
  2484. USHORT sid;
  2485. NTSTATUS status = STATUS_SUCCESS;
  2486. SMB_STATUS SmbStatus = SmbStatusInProgress;
  2487. PREQ_FIND_CLOSE2 request;
  2488. PRESP_FIND_CLOSE2 response;
  2489. PAGED_CODE( );
  2490. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  2491. WorkContext->PreviousSMB = EVENT_TYPE_SMB_FIND_CLOSE2;
  2492. SrvWmiStartContext(WorkContext);
  2493. IF_SMB_DEBUG(SEARCH1) {
  2494. SrvPrint2( "Find Close2 request header at 0x%p, response header at 0x%p\n",
  2495. WorkContext->RequestHeader, WorkContext->ResponseHeader );
  2496. SrvPrint2( "Find Close2 request params at 0x%p, response params%p\n",
  2497. WorkContext->RequestParameters,
  2498. WorkContext->ResponseParameters );
  2499. }
  2500. request = (PREQ_FIND_CLOSE2)WorkContext->RequestParameters;
  2501. response = (PRESP_FIND_CLOSE2)WorkContext->ResponseParameters;
  2502. //
  2503. // If a session block has not already been assigned to the current
  2504. // work context , verify the UID. If verified, the address of the
  2505. // session block corresponding to this user is stored in the WorkContext
  2506. // block and the session block is referenced.
  2507. //
  2508. session = SrvVerifyUid(
  2509. WorkContext,
  2510. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid )
  2511. );
  2512. if ( session == NULL ) {
  2513. IF_DEBUG(SMB_ERRORS) {
  2514. SrvPrint1( "SrvSmbSearch: Invalid UID: 0x%lx\n",
  2515. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid ) );
  2516. }
  2517. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_UID );
  2518. status = STATUS_SMB_BAD_UID;
  2519. SmbStatus = SmbStatusSendResponse;
  2520. }
  2521. //
  2522. // Get the search block corresponding to this SID. SrvVerifySid
  2523. // references the search block.
  2524. //
  2525. sid = SmbGetUshort( &request->Sid );
  2526. search = SrvVerifySid(
  2527. WorkContext,
  2528. SID_INDEX2( sid ),
  2529. SID_SEQUENCE2( sid ),
  2530. &directoryInformation,
  2531. sizeof(SRV_DIRECTORY_INFORMATION)
  2532. );
  2533. if ( search == NULL ) {
  2534. IF_DEBUG(SMB_ERRORS) SrvPrint0( "SrvSmbFindClose2: Invalid SID.\n" );
  2535. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  2536. status = STATUS_INVALID_HANDLE;
  2537. SmbStatus = SmbStatusSendResponse;
  2538. goto Cleanup;
  2539. }
  2540. //
  2541. // Close the query directory and the search, then dereference our
  2542. // pointer to the search block.
  2543. //
  2544. search->DirectoryHandle = NULL;
  2545. SrvCloseSearch( search );
  2546. SrvCloseQueryDirectory( &directoryInformation );
  2547. SrvDereferenceSearch( search );
  2548. //
  2549. // Build the response SMB.
  2550. //
  2551. response->WordCount = 0;
  2552. SmbPutUshort( &response->ByteCount, 0 );
  2553. WorkContext->ResponseParameters = NEXT_LOCATION(
  2554. response,
  2555. RESP_FIND_CLOSE2,
  2556. 0
  2557. );
  2558. SmbStatus = SmbStatusSendResponse;
  2559. Cleanup:
  2560. SrvWmiEndContext(WorkContext);
  2561. return SmbStatus;
  2562. } // SrvSmbFindClose2