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

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