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.

3946 lines
148 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. fileinfo.c
  5. Abstract:
  6. This module implements the mini redirector call down routines pertaining to retrieval/
  7. update of file/directory/volume information.
  8. Author:
  9. Joe Linn [JoeLi] 7-March-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #pragma warning(error:4101) // Unreferenced local variable
  15. RXDT_DefineCategory(DIRCTRL);
  16. #define Dbg (DEBUG_TRACE_DIRCTRL)
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE, __MRxSmbAllocateSideBuffer)
  19. #pragma alloc_text(PAGE, MRxSmbDeallocateSideBuffer)
  20. #pragma alloc_text(PAGE, MRxSmbTranslateLanManFindBuffer)
  21. #pragma alloc_text(PAGE, MrxSmbUnalignedDirEntryCopyTail)
  22. #pragma alloc_text(PAGE, MRxSmbQueryDirectory)
  23. #pragma alloc_text(PAGE, MRxSmbQueryVolumeInformation)
  24. #pragma alloc_text(PAGE, MRxSmbQueryVolumeInformationWithFullBuffer)
  25. #pragma alloc_text(PAGE, MRxSmbSetVolumeInformation)
  26. #pragma alloc_text(PAGE, MRxSmbQueryFileInformation)
  27. #pragma alloc_text(PAGE, MRxSmbSetFileInformation)
  28. #pragma alloc_text(PAGE, MRxSmbQueryNamedPipeInformation)
  29. #pragma alloc_text(PAGE, MRxSmbSetNamedPipeInformation)
  30. #pragma alloc_text(PAGE, MRxSmbSetFileInformationAtCleanup)
  31. #pragma alloc_text(PAGE, MRxSmbIsValidDirectory)
  32. #pragma alloc_text(PAGE, MRxSmbQueryFileInformationFromPseudoOpen)
  33. #endif
  34. NTSTATUS
  35. FsRtlValidateFileInformationBuffer(
  36. ULONG FileInformationClass,
  37. PVOID InformationBuffer,
  38. ULONG InformationBufferLength );
  39. #define MRxSmbForceCoreInfo FALSE
  40. //#define FORCECOREINFO
  41. #if DBG
  42. #ifdef FORCECOREINFO
  43. #undef MRxSmbForceCoreInfo
  44. BOOLEAN MRxSmbForceCoreInfo = TRUE;
  45. #endif
  46. #endif
  47. BOOLEAN MRxSmbBypassDownLevelRename = FALSE;
  48. //BOOLEAN MRxSmbBypassDownLevelRename = TRUE;
  49. ULONG UnalignedDirEntrySideBufferSize = 16384;
  50. //
  51. // Global flag defined in init.c. It is set to true on SERVER or better SKUs.
  52. //
  53. extern BOOLEAN MRxSmbEnableOpDirCache;
  54. //
  55. // All T2Find requests to the remote server request the 32 bit resume key
  56. // so SMB_RFIND_BUFFER2 is used instead of SMB_FIND_BUFFER2.
  57. //
  58. typedef struct _SMB_FIND_BUFFER2_WITH_RESUME {
  59. _ULONG( ResumeKey );
  60. SMB_FIND_BUFFER2;
  61. } SMB_FIND_BUFFER2_WITH_RESUME;
  62. typedef SMB_FIND_BUFFER2_WITH_RESUME SMB_UNALIGNED *PSMB_FIND_BUFFER2_WITH_RESUME;
  63. //CODE.IMPROVEMENT we should have a nondebug version of this sidebuffer stuff
  64. // that basically just does a allocatepool/freepool
  65. LIST_ENTRY MRxSmbSideBuffersList = {NULL,NULL};
  66. ULONG MRxSmbSideBuffersSpinLock = 0;
  67. ULONG MRxSmbSideBuffersCount = 0;
  68. ULONG MRxSmbSideBuffersSerialNumber = 0;
  69. BOOLEAN MRxSmbLoudSideBuffers = FALSE;
  70. typedef struct _SIDE_BUFFER {
  71. ULONG Signature;
  72. LIST_ENTRY ListEntry;
  73. PMRX_FCB Fcb;
  74. PMRX_FOBX Fobx;
  75. PMRX_SMB_FOBX smbFobx;
  76. ULONG SerialNumber;
  77. BYTE Buffer;
  78. } SIDE_BUFFER, *PSIDE_BUFFER;
  79. NTSTATUS
  80. MRxSmbCoreCheckPath(
  81. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  82. );
  83. VOID
  84. __MRxSmbAllocateSideBuffer(
  85. IN OUT PRX_CONTEXT RxContext,
  86. IN OUT PMRX_SMB_FOBX smbFobx,
  87. IN USHORT Setup
  88. #if DBG
  89. ,IN PUNICODE_STRING smbtemplate
  90. #endif
  91. )
  92. {
  93. RxCaptureFcb;RxCaptureFobx;
  94. PSIDE_BUFFER SideBuffer;
  95. ULONG SideBufferSize = UnalignedDirEntrySideBufferSize+sizeof(SIDE_BUFFER);
  96. POOL_TYPE PoolType;
  97. PAGED_CODE();
  98. ASSERT( smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL);
  99. #ifdef _WIN64
  100. //
  101. // NT64: When PagedPool is used here, we get memory corruption on
  102. // some findfirst/findnext operations. Find out why.
  103. //
  104. PoolType = NonPagedPool;
  105. #else
  106. PoolType = PagedPool;
  107. #endif
  108. SideBuffer = (PSIDE_BUFFER)RxAllocatePoolWithTag(
  109. PoolType,
  110. SideBufferSize,
  111. MRXSMB_DIRCTL_POOLTAG);
  112. if (SideBuffer==NULL) {
  113. return;
  114. }
  115. ASSERT( smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL);
  116. SideBuffer->Signature = 'JLBS';
  117. SideBuffer->smbFobx = smbFobx;
  118. SideBuffer->Fobx = capFobx;
  119. SideBuffer->Fcb = capFcb;
  120. smbFobx->Enumeration.UnalignedDirEntrySideBuffer = &SideBuffer->Buffer;
  121. RxLog(("Allocsidebuf %lx fo/f=%lx,%lx\n",
  122. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  123. capFobx,capFcb));
  124. SmbLog(LOG,
  125. MRxSmbAllocateSideBuffer,
  126. LOGPTR(smbFobx->Enumeration.UnalignedDirEntrySideBuffer)
  127. LOGPTR(capFobx)
  128. LOGPTR(capFcb));
  129. smbFobx->Enumeration.SerialNumber = SideBuffer->SerialNumber = InterlockedIncrement(&MRxSmbSideBuffersSerialNumber);
  130. InterlockedIncrement(&MRxSmbSideBuffersCount);
  131. if (MRxSmbSideBuffersList.Flink==NULL) {
  132. InitializeListHead(&MRxSmbSideBuffersList);
  133. }
  134. ExAcquireFastMutex(&MRxSmbSerializationMutex);
  135. InsertTailList(&MRxSmbSideBuffersList,&SideBuffer->ListEntry);
  136. ExReleaseFastMutex(&MRxSmbSerializationMutex);
  137. if (!MRxSmbLoudSideBuffers) return;
  138. KdPrint(("Allocating side buffer %08lx %08lx %08lx %08lx %08lxon <%wZ> %s %wZ\n",
  139. &SideBuffer->Buffer,
  140. MRxSmbSideBuffersCount,
  141. smbFobx,capFobx,capFobx->pSrvOpen,
  142. GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext),
  143. (Setup == TRANS2_FIND_FIRST2)?"First":"Next",
  144. smbtemplate
  145. ));
  146. }
  147. VOID
  148. MRxSmbDeallocateSideBuffer(
  149. IN OUT PRX_CONTEXT RxContext,
  150. IN OUT PMRX_SMB_FOBX smbFobx,
  151. IN PSZ where
  152. )
  153. {
  154. PSIDE_BUFFER SideBuffer;
  155. RxCaptureFcb;RxCaptureFobx;
  156. PAGED_CODE();
  157. if( smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL) return;
  158. SideBuffer = CONTAINING_RECORD(smbFobx->Enumeration.UnalignedDirEntrySideBuffer,SIDE_BUFFER,Buffer);
  159. if (MRxSmbLoudSideBuffers){
  160. DbgPrint("D--------- side buffer %08lx %08lx %08lx %08lx %08lxon <%wZ> %s\n",
  161. &SideBuffer->Buffer,
  162. MRxSmbSideBuffersCount,
  163. smbFobx,capFobx,capFobx->pSrvOpen,
  164. GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext),
  165. where
  166. );
  167. }
  168. ASSERT(SideBuffer->Signature == 'JLBS');
  169. ASSERT(SideBuffer->Fobx == capFobx);
  170. ASSERT(SideBuffer->Fcb == capFcb);
  171. ASSERT(SideBuffer->smbFobx == smbFobx);
  172. ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
  173. ExAcquireFastMutex(&MRxSmbSerializationMutex);
  174. InterlockedDecrement(&MRxSmbSideBuffersCount);
  175. RemoveEntryList(&SideBuffer->ListEntry);
  176. ExReleaseFastMutex(&MRxSmbSerializationMutex);
  177. RxLog(("Deallocsidebuf %lx fo/f=%lx,%lx\n",
  178. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  179. capFobx,capFcb));
  180. SmbLog(LOG,
  181. MRxSmbDeallocateSideBuffer,
  182. LOGPTR(smbFobx->Enumeration.UnalignedDirEntrySideBuffer)
  183. LOGPTR(capFobx)
  184. LOGPTR(capFcb));
  185. RxFreePool(SideBuffer);
  186. smbFobx->Enumeration.UnalignedDirEntrySideBuffer = NULL;
  187. }
  188. #if 0
  189. //
  190. // The NtQueryDirectory response contains one of the following three structures. We use this union
  191. // to reduce the amount of casting needed
  192. //
  193. typedef union _SMB_RFIND_BUFFER_NT {
  194. FILE_NAMES_INFORMATION Names;
  195. FILE_DIRECTORY_INFORMATION Dir;
  196. FILE_FULL_DIR_INFORMATION FullDir;
  197. FILE_BOTH_DIR_INFORMATION BothDir;
  198. } SMB_RFIND_BUFFER_NT;
  199. typedef SMB_RFIND_BUFFER_NT SMB_UNALIGNED *PSMB_RFIND_BUFFER_NT;
  200. #endif
  201. VOID
  202. MRxSmbTranslateLanManFindBuffer(
  203. PRX_CONTEXT RxContext,
  204. PULONG PreviousReturnedEntry,
  205. PBYTE ThisEntryInBuffer
  206. )
  207. {
  208. RxCaptureFcb; RxCaptureFobx;
  209. PSMBCEDB_SERVER_ENTRY pServerEntry;
  210. PSMBCE_SERVER Server;
  211. ULONG FileInformationClass = RxContext->Info.FileInformationClass;
  212. PFILE_FULL_DIR_INFORMATION NtBuffer = (PFILE_FULL_DIR_INFORMATION)PreviousReturnedEntry;
  213. PSMB_FIND_BUFFER2_WITH_RESUME SmbBuffer = (PSMB_FIND_BUFFER2_WITH_RESUME)ThisEntryInBuffer;
  214. SMB_TIME Time;
  215. SMB_DATE Date;
  216. PAGED_CODE();
  217. if (FileInformationClass==FileNamesInformation) { return; }
  218. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  219. //CODE.IMPROVEMENT we should cacheup the server somewhere....getting it everytime is uneficient
  220. Server = &pServerEntry->Server;
  221. SmbMoveTime (&Time, &SmbBuffer->CreationTime);
  222. SmbMoveDate (&Date, &SmbBuffer->CreationDate);
  223. NtBuffer->CreationTime = MRxSmbConvertSmbTimeToTime(Server, Time, Date);
  224. SmbMoveTime (&Time, &SmbBuffer->LastAccessTime);
  225. SmbMoveDate (&Date, &SmbBuffer->LastAccessDate);
  226. NtBuffer->LastAccessTime = MRxSmbConvertSmbTimeToTime(Server, Time, Date);
  227. SmbMoveTime (&Time, &SmbBuffer->LastWriteTime);
  228. SmbMoveDate (&Date, &SmbBuffer->LastWriteDate);
  229. NtBuffer->LastWriteTime = MRxSmbConvertSmbTimeToTime(Server, Time, Date);
  230. NtBuffer->ChangeTime.QuadPart = 0;
  231. NtBuffer->EndOfFile.QuadPart = SmbGetUlong(&SmbBuffer->DataSize);
  232. NtBuffer->AllocationSize.QuadPart = SmbGetUlong(&SmbBuffer->AllocationSize);
  233. NtBuffer->FileAttributes = MRxSmbMapSmbAttributes(SmbBuffer->Attributes);
  234. if ((FileInformationClass==FileFullDirectoryInformation)
  235. || (FileInformationClass==FileBothDirectoryInformation)) {
  236. NtBuffer->EaSize = SmbGetUlong(&SmbBuffer->EaSize);
  237. }
  238. }
  239. NTSTATUS
  240. MrxSmbUnalignedDirEntryCopyTail(
  241. IN OUT PRX_CONTEXT RxContext,
  242. IN FILE_INFORMATION_CLASS FileInformationClass,
  243. IN OUT PVOID pBuffer,
  244. IN OUT PULONG pLengthRemaining,
  245. IN OUT PMRX_SMB_FOBX smbFobx
  246. )
  247. /*++
  248. Routine Description:
  249. This routine copies the data from the side buffer into the users buffer and adjusts the
  250. lengths remaining appropriately. this is called either if the server doesn't do unicode (w95) OR
  251. if the server does not promise to quadalign entries OR if the user's buffer is not quadaligned.
  252. CODE.IMPROVEMENT if the user's buffer isn't quadaligned we could still get by in most cases by reading the data
  253. into the moved up buffer and then just copying the first entry.
  254. this routine can be entered after a T2 finishes or to copy the last entries from a previous T2. in the second case, the
  255. pUnalignedDirEntrySideBuffer ptr will be null and it will go to acquire the correct pointer from the smbFobx.
  256. this routine has the responsibility to free the sidebufferptr when it is exhausted.
  257. //CODE.IMPROVEMENT.ASHAMED (joe) i apologize for this code.....it is so ugly....but it does
  258. handle nt, win95/samba, and lanman in the same routine. the transformation is nontrivial even
  259. tho it is straightforward to implement.
  260. Arguments:
  261. RxContext - the RDBSS context
  262. Return Value:
  263. RXSTATUS - The return status for the operation
  264. --*/
  265. {
  266. NTSTATUS Status = STATUS_SUCCESS;
  267. RxCaptureFcb;
  268. ULONG i,NameSizeInUnicode;
  269. LONG LocalLengthRemaining; //signed arithmetic makes it easier
  270. PULONG PreviousReturnedEntry = NULL;
  271. ULONG FileNameLengthOffset = smbFobx->Enumeration.FileNameLengthOffset;
  272. ULONG FileNameOffset = smbFobx->Enumeration.FileNameOffset;
  273. PBYTE UnalignedDirEntrySideBuffer = smbFobx->Enumeration.UnalignedDirEntrySideBuffer;
  274. BOOLEAN IsUnicode = smbFobx->Enumeration.IsUnicode;
  275. BOOLEAN IsNonNtT2Find = smbFobx->Enumeration.IsNonNtT2Find;
  276. PMRX_SMB_DIRECTORY_RESUME_INFO ResumeInfo = smbFobx->Enumeration.ResumeInfo;
  277. ULONG FilesReturned = smbFobx->Enumeration.FilesReturned;
  278. ULONG EntryOffset = smbFobx->Enumeration.EntryOffset;
  279. ULONG ReturnedEntryOffset = 0;// = smbFobx->Enumeration.ReturnedEntryOffset; //CODE.IMPROVEMENT get rid of this variable.....
  280. BOOLEAN EndOfSearchReached = smbFobx->Enumeration.EndOfSearchReached;
  281. ULONG TotalDataBytesReturned = smbFobx->Enumeration.TotalDataBytesReturned;
  282. BOOLEAN FilterFailure = FALSE;
  283. PAGED_CODE();
  284. LocalLengthRemaining = (LONG)(*pLengthRemaining);
  285. //
  286. // keep looping until we've filled in all we can or there're no more entries
  287. for (i=ReturnedEntryOffset=0;;) {
  288. ULONG FileNameLength,ThisEntrySize; PCHAR FileNameBuffer;
  289. UNICODE_STRING ReturnedFileName;
  290. OEM_STRING FileName;
  291. NTSTATUS StringStatus;
  292. BOOLEAN TwoExtraBytes = TRUE;
  293. ULONG resumekey,NextEntryOffsetinBuffer;
  294. PULONG PreviousPreviousReturnedEntry = NULL;
  295. PBYTE ThisEntryInBuffer = UnalignedDirEntrySideBuffer+EntryOffset;
  296. //
  297. // don't EVER let yourself get past the data returned...servers return funny stuff.......
  298. if (EntryOffset>=TotalDataBytesReturned){
  299. FilterFailure = TRUE;
  300. FilesReturned = i; //we're done with this buffer........
  301. break;
  302. }
  303. //
  304. // find the name, the length, and the resume key based on whether it is a NT-T2find or a nonNT
  305. if (!IsNonNtT2Find) {
  306. //
  307. // NT, we use the offsets that we stored earlier.........
  308. FileNameLength = SmbGetUlong(ThisEntryInBuffer+FileNameLengthOffset);
  309. FileNameBuffer = ThisEntryInBuffer+FileNameOffset;
  310. resumekey = SmbGetUlong(ThisEntryInBuffer
  311. +FIELD_OFFSET(FILE_FULL_DIR_INFORMATION,FileIndex));
  312. NextEntryOffsetinBuffer = SmbGetUlong(ThisEntryInBuffer);
  313. } else {
  314. //
  315. // for lanman, we always ask for stuff using the SMB_FIND_BUFFER2 to which
  316. // we have prepended a resume key. so, the name is always at a fixed offset.
  317. // Also, for nonNT we have read all the files and must filter out correctly; we
  318. // save where we are in the user's buffer so that we can roll back.
  319. FileNameLength = *(ThisEntryInBuffer
  320. +FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,FileNameLength));
  321. FileNameBuffer = ThisEntryInBuffer
  322. +FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,FileName[0]);
  323. resumekey = SmbGetUlong(ThisEntryInBuffer+
  324. +FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,ResumeKey));
  325. NextEntryOffsetinBuffer = FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,FileName[0])
  326. + FileNameLength + 1; //the +1 is for the null..we could have said Filename{1]
  327. PreviousPreviousReturnedEntry = PreviousReturnedEntry; //save this for rollback on filterfail
  328. }
  329. // some servers lie about how many entries were returned and/or send partial entries
  330. // dont let them trick us..........
  331. if (EntryOffset+NextEntryOffsetinBuffer>TotalDataBytesReturned){
  332. FilterFailure = TRUE;
  333. FilesReturned = i; //we're done with this buffer........
  334. break;
  335. }
  336. if (FileNameLength+(ULONG)(FileNameBuffer-UnalignedDirEntrySideBuffer) > UnalignedDirEntrySideBufferSize) {
  337. //
  338. // Source buffer overrun.
  339. //
  340. Status = STATUS_INVALID_NETWORK_RESPONSE;
  341. break;
  342. }
  343. FileName.Buffer = FileNameBuffer;
  344. FileName.Length = (USHORT)FileNameLength;
  345. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: EO,REO=%08lx,%08lx\n",
  346. EntryOffset,ReturnedEntryOffset));
  347. //check to see if this entry will fit
  348. if (IsUnicode) {
  349. NameSizeInUnicode = FileNameLength;
  350. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: length=%08lx/%08lx, name = %wZ\n",
  351. FileNameLength,NameSizeInUnicode,&FileName));
  352. } else {
  353. //CODE.IMPROVEMENT should i use RtlOemStringToUnicodeSize???
  354. NameSizeInUnicode = RtlxOemStringToUnicodeSize(&FileName)-sizeof(WCHAR);
  355. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: length=%08lx/%08lx, name = %.*s\n",
  356. FileNameLength,NameSizeInUnicode,FileNameLength,FileNameBuffer));
  357. }
  358. //
  359. // now that we know the size of the name and its location, we need to copy it
  360. // to the user's buffer
  361. ThisEntrySize = FileNameOffset+NameSizeInUnicode;
  362. if ((LONG)ThisEntrySize > LocalLengthRemaining) {
  363. break;
  364. }
  365. if (((LONG)ThisEntrySize)>LocalLengthRemaining-(LONG)sizeof(WCHAR)) {
  366. TwoExtraBytes = FALSE;
  367. }
  368. ThisEntrySize = LongAlign(ThisEntrySize);
  369. PreviousReturnedEntry = (PULONG)(((PBYTE)pBuffer)+ReturnedEntryOffset);
  370. //
  371. // next we compute where the next entry after this one will start. the definition is
  372. // that it must be 8-byte aligned. we know already that it's 4byte aligned.
  373. if (!IsPtrQuadAligned((PCHAR)(PreviousReturnedEntry)+ThisEntrySize) ){
  374. ThisEntrySize += sizeof(ULONG);
  375. }
  376. if (i!=0) {
  377. ASSERT(IsPtrQuadAligned(PreviousReturnedEntry));
  378. }
  379. //
  380. // if this is an NT find, we can copy in the data now. for lanman, we
  381. // copy in the data later........
  382. if (!IsNonNtT2Find) {
  383. //copy everything in the entry up to but not including the name info
  384. RtlCopyMemory(PreviousReturnedEntry,UnalignedDirEntrySideBuffer+EntryOffset,FileNameOffset);
  385. } else {
  386. // clear out all fields i cannot support.
  387. RtlZeroMemory(PreviousReturnedEntry,FileNameOffset);
  388. }
  389. // store the length of this entry and the size of the name...if this is the last
  390. // entry returned, then the offset field will be cleared later
  391. *PreviousReturnedEntry = ThisEntrySize;
  392. *((PULONG)(((PBYTE)PreviousReturnedEntry)+FileNameLengthOffset)) = NameSizeInUnicode;
  393. //copy in the name .........this is made difficult by the oem-->unicode routine that
  394. // requires space for a NULL! CODE.IMPROVEMENT maybe we should have own routine that
  395. // doesn't require space for the null
  396. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: REO/buf/pentry=%08lx/%08lx/%08lx\n",
  397. pBuffer,ReturnedEntryOffset,PreviousReturnedEntry));
  398. ReturnedFileName.Buffer = (PWCH)(((PBYTE)PreviousReturnedEntry)+FileNameOffset);
  399. if (!IsUnicode) {
  400. if (TwoExtraBytes) {
  401. ReturnedFileName.MaximumLength = sizeof(WCHAR)+(USHORT)NameSizeInUnicode;
  402. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: filenamebuf,length=%08lx/%08lx\n",
  403. ReturnedFileName.Buffer,ReturnedFileName.MaximumLength));
  404. StringStatus = RtlOemStringToUnicodeString(&ReturnedFileName,&FileName,FALSE); //false means don;t allocate
  405. } else {
  406. ReturnedFileName.MaximumLength = (USHORT)NameSizeInUnicode;
  407. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: filenamebuf,length=%08lx/%08lx\n",
  408. ReturnedFileName.Buffer,ReturnedFileName.MaximumLength));
  409. StringStatus = RtlOemStringToCountedUnicodeString(&ReturnedFileName,&FileName,FALSE); //false means don;t allocate
  410. }
  411. if (StringStatus != RX_MAP_STATUS(SUCCESS)){
  412. ReturnedFileName.Length = 0;
  413. }
  414. // Win95 returns the shortname in ascii....spread it out
  415. if ((FileInformationClass == FileBothDirectoryInformation) && !IsNonNtT2Find) {
  416. PFILE_BOTH_DIR_INFORMATION BothInfo = (PFILE_BOTH_DIR_INFORMATION)PreviousReturnedEntry;
  417. OEM_STRING oemName;
  418. UNICODE_STRING UnicodeName;
  419. WCHAR wcharBuffer[12];
  420. oemName.Buffer = (PBYTE)(&BothInfo->ShortName[0]);
  421. oemName.Length =
  422. oemName.MaximumLength = BothInfo->ShortNameLength;
  423. UnicodeName.Buffer = wcharBuffer;
  424. UnicodeName.Length = 0;
  425. UnicodeName.MaximumLength = sizeof(wcharBuffer);
  426. StringStatus = RtlOemStringToUnicodeString(&UnicodeName, &oemName, FALSE);
  427. if (StringStatus == RX_MAP_STATUS(SUCCESS)) {
  428. BothInfo->ShortNameLength = (CHAR)UnicodeName.Length;
  429. RtlCopyMemory(BothInfo->ShortName, UnicodeName.Buffer, UnicodeName.Length);
  430. } else {
  431. BothInfo->ShortNameLength = 0;
  432. }
  433. IF_DEBUG {
  434. UNICODE_STRING LastName;
  435. LastName.Buffer = (PWCHAR)wcharBuffer;
  436. LastName.Length = (USHORT)UnicodeName.Length;
  437. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: unicodeshortnamename = %wZ\n", &LastName));
  438. }
  439. }
  440. } else {
  441. //here, it's already unicode.....just copy the bytes
  442. RtlCopyMemory(ReturnedFileName.Buffer,FileName.Buffer,FileName.Length);
  443. ReturnedFileName.Length = FileName.Length;
  444. }
  445. IF_DEBUG {
  446. UNICODE_STRING LastName;
  447. LastName.Buffer = ReturnedFileName.Buffer;
  448. LastName.Length = (USHORT)NameSizeInUnicode;
  449. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: unicodename = %wZ\n", &LastName));
  450. }
  451. //now...setup to resume based on this entry
  452. if (ResumeInfo != NULL) {
  453. PREQ_FIND_NEXT2 pFindNext2Request = &ResumeInfo->FindNext2_Request;
  454. //ULONG resumekey = ((PFILE_FULL_DIR_INFORMATION)PreviousReturnedEntry)->FileIndex;
  455. //CODE.IMPROVEMENT put asserts here that all of the levels have the fileindex in the same spot
  456. // for goodness sake.....use a macro. actually, this code should go up above
  457. // where (a) all the types are visible and (b) it will execute on the NT path as well
  458. if (FileNameLength > MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)) {
  459. Status = STATUS_INVALID_NETWORK_RESPONSE;
  460. break;
  461. }
  462. pFindNext2Request->ResumeKey = resumekey;
  463. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: resumekey = %08lx\n", resumekey));
  464. RtlCopyMemory(&pFindNext2Request->Buffer[0],FileNameBuffer,FileNameLength);
  465. //buffer is a UCHAR...not WCHAR
  466. if (IsUnicode) {
  467. // In the case of UNICODE strings an additional NULL is required ( WCHAR NULL )
  468. pFindNext2Request->Buffer[FileNameLength] = 0; //nullterminated
  469. pFindNext2Request->Buffer[FileNameLength + 1] = 0; //nullterminated
  470. smbFobx->Enumeration.ResumeInfo->ParametersLength
  471. = (USHORT)(&pFindNext2Request->Buffer[FileNameLength+2] - (PBYTE)pFindNext2Request);
  472. } else {
  473. pFindNext2Request->Buffer[FileNameLength] = 0; //nullterminated
  474. smbFobx->Enumeration.ResumeInfo->ParametersLength
  475. = (USHORT)(&pFindNext2Request->Buffer[FileNameLength+1] - (PBYTE)pFindNext2Request);
  476. }
  477. }
  478. //ASSERT(!IsNonNtT2Find);
  479. //at this point, we have copied the name and the resume key. BUT, for nonnt we have to
  480. //filter the names so we still may have to roll back
  481. if (!IsNonNtT2Find) {
  482. //no need for filtering on NT
  483. FilterFailure = FALSE;
  484. } else {
  485. // here we have to filter out based on the template
  486. RxCaptureFobx; //do this here so it's not on the NT path
  487. FilterFailure = FALSE;
  488. if (smbFobx->Enumeration.WildCardsFound ) {
  489. try
  490. {
  491. FilterFailure = !FsRtlIsNameInExpression(
  492. &capFobx->UnicodeQueryTemplate,
  493. &ReturnedFileName,
  494. TRUE,
  495. NULL );
  496. }
  497. except(EXCEPTION_EXECUTE_HANDLER)
  498. {
  499. FilterFailure = TRUE;
  500. }
  501. } else {
  502. FilterFailure = !RtlEqualUnicodeString(
  503. &capFobx->UnicodeQueryTemplate,
  504. &ReturnedFileName,
  505. TRUE ); //case-insensitive
  506. }
  507. if (!FilterFailure) {
  508. if (((LONG)ThisEntrySize)>LocalLengthRemaining) {
  509. break;
  510. }
  511. // since we didn't copy the data before, we have to copy it now...
  512. MRxSmbTranslateLanManFindBuffer(RxContext,PreviousReturnedEntry,ThisEntryInBuffer);
  513. } else {
  514. PreviousReturnedEntry = PreviousPreviousReturnedEntry; //rollback on filterfail
  515. }
  516. }
  517. if (!FilterFailure) {
  518. // filtering succeeded..... adjust returned sizes and counts
  519. LocalLengthRemaining -= ThisEntrySize;
  520. i++;
  521. ReturnedEntryOffset += ThisEntrySize;
  522. } else {
  523. FilesReturned--; //we exit the loop if i passes filesreturned
  524. }
  525. //
  526. // complicated test to keep going.......
  527. //EntryOffset += SmbGetUlong(UnalignedDirEntrySideBuffer+EntryOffset);
  528. EntryOffset += NextEntryOffsetinBuffer;
  529. if ((i>=FilesReturned)
  530. ||(LocalLengthRemaining<0)
  531. || (RxContext->QueryDirectory.ReturnSingleEntry&&(i>0)) ) {
  532. //CODE.IMPROVEMENT we could be more agressive than 0 in the compare against
  533. // locallengthremaining....it's actually whatever
  534. // the minimum recordsize is..........probably FileNameOffset
  535. break;
  536. }
  537. }
  538. if (Status == STATUS_SUCCESS) {
  539. //
  540. // if we are not returning even one entry, either we didn't have space for even one entry
  541. // OR we're filtering and no guys passed the filter. return an appropriate error in each case
  542. if (i==0) {
  543. Status = FilterFailure?STATUS_MORE_PROCESSING_REQUIRED:STATUS_BUFFER_OVERFLOW;
  544. } else {
  545. *PreviousReturnedEntry = 0; // this clears the "next" link for the last returned entry
  546. }
  547. //
  548. // send back the right size
  549. if (LocalLengthRemaining <= 0) {
  550. *pLengthRemaining = 0;
  551. } else {
  552. *pLengthRemaining = (ULONG)LocalLengthRemaining;
  553. }
  554. //
  555. // if we're finished with the sidebuffer, deallocate it.
  556. // otherwise setup to resume........
  557. if (i>=FilesReturned) {
  558. RxLog(("sidebufdealloc %lx %lx\n",RxContext,smbFobx));
  559. SmbLog(LOG,
  560. MrxSmbUnalignedDirEntryCopyTail,
  561. LOGPTR(RxContext)
  562. LOGPTR(smbFobx));
  563. MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"Tail");
  564. if (EndOfSearchReached) {
  565. //smbFobx->Enumeration.Flags &= ~SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN;
  566. //we will close the search handle when the user's handle closes
  567. smbFobx->Enumeration.ErrorStatus = STATUS_NO_MORE_FILES;
  568. }
  569. } else {
  570. //set up to resume here
  571. ASSERT(smbFobx->Enumeration.UnalignedDirEntrySideBuffer == UnalignedDirEntrySideBuffer);
  572. smbFobx->Enumeration.EntryOffset = EntryOffset;
  573. smbFobx->Enumeration.FilesReturned = FilesReturned - i;
  574. }
  575. } else {
  576. smbFobx->Enumeration.ErrorStatus = Status;
  577. RxLog(("sidebufdealloc %lx %lx\n",RxContext,smbFobx));
  578. SmbLog(LOG,
  579. MrxSmbUnalignedDirEntryCopyTail,
  580. LOGPTR(RxContext)
  581. LOGPTR(smbFobx));
  582. MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"Tail");
  583. }
  584. return(Status);
  585. }
  586. NTSTATUS
  587. MRxSmbQueryDirectoryFromCache (
  588. PRX_CONTEXT RxContext,
  589. PSMBPSE_FILEINFO_BUNDLE FileInfo
  590. )
  591. /*++
  592. Routine Description:
  593. This routine copies the data from the file information cache into the users buffer and adjusts the
  594. lengths remaining appropriately. This will avoid to send the FindFirst and FindClose requests to
  595. the server.
  596. Arguments:
  597. RxContext - the RDBSS context
  598. FileInfo - the basic and standard file information
  599. Return Value:
  600. NTSTATUS - The return status for the operation
  601. Notes:
  602. --*/
  603. {
  604. NTSTATUS Status = STATUS_SUCCESS;
  605. RxCaptureFcb;
  606. RxCaptureFobx;
  607. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  608. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  609. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  610. PBYTE pBuffer = RxContext->Info.Buffer;
  611. PULONG pLengthRemaining = &RxContext->Info.LengthRemaining;
  612. FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass;
  613. PUNICODE_STRING FileName = &capFobx->UnicodeQueryTemplate;
  614. ULONG SpaceNeeded = smbFobx->Enumeration.FileNameOffset+FileName->Length;
  615. RxDbgTrace(+1, Dbg,
  616. ("MRxSmbQueryDirectoryFromCache entry(%08lx)...%08lx %08lx %08lx %08lx\n",
  617. RxContext,
  618. FileInformationClass,pBuffer,*pLengthRemaining,
  619. smbFobx->Enumeration.ResumeInfo ));
  620. if (SpaceNeeded > *pLengthRemaining) {
  621. Status = STATUS_BUFFER_OVERFLOW;
  622. goto FINALLY;
  623. }
  624. RtlZeroMemory(pBuffer,smbFobx->Enumeration.FileNameOffset);
  625. switch (FileInformationClass) {
  626. case FileNamesInformation:
  627. Status = STATUS_MORE_PROCESSING_REQUIRED;
  628. goto FINALLY;
  629. break;
  630. case FileBothDirectoryInformation:
  631. if (!FlagOn( NetRoot->Flags,NETROOT_FLAG_UNIQUE_FILE_NAME )) {
  632. Status = STATUS_MORE_PROCESSING_REQUIRED;
  633. goto FINALLY;
  634. }
  635. // lack of break is intentional
  636. case FileDirectoryInformation:
  637. case FileFullDirectoryInformation: {
  638. PFILE_DIRECTORY_INFORMATION pThisBuffer = (PFILE_DIRECTORY_INFORMATION)pBuffer;
  639. pThisBuffer->FileAttributes = FileInfo->Basic.FileAttributes;
  640. pThisBuffer->CreationTime = FileInfo->Basic.CreationTime;
  641. pThisBuffer->LastAccessTime = FileInfo->Basic.LastAccessTime;
  642. pThisBuffer->LastWriteTime = FileInfo->Basic.LastWriteTime;
  643. pThisBuffer->EndOfFile = FileInfo->Standard.EndOfFile;
  644. pThisBuffer->AllocationSize = FileInfo->Standard.AllocationSize;
  645. break;
  646. }
  647. default:
  648. RxDbgTrace( 0, Dbg, ("MRxSmbCoreFileSearch: Invalid FS information class\n"));
  649. ASSERT(!"this can't happen");
  650. Status = STATUS_INVALID_PARAMETER;
  651. goto FINALLY;
  652. }
  653. RtlCopyMemory(pBuffer+smbFobx->Enumeration.FileNameOffset,
  654. FileName->Buffer,
  655. FileName->Length);
  656. *((PULONG)(pBuffer+smbFobx->Enumeration.FileNameLengthOffset)) = FileName->Length;
  657. *pLengthRemaining -= SpaceNeeded;
  658. FINALLY:
  659. RxDbgTrace(-1, Dbg, ("MRxSmbQueryDirectoryFromCache exit-> %08lx %08lx\n", RxContext, Status ));
  660. return Status;
  661. }
  662. ULONG MRxSmbWin95Retries = 0;
  663. NTSTATUS
  664. MRxSmbQueryDirectory(
  665. IN OUT PRX_CONTEXT RxContext
  666. )
  667. /*++
  668. Routine Description:
  669. This routine does a directory query. Only the NT-->NT path is implemented.
  670. //CODE.IMPROVEMENT.ASHAMED this code is UGLY and has no reasonable modularity............
  671. Arguments:
  672. RxContext - the RDBSS context
  673. Return Value:
  674. RXSTATUS - The return status for the operation
  675. --*/
  676. {
  677. NTSTATUS Status;
  678. RxCaptureFcb;
  679. RxCaptureFobx;
  680. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  681. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  682. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  683. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  684. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = SmbCeGetAssociatedVNetRootContext(SrvOpen->pVNetRoot);
  685. PSMBCE_SESSION pSession = &pVNetRootContext->pSessionEntry->Session;
  686. FILE_INFORMATION_CLASS FileInformationClass;
  687. PVOID Buffer;
  688. PULONG pLengthRemaining;
  689. ULONG BufferLength;
  690. USHORT SmbFileInfoLevel;
  691. ULONG FilesReturned;
  692. ULONG RetryCount = 0;
  693. USHORT Setup;
  694. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  695. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  696. PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
  697. //REQ_FIND_NEXT2 FindNext2Request;
  698. PREQ_FIND_FIRST2 pFindFirst2Request = NULL;
  699. PBYTE SendParamsBuffer,ReceiveParamsBuffer;
  700. PBYTE UnalignedDirEntrySideBuffer;
  701. BOOLEAN DirEntriesAreUaligned = FALSE;
  702. BOOLEAN IsUnicode = TRUE;
  703. BOOLEAN IsNonNtT2Find;
  704. USHORT SearchFlags = SMB_FIND_CLOSE_AT_EOS|SMB_FIND_RETURN_RESUME_KEYS;
  705. USHORT NumEntries;
  706. ULONG SendParamsBufferLength,ReceiveParamsBufferLength;
  707. //CODE.IMPROVEMENT this should be overallocated and unioned
  708. RESP_FIND_FIRST2 FindFirst2Response;
  709. SMBPSE_FILEINFO_BUNDLE FileInfo;
  710. UNICODE_STRING FileName = {0,0,NULL};
  711. BOOLEAN CanCacheDir = FALSE;
  712. struct {
  713. RESP_FIND_NEXT2 FindNext2Response;
  714. ULONG Pad; //nonnt needs this
  715. } XX;
  716. #if DBG
  717. UNICODE_STRING smbtemplate = {0,0,NULL};
  718. #endif
  719. PAGED_CODE();
  720. TURN_BACK_ASYNCHRONOUS_OPERATIONS();
  721. FileInformationClass = RxContext->Info.FileInformationClass;
  722. Buffer = RxContext->Info.Buffer;
  723. pLengthRemaining = &RxContext->Info.LengthRemaining;
  724. RxDbgTrace(+1, Dbg, ("MRxSmbQueryDirectory: directory=<%wZ>\n",
  725. GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext)
  726. ));
  727. #define __GET_NAME_PARAMS_FOR_TYPE(___type___) { \
  728. smbFobx->Enumeration.FileNameOffset = (USHORT)FIELD_OFFSET(___type___,FileName[0]); \
  729. smbFobx->Enumeration.FileNameLengthOffset = (USHORT)FIELD_OFFSET(___type___,FileNameLength); \
  730. }
  731. switch (FileInformationClass) {
  732. case FileDirectoryInformation:
  733. SmbFileInfoLevel = SMB_FIND_FILE_DIRECTORY_INFO;
  734. __GET_NAME_PARAMS_FOR_TYPE(FILE_DIRECTORY_INFORMATION);
  735. break;
  736. case FileFullDirectoryInformation:
  737. SmbFileInfoLevel = SMB_FIND_FILE_FULL_DIRECTORY_INFO;
  738. __GET_NAME_PARAMS_FOR_TYPE(FILE_FULL_DIR_INFORMATION);
  739. break;
  740. case FileBothDirectoryInformation:
  741. SmbFileInfoLevel = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
  742. __GET_NAME_PARAMS_FOR_TYPE(FILE_BOTH_DIR_INFORMATION);
  743. break;
  744. case FileNamesInformation:
  745. SmbFileInfoLevel = SMB_FIND_FILE_NAMES_INFO;
  746. __GET_NAME_PARAMS_FOR_TYPE(FILE_NAMES_INFORMATION);
  747. break;
  748. case FileIdFullDirectoryInformation:
  749. SmbFileInfoLevel = SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO;
  750. __GET_NAME_PARAMS_FOR_TYPE(FILE_ID_FULL_DIR_INFORMATION);
  751. break;
  752. case FileIdBothDirectoryInformation:
  753. SmbFileInfoLevel = SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO;
  754. __GET_NAME_PARAMS_FOR_TYPE(FILE_ID_BOTH_DIR_INFORMATION);
  755. break;
  756. default:
  757. RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: Invalid FS information class\n"));
  758. Status = STATUS_INVALID_PARAMETER;
  759. goto FINALLY;
  760. }
  761. IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC{
  762. NOTHING;
  763. } else {
  764. if (CscPerformOperationInDisconnectedMode(RxContext)){
  765. NTSTATUS DirCtrlNtStatus;
  766. DirCtrlNtStatus = MRxSmbDCscQueryDirectory(RxContext);
  767. if (DirCtrlNtStatus != STATUS_MORE_PROCESSING_REQUIRED) {
  768. RxDbgTrace(0, Dbg,
  769. ("MRxSmbQueryVolumeInfo returningDCON with status=%08lx\n",
  770. DirCtrlNtStatus ));
  771. Status = DirCtrlNtStatus;
  772. goto FINALLY;
  773. } else {
  774. NOTHING;
  775. }
  776. }
  777. }
  778. #if DBG
  779. if (MRxSmbLoudSideBuffers) {
  780. SetFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_LOUD_FINALIZE);
  781. }
  782. #endif
  783. if( RxContext->QueryDirectory.RestartScan )
  784. {
  785. ClearFlag( smbFobx->Enumeration.Flags, SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST );
  786. MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"Restart");
  787. }
  788. if (FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST) &&
  789. (FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_NO_WILDCARD) ||
  790. FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE))) {
  791. // if the FindFirst has been satisfied basied on local file information cache,
  792. // we should fail the FindNext since the file has been found with the exact name.
  793. RxDbgTrace( 0, Dbg, ("Failing FNext RD_FROM_CACHE :%wZ:%wZ: WLD %d RDC %d\n", GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext), &capFobx->UnicodeQueryTemplate, FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_NO_WILDCARD), FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE)));
  794. SmbLog(LOG,MRxSmbFailingFNext,
  795. LOGUSTR(*GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext))
  796. LOGUSTR(capFobx->UnicodeQueryTemplate));
  797. //LOG???(FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_NO_WILDCARD))
  798. //LOG???(FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE)));
  799. Status = RX_MAP_STATUS(NO_MORE_FILES);
  800. smbFobx->Enumeration.EndOfSearchReached = TRUE;
  801. smbFobx->Enumeration.ErrorStatus = RX_MAP_STATUS(NO_MORE_FILES);
  802. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE);
  803. goto FINALLY;
  804. }
  805. if (capFobx->UnicodeQueryTemplate.Length != 0 &&
  806. !FsRtlDoesNameContainWildCards(&capFobx->UnicodeQueryTemplate) &&
  807. !FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST)) {
  808. // if it is the FindFirst, we try to find the file on local file information cache.
  809. PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  810. PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate;
  811. UNICODE_STRING TargetName = {0,0,NULL};
  812. TargetName.Length = DirectoryName->Length + Template->Length + sizeof(WCHAR);
  813. TargetName.MaximumLength = TargetName.Length;
  814. TargetName.Buffer = (PWCHAR)RxAllocatePoolWithTag(PagedPool,
  815. TargetName.Length,
  816. MRXSMB_DIRCTL_POOLTAG);
  817. if (TargetName.Buffer == NULL) {
  818. Status = STATUS_INSUFFICIENT_RESOURCES;
  819. goto FINALLY;
  820. }
  821. RtlCopyMemory(TargetName.Buffer,
  822. DirectoryName->Buffer,
  823. DirectoryName->Length);
  824. TargetName.Buffer[DirectoryName->Length/sizeof(WCHAR)] = L'\\';
  825. RtlCopyMemory(&TargetName.Buffer[DirectoryName->Length/sizeof(WCHAR)+1],
  826. Template->Buffer,
  827. Template->Length);
  828. if (MRxSmbIsFileInfoCacheFound(RxContext,
  829. &FileInfo,
  830. &Status,
  831. &TargetName)) {
  832. // if the file has been found on the local cache, we satisfy the FindFirst
  833. // basied on the cache.
  834. if (Status == STATUS_SUCCESS) {
  835. Status = MRxSmbQueryDirectoryFromCache(RxContext, &FileInfo);
  836. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  837. SetFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE);
  838. SetFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST);
  839. RxFreePool(TargetName.Buffer);
  840. goto FINALLY;
  841. }
  842. }
  843. }
  844. RxFreePool(TargetName.Buffer);
  845. SearchFlags |= SMB_FIND_CLOSE_AFTER_REQUEST;
  846. SetFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_NO_WILDCARD);
  847. }
  848. if ((!FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST)) &&
  849. (FileInformationClass == FileBothDirectoryInformation) &&
  850. (pServerEntry->Server.DialectFlags&(DF_NT_SMBS|DF_W95|DF_LANMAN20)) &&
  851. (pServerEntry->Server.Dialect==NTLANMAN_DIALECT) &&
  852. (pServerEntry->Server. AliasedServers == 0) &&
  853. (smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL) &&
  854. (FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) &&
  855. (!FlagOn(capFobx->Flags,FOBX_FLAG_BACKUP_INTENT)) &&
  856. (!FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION)) &&
  857. (SearchFlags & SMB_FIND_CLOSE_AT_EOS) &&
  858. (*pLengthRemaining <= NAME_CACHE_PARTIAL_DIR_BUFFER_SIZE) &&
  859. (BooleanFlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE)) &&
  860. (GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext)->Length > 0) &&
  861. ((&capFobx->UnicodeQueryTemplate)->Length == sizeof(WCHAR)) &&
  862. ((&capFobx->UnicodeQueryTemplate)->Buffer[0] == L'*') &&
  863. // (!(RxContext->QueryDirectory.RestartScan)) &&
  864. // (!(RxContext->QueryDirectory.ReturnSingleEntry)) &&
  865. MRxSmbEnableOpDirCache &&
  866. TRUE) {
  867. CanCacheDir = TRUE;
  868. if (MRxSmbIsFullDirectoryCached(RxContext,
  869. RxContext->Info.Buffer,
  870. pLengthRemaining,
  871. smbFobx,
  872. &Status)) {
  873. goto FINALLY;
  874. }
  875. } else {
  876. if ( (FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_FULL_DIR_CACHE)) &&
  877. (smbFobx->Enumeration.UnalignedDirEntrySideBuffer != NULL) &&
  878. (FileInformationClass == FileBothDirectoryInformation) &&
  879. (capFobx->UnicodeQueryTemplate.Length == sizeof(WCHAR)) &&
  880. (capFobx->UnicodeQueryTemplate.Buffer[0] == L'*')) {
  881. RxDbgTrace( 0, Dbg, ("FNext FullDirCache setup :%wZ:%wZ:\n", GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext), (&capFobx->UnicodeQueryTemplate)));
  882. SmbLog(LOG,MRxSmbFullDirCacheSetup,
  883. LOGUSTR(*GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext))
  884. LOGUSTR(capFobx->UnicodeQueryTemplate));
  885. } else {
  886. RxDbgTrace( 0, Dbg, ("Else :%wZ:%wZ:\n", GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext), (&capFobx->UnicodeQueryTemplate)));
  887. SmbLog(LOG,MRxSmbFullDirCacheElse,
  888. LOGUSTR(*GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext))
  889. LOGUSTR(capFobx->UnicodeQueryTemplate));
  890. RxDbgTrace( 0, Dbg, ("From FF, non conforming\n"));
  891. SmbLog(LOG,MRxSmbFFNonConforming,LOGNOTHING);
  892. MRxSmbInvalidateFullDirectoryCache(RxContext);
  893. // CODE.IMPROVEMENT
  894. // Check if the query is for FileNamesInfo or
  895. // some such and try to satisfy from cache.
  896. }
  897. }
  898. if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_DEFERRED_OPEN)) {
  899. BOOLEAN AcquireExclusive = RxIsFcbAcquiredExclusive(capFcb);
  900. BOOLEAN AcquireShare = RxIsFcbAcquiredShared(capFcb) > 0;
  901. if (AcquireExclusive || AcquireShare) {
  902. RxReleaseFcbResourceInMRx(capFcb );
  903. }
  904. // connection could have been timed out, try to reconnect.
  905. Status = SmbCeReconnect(SrvOpen->pVNetRoot);
  906. if (AcquireExclusive) {
  907. RxAcquireExclusiveFcbResourceInMRx( capFcb );
  908. } else if (AcquireShare) {
  909. RxAcquireExclusiveFcbResourceInMRx( capFcb );
  910. }
  911. if (Status != STATUS_SUCCESS) {
  912. // connection cannot be recovered.
  913. goto FINALLY;
  914. }
  915. }
  916. //RxPurgeRelatedFobxs((PNET_ROOT)(capFcb->pNetRoot), RxContext, FALSE);
  917. //RxScavengeFobxsForNetRoot((PNET_ROOT)(capFcb->pNetRoot));
  918. if (MRxSmbForceCoreInfo ||
  919. !(pServerEntry->Server.DialectFlags&(DF_NT_SMBS|DF_W95|DF_LANMAN20))) {
  920. BufferLength = *pLengthRemaining;
  921. Status = MRxSmbCoreInformation(RxContext,
  922. (ULONG)SmbFileInfoLevel,
  923. Buffer,
  924. pLengthRemaining,
  925. SMBPSE_OE_FROM_QUERYDIRECTORY
  926. );
  927. if( NT_SUCCESS( Status ) ) {
  928. Status = FsRtlValidateFileInformationBuffer(FileInformationClass, Buffer, BufferLength);
  929. }
  930. return Status;
  931. }
  932. if (smbFobx->Enumeration.UnalignedDirEntrySideBuffer != NULL){
  933. RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: win95 internal resume\n"));
  934. Status = MrxSmbUnalignedDirEntryCopyTail(RxContext,
  935. FileInformationClass,
  936. Buffer,
  937. pLengthRemaining, //CODE.IMPROVEMENT dont pass args 2-4
  938. smbFobx);
  939. RxDbgTrace( 0, Dbg, ("Picking up FNext setup:%wZ:%wZ:\n", GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext), (&capFobx->UnicodeQueryTemplate)));
  940. SmbLog(LOG,MRxSmbPickingUpFNext,
  941. LOGUSTR(*GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext))
  942. LOGUSTR(capFobx->UnicodeQueryTemplate));
  943. if ((smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL) &&
  944. (FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_FULL_DIR_CACHE))) {
  945. RxDbgTrace( 0, Dbg, ("Resetting FNext setup:%wZ:%wZ:\n", GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext), (&capFobx->UnicodeQueryTemplate)));
  946. SmbLog(LOG,MRxSmbResettingFNext,
  947. LOGUSTR(*GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext))
  948. LOGUSTR(capFobx->UnicodeQueryTemplate));
  949. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_FULL_DIR_CACHE);
  950. // Mark as done, so the next FindNext will be failed.
  951. SetFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE);
  952. }
  953. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  954. return(Status);
  955. } else {
  956. Status = STATUS_SUCCESS;
  957. }
  958. }
  959. NumEntries = RxContext->QueryDirectory.ReturnSingleEntry?1:2000;
  960. IsUnicode = BooleanFlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE);
  961. IsNonNtT2Find = !(pServerEntry->Server.Dialect==NTLANMAN_DIALECT);
  962. //CODE.IMPROVEMENT.ASHAMED put in the quadaligned optimization
  963. if (TRUE || FlagOn(pServerEntry->Server.DialectFlags,DF_W95)){
  964. DirEntriesAreUaligned = TRUE;
  965. //SearchFlags = SMB_FIND_RETURN_RESUME_KEYS;
  966. //SearchFlags = SMB_FIND_CLOSE_AT_EOS;
  967. NumEntries = (USHORT)(1+ UnalignedDirEntrySideBufferSize
  968. /(IsNonNtT2Find?FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME, FileName)
  969. :FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName)));
  970. }
  971. if (FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)
  972. && FlagOn(capFobx->Flags,FOBX_FLAG_BACKUP_INTENT)){
  973. SearchFlags |= SMB_FIND_WITH_BACKUP_INTENT;
  974. //CODE.IMPROVEMENT turn this back on!
  975. //SearchFlags |= SMB_FIND_CLOSE_AT_EOS;
  976. }
  977. if (IsNonNtT2Find) {
  978. SearchFlags &= ~(SMB_FIND_CLOSE_AT_EOS | SMB_FIND_CLOSE_AFTER_REQUEST);
  979. }
  980. RETRY_____:
  981. if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION) &&
  982. FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST)) {
  983. if (smbFobx->Enumeration.Version != pServerEntry->Server.Version) {
  984. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST);
  985. }
  986. }
  987. if (!FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST)) {
  988. //this is the first time thru
  989. PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  990. PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate;
  991. ULONG DirectoryNameLength,TemplateLength,AllocationLength;
  992. PBYTE SmbFileName;
  993. RxDbgTrace(0, Dbg, ("-->FINFDIRST\n"));
  994. smbFobx->Enumeration.ErrorStatus = RX_MAP_STATUS(SUCCESS);
  995. if (smbFobx->Enumeration.WildCardsFound = FsRtlDoesNameContainWildCards(Template)){
  996. //we need an upcased template for
  997. RtlUpcaseUnicodeString( Template, Template, FALSE );
  998. }
  999. Setup = TRANS2_FIND_FIRST2;
  1000. DirectoryNameLength = DirectoryName->Length;
  1001. TemplateLength = Template->Length;
  1002. AllocationLength = sizeof(REQ_FIND_FIRST2) //NOTE: this buffer is bigger than w95 needs
  1003. +2*sizeof(WCHAR)
  1004. +DirectoryNameLength
  1005. +TemplateLength;
  1006. //CODE.IMPROVEMENT this would be a good place to have the xact studcode working......
  1007. pFindFirst2Request = (PREQ_FIND_FIRST2)RxAllocatePoolWithTag(
  1008. PagedPool,
  1009. AllocationLength,
  1010. MRXSMB_DIRCTL_POOLTAG);
  1011. if (pFindFirst2Request==NULL) {
  1012. RxDbgTrace(0, Dbg, (" --> Couldn't get the pFindFirst2Request!\n"));
  1013. Status = STATUS_INSUFFICIENT_RESOURCES;
  1014. goto FINALLY;
  1015. }
  1016. SmbFileName = &pFindFirst2Request->Buffer[0];
  1017. if (IsUnicode) {
  1018. RtlCopyMemory(SmbFileName,DirectoryName->Buffer,DirectoryNameLength);
  1019. SmbFileName += DirectoryNameLength;
  1020. if (*((PWCHAR)(SmbFileName-sizeof(WCHAR))) != L'\\') {
  1021. *((PWCHAR)SmbFileName) = L'\\'; SmbFileName+= sizeof(WCHAR);
  1022. }
  1023. RtlCopyMemory(SmbFileName,Template->Buffer,TemplateLength);
  1024. SmbFileName += TemplateLength;
  1025. *((PWCHAR)SmbFileName) = 0; SmbFileName+= sizeof(WCHAR); //trailing NULL;
  1026. IF_DEBUG {
  1027. DbgDoit(smbtemplate.Buffer = (PWCHAR)&pFindFirst2Request->Buffer[0];);
  1028. DbgDoit(smbtemplate.Length = (USHORT)(SmbFileName - (PBYTE)smbtemplate.Buffer););
  1029. RxDbgTrace(0, Dbg, (" --> smbtemplate <%wZ>!\n",&smbtemplate));
  1030. }
  1031. } else {
  1032. ULONG BufSize = AllocationLength;
  1033. PUNICODE_STRING FinalTemplate = Template;
  1034. UNICODE_STRING AllFiles;
  1035. SmbPutUnicodeStringAsOemString(&SmbFileName,DirectoryName,&AllocationLength);
  1036. // append a backslash if it doesn't exist in the unicode version
  1037. // NB !!! Don't compare with OEM string
  1038. // it busts DBCS characters with 0x5c at the end
  1039. if (!DirectoryName->Length || (DirectoryName->Buffer[(DirectoryName->Length/sizeof(USHORT))-1] != (USHORT)'\\'))
  1040. {
  1041. *(SmbFileName-1) = '\\';
  1042. }
  1043. else
  1044. {
  1045. // there is already a backslash, backup one character
  1046. SmbFileName -= 1; AllocationLength += 1;
  1047. }
  1048. if (IsNonNtT2Find) {
  1049. //we'll get them all and filter on out side
  1050. //CODE.IMPROVEMENT don't do that...translate the pattern
  1051. RtlInitUnicodeString(&AllFiles, L"*.*");
  1052. FinalTemplate = &AllFiles;
  1053. }
  1054. SmbPutUnicodeStringAsOemString(&SmbFileName,FinalTemplate,&AllocationLength);
  1055. //already padded *SmbFileName = 0; SmbFileName+= sizeof(CHAR); //trailing NULL;
  1056. IF_DEBUG {
  1057. DbgDoit(smbtemplate.Buffer = (PWCHAR)&pFindFirst2Request->Buffer[0];);
  1058. DbgDoit(smbtemplate.Length = (USHORT)(SmbFileName - (PBYTE)smbtemplate.Buffer););
  1059. RxDbgTrace(0, Dbg, (" --> smbtemplate <%s>!\n",&pFindFirst2Request->Buffer[0]));
  1060. }
  1061. }
  1062. // SearchAttributes is hardcoded to the magic number 0x16
  1063. pFindFirst2Request->SearchAttributes =
  1064. (SMB_FILE_ATTRIBUTE_DIRECTORY
  1065. | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN);
  1066. pFindFirst2Request->SearchCount = NumEntries;
  1067. pFindFirst2Request->Flags = SearchFlags;
  1068. pFindFirst2Request->InformationLevel = IsNonNtT2Find?SMB_INFO_QUERY_EA_SIZE:SmbFileInfoLevel;
  1069. pFindFirst2Request->SearchStorageType = 0;
  1070. SendParamsBuffer = (PBYTE)pFindFirst2Request;
  1071. SendParamsBufferLength = (ULONG)(SmbFileName - SendParamsBuffer);
  1072. ReceiveParamsBuffer = (PBYTE)&FindFirst2Response;
  1073. ReceiveParamsBufferLength = sizeof(FindFirst2Response);
  1074. } else {
  1075. if (smbFobx->Enumeration.ResumeInfo!=NULL) {
  1076. PREQ_FIND_NEXT2 pFindNext2Request;
  1077. RxDbgTrace(0, Dbg, ("-->FINDNEXT\n"));
  1078. if (smbFobx->Enumeration.ErrorStatus != RX_MAP_STATUS(SUCCESS)) {
  1079. Status = smbFobx->Enumeration.ErrorStatus;
  1080. RxDbgTrace(0, Dbg, ("-->ERROR EARLY OUT\n"));
  1081. goto FINALLY;
  1082. }
  1083. Setup = TRANS2_FIND_NEXT2;
  1084. pFindNext2Request = &smbFobx->Enumeration.ResumeInfo->FindNext2_Request;
  1085. pFindNext2Request->Sid = smbFobx->Enumeration.SearchHandle;
  1086. pFindNext2Request->SearchCount = NumEntries;
  1087. pFindNext2Request->InformationLevel = IsNonNtT2Find?SMB_INFO_QUERY_EA_SIZE:SmbFileInfoLevel;
  1088. //pFindNext2Request->ResumeKey and pFindNext2Request->Buffer are setup by the previous pass
  1089. pFindNext2Request->Flags = SearchFlags;
  1090. SendParamsBuffer = (PBYTE)pFindNext2Request;
  1091. SendParamsBufferLength = smbFobx->Enumeration.ResumeInfo->ParametersLength;
  1092. ReceiveParamsBuffer = (PBYTE)&XX.FindNext2Response;
  1093. ReceiveParamsBufferLength = sizeof(XX.FindNext2Response);
  1094. if (IsNonNtT2Find) {
  1095. //
  1096. // The LMX server wants this to be 10 instead of 8, for some reason.
  1097. // If you set it to 8, the server gets very confused. Also, warp.
  1098. //
  1099. ReceiveParamsBufferLength = 10; //....sigh
  1100. }
  1101. } else {
  1102. // if the ResumeInfo buffer was not allocated, the end of the search has been reached.
  1103. Status = RX_MAP_STATUS(NO_MORE_FILES);
  1104. smbFobx->Enumeration.EndOfSearchReached = TRUE;
  1105. smbFobx->Enumeration.ErrorStatus = RX_MAP_STATUS(NO_MORE_FILES);
  1106. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE);
  1107. goto FINALLY;
  1108. }
  1109. }
  1110. //NTRAID-455632-2/2/2000-yunlin A smaller buffer should be used
  1111. if ((DirEntriesAreUaligned) &&
  1112. (smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL)) {
  1113. MRxSmbAllocateSideBuffer(RxContext,smbFobx,
  1114. Setup, &smbtemplate
  1115. );
  1116. if (smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL) {
  1117. RxDbgTrace(0, Dbg, (" --> Couldn't get the win95 sidebuffer!\n"));
  1118. Status = STATUS_INSUFFICIENT_RESOURCES;
  1119. goto FINALLY;
  1120. }
  1121. UnalignedDirEntrySideBuffer = smbFobx->Enumeration.UnalignedDirEntrySideBuffer;
  1122. smbFobx->Enumeration.IsUnicode = IsUnicode;
  1123. smbFobx->Enumeration.IsNonNtT2Find = IsNonNtT2Find;
  1124. }
  1125. {
  1126. PSIDE_BUFFER SideBuffer;
  1127. SideBuffer = (PSIDE_BUFFER)CONTAINING_RECORD(
  1128. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  1129. SIDE_BUFFER,
  1130. Buffer);
  1131. ASSERT(SideBuffer->Signature == 'JLBS');
  1132. ASSERT(SideBuffer->Fobx == capFobx);
  1133. ASSERT(SideBuffer->Fcb == capFcb);
  1134. ASSERT(SideBuffer->smbFobx == smbFobx);
  1135. ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
  1136. }
  1137. Status = SmbCeTransact(
  1138. RxContext,
  1139. pTransactionOptions,
  1140. &Setup,
  1141. sizeof(Setup),
  1142. NULL,
  1143. 0,
  1144. SendParamsBuffer,
  1145. SendParamsBufferLength,
  1146. ReceiveParamsBuffer,
  1147. ReceiveParamsBufferLength,
  1148. NULL,
  1149. 0,
  1150. DirEntriesAreUaligned?UnalignedDirEntrySideBuffer:Buffer, // the buffer for data
  1151. DirEntriesAreUaligned?UnalignedDirEntrySideBufferSize:*pLengthRemaining, // the length of the buffer
  1152. &ResumptionContext);
  1153. if (NT_SUCCESS(Status)) {
  1154. BOOLEAN EndOfSearchReached;
  1155. {
  1156. PSIDE_BUFFER SideBuffer;
  1157. SideBuffer = (PSIDE_BUFFER)CONTAINING_RECORD(
  1158. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  1159. SIDE_BUFFER,
  1160. Buffer);
  1161. ASSERT(SideBuffer->Signature == 'JLBS');
  1162. ASSERT(SideBuffer->Fobx == capFobx);
  1163. ASSERT(SideBuffer->Fcb == capFcb);
  1164. ASSERT(SideBuffer->smbFobx == smbFobx);
  1165. ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
  1166. }
  1167. if (NT_SUCCESS(Status)) {
  1168. // a) need to set the length remaining correctly
  1169. // b) need to setup for a resume and see if the search was closed
  1170. ULONG LastNameOffset=0;
  1171. PMRX_SMB_DIRECTORY_RESUME_INFO ResumeInfo = NULL;
  1172. ULONG OriginalBufferLength = *pLengthRemaining;
  1173. IF_DEBUG { LastNameOffset = 0x40000000; }
  1174. RetryCount = 0;
  1175. smbFobx->Enumeration.Flags |= SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST;
  1176. smbFobx->Enumeration.TotalDataBytesReturned = ResumptionContext.DataBytesReceived;
  1177. if (Setup == TRANS2_FIND_FIRST2) {
  1178. smbFobx->Enumeration.SearchHandle = FindFirst2Response.Sid;
  1179. smbFobx->Enumeration.Version = ResumptionContext.ServerVersion;
  1180. smbFobx->Enumeration.Flags |= SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN; //but look right below
  1181. //CODE.IMPROVEMENT since the responses look so much alike we could coalesce this code....
  1182. EndOfSearchReached = (BOOLEAN)FindFirst2Response.EndOfSearch;
  1183. FilesReturned = FindFirst2Response.SearchCount;
  1184. LastNameOffset = FindFirst2Response.LastNameOffset;
  1185. } else {
  1186. EndOfSearchReached = (BOOLEAN)XX.FindNext2Response.EndOfSearch;
  1187. FilesReturned = XX.FindNext2Response.SearchCount;
  1188. LastNameOffset = XX.FindNext2Response.LastNameOffset;
  1189. }
  1190. //
  1191. // Please note: LANMAN 2.x servers prematurely set the
  1192. // EndOfSearch flag, so we must ignore it on LM 2.x servers.
  1193. //
  1194. // NT Returns the correct information, none of the LM varients
  1195. // appear to do so.
  1196. //
  1197. if (IsNonNtT2Find) {
  1198. EndOfSearchReached = FALSE;
  1199. }
  1200. if (Status==RX_MAP_STATUS(SUCCESS) && FilesReturned==0) {
  1201. RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: no files returned...switch status\n"));
  1202. EndOfSearchReached = TRUE;
  1203. Status = RX_MAP_STATUS(NO_MORE_FILES);
  1204. }
  1205. if (!DirEntriesAreUaligned) {
  1206. if( !EndOfSearchReached ) {
  1207. Status = FsRtlValidateFileInformationBuffer(FileInformationClass, Buffer, *pLengthRemaining);
  1208. if( !NT_SUCCESS( Status ) ) {
  1209. goto FINALLY;
  1210. }
  1211. }
  1212. *pLengthRemaining -= ResumptionContext.DataBytesReceived;
  1213. if (EndOfSearchReached) {
  1214. smbFobx->Enumeration.ErrorStatus = RX_MAP_STATUS(NO_MORE_FILES);
  1215. }
  1216. }
  1217. if (EndOfSearchReached ||
  1218. SearchFlags & SMB_FIND_CLOSE_AFTER_REQUEST) {
  1219. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN);
  1220. }
  1221. if (FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN)) {
  1222. //if the search handle is open, then we set up to resume
  1223. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectory: rinfo = %08lx\n", smbFobx->Enumeration.ResumeInfo));
  1224. if (smbFobx->Enumeration.ResumeInfo==NULL) {
  1225. smbFobx->Enumeration.ResumeInfo =
  1226. (PMRX_SMB_DIRECTORY_RESUME_INFO)RxAllocatePoolWithTag(
  1227. PagedPool,
  1228. sizeof(MRX_SMB_DIRECTORY_RESUME_INFO),
  1229. MRXSMB_DIRCTL_POOLTAG);
  1230. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectory: allocatedinfo = %08lx\n", ResumeInfo));
  1231. if (smbFobx->Enumeration.ResumeInfo == NULL) {
  1232. Status = STATUS_INSUFFICIENT_RESOURCES;
  1233. goto FINALLY;
  1234. }
  1235. }
  1236. ResumeInfo = smbFobx->Enumeration.ResumeInfo;
  1237. ASSERT (ResumeInfo!=NULL);
  1238. {
  1239. PSIDE_BUFFER SideBuffer;
  1240. SideBuffer = (PSIDE_BUFFER)CONTAINING_RECORD(
  1241. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  1242. SIDE_BUFFER,
  1243. Buffer);
  1244. ASSERT(SideBuffer->Signature == 'JLBS');
  1245. ASSERT(SideBuffer->Fobx == capFobx);
  1246. ASSERT(SideBuffer->Fcb == capFcb);
  1247. ASSERT(SideBuffer->smbFobx == smbFobx);
  1248. ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
  1249. }
  1250. RxLog(("MRxqdir: rinfo = %lx", smbFobx->Enumeration.ResumeInfo));
  1251. RxLog(("MRxqdir2: olen = %lx, thisl = %lx",
  1252. OriginalBufferLength, ResumptionContext.DataBytesReceived));
  1253. SmbLog(LOG,
  1254. MRxSmbQueryDirectory,
  1255. LOGPTR(smbFobx->Enumeration.ResumeInfo)
  1256. LOGULONG(OriginalBufferLength)
  1257. LOGULONG(ResumptionContext.DataBytesReceived));
  1258. if (!DirEntriesAreUaligned) {
  1259. PBYTE LastEntry = ((PBYTE)Buffer)+LastNameOffset;
  1260. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectory: lastentry = %08lx\n", LastEntry));
  1261. //this is for NT....the data is already in the buffer.......just setup the resume info
  1262. if (SmbFileInfoLevel>=SMB_FIND_FILE_DIRECTORY_INFO) { //we may start sending nonNT levels...could be an assert
  1263. PREQ_FIND_NEXT2 pFindNext2Request = &ResumeInfo->FindNext2_Request;
  1264. ULONG resumekey = ((PFILE_FULL_DIR_INFORMATION)LastEntry)->FileIndex;
  1265. ULONG FileNameLength; PWCHAR FileNameBuffer;
  1266. pFindNext2Request->ResumeKey = resumekey;
  1267. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectory: resumekey = %08lx\n", resumekey));
  1268. FileNameLength = *((PULONG)(LastEntry+smbFobx->Enumeration.FileNameLengthOffset));
  1269. FileNameBuffer = (PWCHAR)(LastEntry+smbFobx->Enumeration.FileNameOffset);
  1270. IF_DEBUG {
  1271. UNICODE_STRING LastName;
  1272. LastName.Buffer = FileNameBuffer;
  1273. LastName.Length = (USHORT)FileNameLength;
  1274. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectory: resumename = %wZ\n", &LastName));
  1275. }
  1276. if ((FileNameLength > MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)) ||
  1277. ((PBYTE)FileNameBuffer+FileNameLength > (PBYTE)Buffer+OriginalBufferLength)) {
  1278. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1279. } else {
  1280. RtlCopyMemory(&pFindNext2Request->Buffer[0],FileNameBuffer,FileNameLength);
  1281. //buffer is a UCHAR...not WCHAR
  1282. pFindNext2Request->Buffer[FileNameLength] = 0; //nullterminated in unicode
  1283. pFindNext2Request->Buffer[FileNameLength+1] = 0; //nullterminated in unicode
  1284. smbFobx->Enumeration.ResumeInfo->ParametersLength
  1285. = (USHORT)(&pFindNext2Request->Buffer[FileNameLength+2] - (PBYTE)pFindNext2Request);
  1286. }
  1287. } else {
  1288. ASSERT(!"don't know how to get resume key/name for nonNT");
  1289. }
  1290. }
  1291. }
  1292. {
  1293. PSIDE_BUFFER SideBuffer;
  1294. SideBuffer = (PSIDE_BUFFER)CONTAINING_RECORD(
  1295. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  1296. SIDE_BUFFER,
  1297. Buffer);
  1298. ASSERT(SideBuffer->Signature == 'JLBS');
  1299. ASSERT(SideBuffer->Fobx == capFobx);
  1300. ASSERT(SideBuffer->Fcb == capFcb);
  1301. ASSERT(SideBuffer->smbFobx == smbFobx);
  1302. ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
  1303. }
  1304. //for NT we are finished. for win95 we have to go thru the side buffer and
  1305. // 1) copy in the data transforming ascii->unicode on the names, and
  1306. // 2) remember the resume key and the filename of the last guy that we process
  1307. // because win95 doesn't 8byte aling things and because of unicode, we could end up
  1308. // with more data in the sidebuffer than we can return. this is very unfortunate.
  1309. // what would be cool CODE.IMPROVEMENT, would be to implement buffering in the wrapper
  1310. // the code is moved down because we want to do it after the unlock
  1311. }
  1312. if (DirEntriesAreUaligned && (Status == STATUS_SUCCESS)) {
  1313. smbFobx->Enumeration.FilesReturned = FilesReturned;
  1314. smbFobx->Enumeration.EntryOffset = 0;
  1315. smbFobx->Enumeration.EndOfSearchReached = EndOfSearchReached;
  1316. if ((Status == STATUS_SUCCESS) &&
  1317. (CanCacheDir) &&
  1318. (smbFobx->Enumeration.TotalDataBytesReturned <=
  1319. NAME_CACHE_PARTIAL_DIR_BUFFER_SIZE) &&
  1320. (EndOfSearchReached) &&
  1321. TRUE) {
  1322. RxDbgTrace( 0, Dbg, ("Trying to Cache %wZ, Bytes:%ld, EOS:%d, Files:%d\n",GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext),smbFobx->Enumeration.TotalDataBytesReturned,(ULONG)EndOfSearchReached,FilesReturned));
  1323. SmbLog(LOG,MRxSmbAttemptingCache,
  1324. LOGUSTR(*GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext))
  1325. LOGULONG(smbFobx->Enumeration.TotalDataBytesReturned)
  1326. LOGULONG(FilesReturned));
  1327. MRxSmbCacheFullDirectory(
  1328. RxContext,
  1329. RxContext->Info.Buffer,
  1330. smbFobx->Enumeration.TotalDataBytesReturned,
  1331. smbFobx);
  1332. // Mark smbFobx such that we won't invalidate on FNext.
  1333. SetFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_FULL_DIR_CACHE);
  1334. // If READ_FROM_CACHE is set, the FindNext will be failed, since
  1335. // this was satisfied from Full Dir Cache,
  1336. // Since we setup the Target SmbFobx properly for the FindNext,
  1337. // we let the FindNext pass through.
  1338. }
  1339. Status = MrxSmbUnalignedDirEntryCopyTail(RxContext,
  1340. FileInformationClass,
  1341. Buffer,
  1342. pLengthRemaining,
  1343. smbFobx);
  1344. }
  1345. } else {
  1346. // CODE IMPROVEMENT we should cache the file not found for findfirst as well
  1347. }
  1348. FINALLY:
  1349. //for downlevel-T2, we will have to go back to the server for some more.....sigh.......
  1350. if (Status==STATUS_MORE_PROCESSING_REQUIRED) {
  1351. goto RETRY_____;
  1352. }
  1353. //
  1354. // under stress, the win95 server returns this......
  1355. if ( (Status == STATUS_UNEXPECTED_NETWORK_ERROR)
  1356. && FlagOn(pServerEntry->Server.DialectFlags,DF_W95)
  1357. && (RetryCount < 10) ) {
  1358. RetryCount++;
  1359. MRxSmbWin95Retries++;
  1360. goto RETRY_____;
  1361. }
  1362. if (pFindFirst2Request) RxFreePool(pFindFirst2Request);
  1363. if (!NT_SUCCESS(Status)) {
  1364. RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: Failed .. returning %lx\n",Status));
  1365. //smbFobx->Enumeration.Flags &= ~SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN;
  1366. smbFobx->Enumeration.ErrorStatus = Status; //keep returning this
  1367. MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"ErrOut");
  1368. if (smbFobx->Enumeration.ResumeInfo!=NULL) {
  1369. RxFreePool(smbFobx->Enumeration.ResumeInfo);
  1370. smbFobx->Enumeration.ResumeInfo = NULL;
  1371. }
  1372. }
  1373. RxDbgTraceUnIndent(-1,Dbg);
  1374. return Status;
  1375. }
  1376. RXDT_DefineCategory(VOLINFO);
  1377. #undef Dbg
  1378. #define Dbg (DEBUG_TRACE_VOLINFO)
  1379. NTSTATUS
  1380. MRxSmbQueryVolumeInformationWithFullBuffer(
  1381. IN OUT PRX_CONTEXT RxContext
  1382. );
  1383. NTSTATUS
  1384. MRxSmbQueryVolumeInformation(
  1385. IN OUT PRX_CONTEXT RxContext
  1386. )
  1387. /*++
  1388. Routine Description:
  1389. This routine queries the volume information. Since the NT server does not
  1390. handle bufferoverflow gracefully on query-fs-info, we allocate a buffer here
  1391. that is big enough to hold anything passed back; then we call the "real"
  1392. queryvolinfo routine.
  1393. Arguments:
  1394. pRxContext - the RDBSS context
  1395. Return Value:
  1396. RXSTATUS - The return status for the operation
  1397. --*/
  1398. {
  1399. NTSTATUS Status;
  1400. RxCaptureFcb; RxCaptureFobx;
  1401. PVOID OriginalBuffer;
  1402. ULONG OriginalLength = RxContext->Info.LengthRemaining;
  1403. ULONG ReturnedLength;
  1404. BOOLEAN UsingSideBuffer = FALSE;
  1405. struct {
  1406. union {
  1407. FILE_FS_LABEL_INFORMATION labelinfo;
  1408. FILE_FS_VOLUME_INFORMATION volumeinfo;
  1409. FILE_FS_SIZE_INFORMATION sizeinfo;
  1410. FILE_FS_DEVICE_INFORMATION deviceinfo;
  1411. FILE_FS_ATTRIBUTE_INFORMATION attributeinfo;
  1412. FILE_FS_CONTROL_INFORMATION controlinfo;
  1413. } Info;
  1414. WCHAR VolumeName[MAXIMUM_FILENAME_LENGTH];
  1415. } SideBuffer;
  1416. PAGED_CODE();
  1417. if( RxContext->Info.LengthRemaining < sizeof( SideBuffer ) ) {
  1418. //
  1419. // i replace the buffer and length in the context with my stuff.
  1420. // This, of course, means that we can't go async....for that we'd
  1421. // have to allocate in stead of using a stack-allocated buffer.
  1422. // In that case we would have to store the buffer somewhere in the
  1423. // context for use with [CODE.IMPROVEMENT] downlevel guys. what would make
  1424. // this work would be if CreateOE saved the exchange and stufferstate
  1425. // values in the context before it overwrote them with its own.
  1426. //
  1427. // it's not immediately obvious that we should be allocating such a large
  1428. // structure on the stack. CODE.IMPROVEMENT..........
  1429. UsingSideBuffer = TRUE;
  1430. OriginalBuffer = RxContext->Info.Buffer;
  1431. RxContext->Info.Buffer = &SideBuffer;
  1432. RxContext->Info.LengthRemaining = sizeof(SideBuffer);
  1433. }
  1434. Status = MRxSmbQueryVolumeInformationWithFullBuffer(RxContext);
  1435. if (Status != STATUS_SUCCESS) {
  1436. goto FINALLY;
  1437. }
  1438. if( UsingSideBuffer == TRUE ) {
  1439. ReturnedLength = sizeof(SideBuffer) - RxContext->Info.LengthRemaining;
  1440. } else {
  1441. ReturnedLength = OriginalLength - RxContext->Info.LengthRemaining;
  1442. }
  1443. if (ReturnedLength > OriginalLength) {
  1444. Status = STATUS_BUFFER_OVERFLOW;
  1445. ReturnedLength = OriginalLength;
  1446. }
  1447. if( UsingSideBuffer == TRUE ) {
  1448. RtlCopyMemory(OriginalBuffer,&SideBuffer,ReturnedLength);
  1449. }
  1450. RxContext->Info.LengthRemaining = OriginalLength - ReturnedLength;
  1451. FINALLY:
  1452. return Status;
  1453. }
  1454. NTSTATUS
  1455. MRxSmbQueryVolumeInformationWithFullBuffer(
  1456. IN OUT PRX_CONTEXT RxContext
  1457. )
  1458. /*++
  1459. Routine Description:
  1460. This routine queries the volume information
  1461. Arguments:
  1462. pRxContext - the RDBSS context
  1463. FsInformationClass - the kind of Fs information desired.
  1464. pBuffer - the buffer for copying the information
  1465. pBufferLength - the buffer length ( set to buffer length on input and set
  1466. to the remaining length on output)
  1467. Return Value:
  1468. RXSTATUS - The return status for the operation
  1469. --*/
  1470. {
  1471. NTSTATUS Status;
  1472. RxCaptureFcb;
  1473. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  1474. RxCaptureFobx;
  1475. PMRX_SRV_OPEN SrvOpen;
  1476. PMRX_SMB_SRV_OPEN smbSrvOpen;
  1477. FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
  1478. PVOID pBuffer = RxContext->Info.Buffer;
  1479. PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
  1480. LONG OriginalLength = *pLengthRemaining;
  1481. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1482. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  1483. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  1484. LARGE_INTEGER CurrentTime;
  1485. BOOLEAN DoAsDownLevel;
  1486. PVOID pInputParamBuffer;
  1487. ULONG InputParamBufferLength;
  1488. USHORT InformationLevel;
  1489. USHORT Setup;
  1490. REQ_QUERY_FS_INFORMATION QueryFsInformationRequest;
  1491. REQ_QUERY_FS_INFORMATION_FID DfsQueryFsInformationRequest;
  1492. PAGED_CODE();
  1493. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1494. if ( FsInformationClass == FileFsDeviceInformation ) {
  1495. PFILE_FS_DEVICE_INFORMATION UsersBuffer = (PFILE_FS_DEVICE_INFORMATION)pBuffer;
  1496. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1497. UsersBuffer->Characteristics = FILE_REMOTE_DEVICE;
  1498. if (NetRoot->Type==NET_ROOT_PIPE) {
  1499. NetRoot->DeviceType = RxDeviceType(NAMED_PIPE);
  1500. }
  1501. UsersBuffer->DeviceType = NetRoot->DeviceType;
  1502. *pLengthRemaining -= (sizeof(FILE_FS_DEVICE_INFORMATION));
  1503. RxDbgTrace( 0, Dbg, ("MRxSmbQueryVolumeInformation: devinfo .. returning\n"));
  1504. return RX_MAP_STATUS(SUCCESS);
  1505. }
  1506. if (capFobx != NULL) {
  1507. SrvOpen = capFobx->pSrvOpen;
  1508. smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1509. pVNetRootContext = SmbCeGetAssociatedVNetRootContext(SrvOpen->pVNetRoot);
  1510. pNetRootEntry = pVNetRootContext->pNetRootEntry;
  1511. } else {
  1512. return RX_MAP_STATUS(INVALID_PARAMETER);
  1513. }
  1514. TURN_BACK_ASYNCHRONOUS_OPERATIONS();
  1515. IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC{
  1516. NOTHING;
  1517. } else {
  1518. if (CscPerformOperationInDisconnectedMode(RxContext)){
  1519. NTSTATUS VolInfoNtStatus;
  1520. VolInfoNtStatus = MRxSmbDCscQueryVolumeInformation(RxContext);
  1521. if (VolInfoNtStatus != STATUS_MORE_PROCESSING_REQUIRED) {
  1522. RxDbgTrace(-1, Dbg,
  1523. ("MRxSmbQueryVolumeInfo returningDCON with status=%08lx\n",
  1524. VolInfoNtStatus ));
  1525. return(VolInfoNtStatus);
  1526. } else {
  1527. NOTHING;
  1528. //RxDbgTrace(0, Dbg,
  1529. // ("MRxSmbQueryVolumeInfo continueingDCON with status=%08lx\n",
  1530. // VolInfoNtStatus ));
  1531. }
  1532. }
  1533. }
  1534. if (FsInformationClass == FileFsVolumeInformation) {
  1535. KeQueryTickCount(&CurrentTime);
  1536. if (CurrentTime.QuadPart < pNetRootEntry->VolumeInfoExpiryTime.QuadPart) {
  1537. // use the cached volume information if it is not expired
  1538. RtlCopyMemory(pBuffer,
  1539. pNetRootEntry->VolumeInfo,
  1540. pNetRootEntry->VolumeInfoLength);
  1541. *pLengthRemaining -= pNetRootEntry->VolumeInfoLength;
  1542. return STATUS_SUCCESS;
  1543. }
  1544. }
  1545. for (;;) {
  1546. if (capFobx != NULL) {
  1547. PMRX_V_NET_ROOT pVNetRoot;
  1548. // Avoid device opens for which the FOBX is the VNET_ROOT instance
  1549. pVNetRoot = (PMRX_V_NET_ROOT)capFobx;
  1550. if (NodeType(pVNetRoot) != RDBSS_NTC_V_NETROOT) {
  1551. PUNICODE_STRING AlreadyPrefixedName =
  1552. GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1553. ULONG FcbAlreadyPrefixedNameLength = AlreadyPrefixedName->Length;
  1554. ULONG NetRootInnerNamePrefixLength = capFcb->pNetRoot->InnerNamePrefix.Length;
  1555. PWCHAR pName = AlreadyPrefixedName->Buffer;
  1556. // If an FSCTL is being attempted against the root of a share.
  1557. // The AlreadyPrefixedName associated with the FCB is the same as
  1558. // the AlreadyPrefixedName length associated with the NET_ROOT instance
  1559. // or atmost one character greater than it ( appending a \) try and
  1560. // reestablish the connection before attempting the FSCTL.
  1561. // This solves thorny issues regarding deletion/creation of shares
  1562. // on the server sides, DFS referrals etc.
  1563. if ((FcbAlreadyPrefixedNameLength == NetRootInnerNamePrefixLength) ||
  1564. ((FcbAlreadyPrefixedNameLength == NetRootInnerNamePrefixLength + sizeof(WCHAR)) &&
  1565. (*((PCHAR)pName + FcbAlreadyPrefixedNameLength - sizeof(WCHAR)) ==
  1566. L'\\'))) {
  1567. Status = SmbCeReconnect(capFobx->pSrvOpen->pVNetRoot);
  1568. }
  1569. }
  1570. }
  1571. DoAsDownLevel = MRxSmbForceCoreInfo;
  1572. if (!FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
  1573. DoAsDownLevel = TRUE;
  1574. }
  1575. if (FlagOn(pServerEntry->Server.DialectFlags,DF_W95)
  1576. && (FsInformationClass==FileFsAttributeInformation)){ //use uplevel for w95 attribute info
  1577. DoAsDownLevel = FALSE;
  1578. }
  1579. if (DoAsDownLevel) {
  1580. Status = MRxSmbCoreInformation(RxContext,
  1581. (ULONG)FsInformationClass,
  1582. pBuffer,
  1583. pLengthRemaining, //CODE.IMPROVEMENT dont pass args 2-4
  1584. SMBPSE_OE_FROM_QUERYVOLUMEINFO
  1585. );
  1586. goto FINALLY;
  1587. }
  1588. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1589. switch (FsInformationClass) {
  1590. case FileFsVolumeInformation :
  1591. InformationLevel = SMB_QUERY_FS_VOLUME_INFO;
  1592. break;
  1593. case FileFsLabelInformation :
  1594. InformationLevel = SMB_QUERY_FS_LABEL_INFO;
  1595. break;
  1596. case FileFsSizeInformation :
  1597. InformationLevel = SMB_QUERY_FS_SIZE_INFO;
  1598. break;
  1599. case FileFsAttributeInformation :
  1600. InformationLevel = SMB_QUERY_FS_ATTRIBUTE_INFO;
  1601. break;
  1602. default:
  1603. if( FlagOn( pServerEntry->Server.DialectFlags, DF_NT_INFO_PASSTHROUGH ) ) {
  1604. InformationLevel = FsInformationClass + SMB_INFO_PASSTHROUGH;
  1605. } else {
  1606. RxDbgTrace( 0, Dbg, ("MRxSmbQueryVolumeInformation: Invalid FS information class\n"));
  1607. Status = STATUS_INVALID_PARAMETER;
  1608. }
  1609. break;
  1610. }
  1611. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1612. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  1613. PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
  1614. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  1615. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1616. if (!FlagOn(pServerEntry->Server.DialectFlags,DF_DFS_TRANS2)) {
  1617. Setup = TRANS2_QUERY_FS_INFORMATION;
  1618. QueryFsInformationRequest.InformationLevel = InformationLevel;
  1619. pInputParamBuffer = &QueryFsInformationRequest;
  1620. InputParamBufferLength = sizeof(QueryFsInformationRequest);
  1621. } else {
  1622. Setup = TRANS2_QUERY_FS_INFORMATION_FID;
  1623. DfsQueryFsInformationRequest.InformationLevel = InformationLevel;
  1624. DfsQueryFsInformationRequest.Fid = smbSrvOpen->Fid;
  1625. pInputParamBuffer = &DfsQueryFsInformationRequest;
  1626. InputParamBufferLength = sizeof(DfsQueryFsInformationRequest);
  1627. }
  1628. Status = SmbCeTransact(
  1629. RxContext,
  1630. pTransactionOptions,
  1631. &Setup,
  1632. sizeof(Setup),
  1633. NULL,
  1634. 0,
  1635. pInputParamBuffer,
  1636. InputParamBufferLength,
  1637. NULL,
  1638. 0,
  1639. NULL,
  1640. 0,
  1641. pBuffer,
  1642. *pLengthRemaining,
  1643. &ResumptionContext);
  1644. if (NT_SUCCESS(Status)) {
  1645. *pLengthRemaining -= ResumptionContext.DataBytesReceived;
  1646. //CODE.IMPROVEMENT if this is a size query, we should store the clustersize in the netroot
  1647. // this would save us one packet later.
  1648. }
  1649. }
  1650. if (!NT_SUCCESS(Status)) {
  1651. RxDbgTrace( 0, Dbg, ("MRxSmbQueryVolumeInformation: Failed .. returning %lx\n",Status));
  1652. }
  1653. if (Status != STATUS_NETWORK_NAME_DELETED) {
  1654. break;
  1655. }
  1656. }
  1657. FINALLY:
  1658. if ((Status == STATUS_SUCCESS) &&
  1659. (FsInformationClass == FileFsVolumeInformation)) {
  1660. LARGE_INTEGER ExpiryTimeInTicks;
  1661. LONG VolumeInfoLength = OriginalLength - *pLengthRemaining;
  1662. if (VolumeInfoLength > pNetRootEntry->VolumeInfoLength) {
  1663. // If the Volume Label gets longer, allocate a new buffer
  1664. if (pNetRootEntry->VolumeInfo != NULL) {
  1665. RxFreePool(pNetRootEntry->VolumeInfo);
  1666. }
  1667. pNetRootEntry->VolumeInfo = RxAllocatePoolWithTag(PagedPool,
  1668. VolumeInfoLength,
  1669. MRXSMB_QPINFO_POOLTAG);
  1670. }
  1671. if (pNetRootEntry->VolumeInfo != NULL) {
  1672. KeQueryTickCount(&CurrentTime);
  1673. ExpiryTimeInTicks.QuadPart = (1000 * 1000 * 10) / KeQueryTimeIncrement();
  1674. ExpiryTimeInTicks.QuadPart = ExpiryTimeInTicks.QuadPart * NAME_CACHE_OBJ_GET_FILE_ATTRIB_LIFETIME;
  1675. pNetRootEntry->VolumeInfoExpiryTime.QuadPart = CurrentTime.QuadPart + ExpiryTimeInTicks.QuadPart;
  1676. RtlCopyMemory(pNetRootEntry->VolumeInfo,
  1677. pBuffer,
  1678. VolumeInfoLength);
  1679. pNetRootEntry->VolumeInfoLength = VolumeInfoLength;
  1680. } else {
  1681. pNetRootEntry->VolumeInfoLength = 0;
  1682. }
  1683. }
  1684. return Status;
  1685. }
  1686. NTSTATUS
  1687. MRxSmbSetVolumeInformation(
  1688. IN OUT PRX_CONTEXT RxContext
  1689. )
  1690. /*++
  1691. Routine Description:
  1692. This routine sets the volume information
  1693. Arguments:
  1694. pRxContext - the RDBSS context
  1695. FsInformationClass - the kind of Fs information desired.
  1696. pBuffer - the buffer for copying the information
  1697. BufferLength - the buffer length
  1698. Return Value:
  1699. RXSTATUS - The return status for the operation
  1700. --*/
  1701. {
  1702. NTSTATUS Status;
  1703. RxCaptureFcb;
  1704. RxCaptureFobx;
  1705. FILE_INFORMATION_CLASS FileInformationClass;
  1706. PVOID pBuffer;
  1707. ULONG BufferLength;
  1708. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1709. BOOLEAN ServerSupportsPassThroughForSetInfo = FALSE;
  1710. PAGED_CODE();
  1711. TURN_BACK_ASYNCHRONOUS_OPERATIONS();
  1712. IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC{
  1713. NOTHING;
  1714. } else {
  1715. if (CscPerformOperationInDisconnectedMode(RxContext)){
  1716. return STATUS_NOT_SUPPORTED;
  1717. }
  1718. }
  1719. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1720. FileInformationClass = RxContext->Info.FileInformationClass;
  1721. pBuffer = RxContext->Info.Buffer;
  1722. BufferLength = RxContext->Info.Length;
  1723. if (!MRxSmbForceCoreInfo &&
  1724. FlagOn( pServerEntry->Server.DialectFlags, DF_NT_INFO_PASSTHROUGH)) {
  1725. ServerSupportsPassThroughForSetInfo = TRUE;
  1726. }
  1727. if (ServerSupportsPassThroughForSetInfo) {
  1728. USHORT Setup = TRANS2_SET_FS_INFORMATION;
  1729. REQ_SET_FS_INFORMATION SetFsInfoRequest;
  1730. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  1731. PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
  1732. if (capFobx != NULL) {
  1733. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  1734. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1735. SetFsInfoRequest.Fid = smbSrvOpen->Fid;
  1736. SetFsInfoRequest.InformationLevel = FileInformationClass +
  1737. SMB_INFO_PASSTHROUGH;
  1738. Status = SmbCeTransact(
  1739. RxContext,
  1740. pTransactionOptions,
  1741. &Setup,
  1742. sizeof(Setup),
  1743. NULL,
  1744. 0,
  1745. &SetFsInfoRequest,
  1746. sizeof(SetFsInfoRequest),
  1747. NULL,
  1748. 0,
  1749. pBuffer,
  1750. BufferLength,
  1751. NULL,
  1752. 0,
  1753. &ResumptionContext);
  1754. } else {
  1755. Status = STATUS_INVALID_PARAMETER;
  1756. }
  1757. } else {
  1758. Status = STATUS_NOT_SUPPORTED;
  1759. }
  1760. if (!NT_SUCCESS(Status)) {
  1761. RxDbgTrace( 0, Dbg, ("MRxSmbSetFile: Failed .. returning %lx\n",Status));
  1762. }
  1763. RxDbgTraceUnIndent(-1,Dbg);
  1764. return Status;
  1765. }
  1766. NTSTATUS
  1767. FsRtlValidateFileInformationBuffer(
  1768. ULONG FileInformationClass,
  1769. PVOID InformationBuffer,
  1770. ULONG InformationBufferLength )
  1771. /*++
  1772. Routine Description:
  1773. This routine validates a file information buffer received from the server.
  1774. Depending on the FileInformationClass, we validate the following:
  1775. * NextEntryOffset points forward, and lies within the buffer
  1776. * File/DirNameLength does not bleed into the next entry
  1777. * NextEntryOffset is suitably aligned.
  1778. Arguments:
  1779. FileInformationClass - The information class we want to validate.
  1780. InformationBuffer - The information buffer to be validated.
  1781. InformationBufferLength - The size in bytes of the buffer
  1782. Return Value:
  1783. STATUS_SUCCESS if the buffer is valid.
  1784. STATUS_INVALID_NETWORK_RESPONSE otherwise.
  1785. Notes:
  1786. --*/
  1787. {
  1788. ULONG CurrentOffset = 0;
  1789. ULONG NextEntryOffset = 0;
  1790. NTSTATUS Status = STATUS_SUCCESS;
  1791. ULONG AlignMask;
  1792. //
  1793. // Return success trivially, if the buffer length is zero.
  1794. //
  1795. if( InformationBufferLength == 0 ) {
  1796. return STATUS_SUCCESS;
  1797. }
  1798. //
  1799. // Some structures need to be 8 byte aligned, while others 4 byte.
  1800. //
  1801. switch( FileInformationClass ) {
  1802. case FileStreamInformation:
  1803. case FileDirectoryInformation:
  1804. case FileFullDirectoryInformation:
  1805. case FileIdFullDirectoryInformation:
  1806. case FileBothDirectoryInformation:
  1807. case FileIdBothDirectoryInformation:
  1808. case FileQuotaInformation:
  1809. AlignMask = 0x7;
  1810. break;
  1811. case FileNamesInformation:
  1812. AlignMask = 0x3;
  1813. break;
  1814. default:
  1815. //
  1816. // Return success for stuff we dont validate.
  1817. //
  1818. return Status;
  1819. }
  1820. //
  1821. // If we reach here, it means that the buffer is a list of entries linked together
  1822. // using a 'NextEntryOffset' field. 'NextEntryOffset' is assumed to be the 1st ULONG
  1823. // in the structure. The last entry in the list is flagged by NextEntryOffset = 0.
  1824. //
  1825. do
  1826. {
  1827. //
  1828. // Return failure if we cannot safely read the 'NextEntryOffset'.
  1829. //
  1830. if( InformationBufferLength < CurrentOffset + sizeof(ULONG) ) {
  1831. ASSERT( !"'NextEntryOffset' overruns buffer" );
  1832. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1833. break;
  1834. }
  1835. NextEntryOffset = *((PULONG)InformationBuffer);
  1836. if( NextEntryOffset == 0 ) {
  1837. NextEntryOffset = InformationBufferLength - CurrentOffset;
  1838. }
  1839. switch(FileInformationClass) {
  1840. case FileStreamInformation: {
  1841. //
  1842. // Stream name length doesnt overrun the current entry or the buffer.
  1843. //
  1844. PFILE_STREAM_INFORMATION pInfo = InformationBuffer;
  1845. if(( CurrentOffset + FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName) > InformationBufferLength ) ||
  1846. ( pInfo->StreamNameLength + FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName) > NextEntryOffset ) ||
  1847. ( (LONG)pInfo->StreamNameLength < 0 ) ) {
  1848. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1849. ASSERT(!"Invalid FileStreamInformation StreamNameLength");
  1850. }
  1851. break;
  1852. }
  1853. case FileDirectoryInformation: {
  1854. //
  1855. // Filename length doesnt overrun the current entry or the buffer.
  1856. //
  1857. PFILE_DIRECTORY_INFORMATION pInfo = InformationBuffer;
  1858. if(( CurrentOffset + FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) > InformationBufferLength ) ||
  1859. ( pInfo->FileNameLength + FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) > NextEntryOffset ) ||
  1860. ( (LONG)pInfo->FileNameLength < 0 ) ) {
  1861. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1862. ASSERT(!"Invalid FileDirectoryInformation FileNameLength");
  1863. }
  1864. break;
  1865. }
  1866. case FileFullDirectoryInformation: {
  1867. //
  1868. // Filename length doesnt overrun the current entry or the buffer.
  1869. //
  1870. PFILE_FULL_DIR_INFORMATION pInfo = InformationBuffer;
  1871. if(( CurrentOffset + FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) > InformationBufferLength ) ||
  1872. ( pInfo->FileNameLength + FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) > NextEntryOffset ) ||
  1873. ( (LONG)pInfo->FileNameLength < 0 ) ) {
  1874. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1875. ASSERT(!"Invalid FileFullDirectoryInformation FileNameLength");
  1876. }
  1877. break;
  1878. }
  1879. case FileIdFullDirectoryInformation: {
  1880. //
  1881. // Filename length doesnt overrun the current entry or the buffer.
  1882. //
  1883. PFILE_ID_FULL_DIR_INFORMATION pInfo = InformationBuffer;
  1884. if(( CurrentOffset + FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, FileName) > InformationBufferLength ) ||
  1885. ( pInfo->FileNameLength + FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, FileName) > NextEntryOffset ) ||
  1886. ( (LONG)pInfo->FileNameLength < 0 ) ) {
  1887. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1888. ASSERT(!"Invalid FileIdFullDirectoryInformation FileNameLength");
  1889. }
  1890. break;
  1891. }
  1892. case FileBothDirectoryInformation: {
  1893. //
  1894. // Filename length doesnt overrun the current entry or the buffer.
  1895. //
  1896. PFILE_BOTH_DIR_INFORMATION pInfo = InformationBuffer;
  1897. if(( CurrentOffset + FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) > InformationBufferLength ) ||
  1898. ( pInfo->FileNameLength + FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) > NextEntryOffset ) ||
  1899. ( (LONG)pInfo->FileNameLength < 0 ) ) {
  1900. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1901. ASSERT(!"Invalid FileBothDirectoryInformation FileNameLength");
  1902. }
  1903. break;
  1904. }
  1905. case FileIdBothDirectoryInformation: {
  1906. //
  1907. // Filename length doesnt overrun the current entry or the buffer.
  1908. //
  1909. PFILE_BOTH_DIR_INFORMATION pInfo = InformationBuffer;
  1910. if(( CurrentOffset + FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName) > InformationBufferLength ) ||
  1911. ( pInfo->FileNameLength + FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName) > NextEntryOffset ) ||
  1912. ( (LONG)pInfo->FileNameLength < 0 ) ) {
  1913. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1914. ASSERT(!"Invalid FileIdBothDirectoryInformation FileNameLength");
  1915. }
  1916. break;
  1917. }
  1918. case FileNamesInformation: {
  1919. //
  1920. // Filename length doesnt overrun the current entry or the buffer.
  1921. //
  1922. PFILE_NAMES_INFORMATION pInfo = InformationBuffer;
  1923. if(( CurrentOffset + FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) > InformationBufferLength ) ||
  1924. ( pInfo->FileNameLength + FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) > NextEntryOffset ) ||
  1925. ( (LONG)pInfo->FileNameLength < 0 ) ) {
  1926. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1927. ASSERT(!"Invalid FileNamesInformation FileNameLength");
  1928. }
  1929. break;
  1930. }
  1931. case FileQuotaInformation:
  1932. //
  1933. // No special checks for this one.
  1934. //
  1935. break;
  1936. default:
  1937. ASSERT(!"Unexpected FileInformationClass");
  1938. break;
  1939. }
  1940. //
  1941. // If there was an error then break out of the loop.
  1942. //
  1943. if( !NT_SUCCESS( Status ) ) {
  1944. break;
  1945. }
  1946. //
  1947. // If 'NextEntryOffset' is 0, then break out
  1948. //
  1949. if( *((PULONG)InformationBuffer) == 0 ) {
  1950. break;
  1951. }
  1952. //
  1953. // Check 'NextEntryOffset' for backward links (note the cast to PLONG)
  1954. //
  1955. if( *((PLONG)InformationBuffer) < 0 ) {
  1956. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1957. ASSERT(!"FileInformation: NextEntryOffset < 0");
  1958. break;
  1959. }
  1960. //
  1961. // Check 'NextEntryOffset' for link which overruns the buffer.
  1962. //
  1963. if( CurrentOffset + *((PULONG)InformationBuffer) >= InformationBufferLength ) {
  1964. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1965. ASSERT(!"FileInformation: NextEntryOffset > InformationBufferLength");
  1966. break;
  1967. }
  1968. //
  1969. // Check for proper alignment
  1970. //
  1971. if( *((PULONG)InformationBuffer) & AlignMask ) {
  1972. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1973. ASSERT(!"FileInformation: NextEntryOffset is not aligned");
  1974. break;
  1975. }
  1976. CurrentOffset += *((PULONG)InformationBuffer);
  1977. InformationBuffer = (PVOID) Add2Ptr( InformationBuffer, *((PULONG)InformationBuffer) );
  1978. } while(1);
  1979. return Status;
  1980. }
  1981. RXDT_DefineCategory(FILEINFO);
  1982. #undef Dbg
  1983. #define Dbg (DEBUG_TRACE_FILEINFO)
  1984. LONG GFAFromLocal;
  1985. NTSTATUS
  1986. MRxSmbQueryFileInformation(
  1987. IN PRX_CONTEXT RxContext )
  1988. /*++
  1989. Routine Description:
  1990. This routine does a query file info.
  1991. Arguments:
  1992. RxContext - the RDBSS context
  1993. Return Value:
  1994. NTSTATUS - The return status for the operation
  1995. --*/
  1996. {
  1997. NTSTATUS Status;
  1998. RxCaptureFcb;
  1999. RxCaptureFobx;
  2000. FILE_INFORMATION_CLASS FileInformationClass;
  2001. PVOID pBuffer;
  2002. PULONG pLengthRemaining;
  2003. ULONG BufferLength;
  2004. PSMBCEDB_SERVER_ENTRY pServerEntry;
  2005. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  2006. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  2007. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  2008. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  2009. PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  2010. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  2011. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)SrvOpen->pVNetRoot->Context;
  2012. PSMBCE_NET_ROOT pSmbNetRoot = &pVNetRootContext->pNetRootEntry->NetRoot;
  2013. USHORT SmbFileInfoLevel;
  2014. USHORT Setup;
  2015. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  2016. PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
  2017. REQ_QUERY_FILE_INFORMATION QueryFileInfoRequest;
  2018. RESP_QUERY_FILE_INFORMATION QueryFileInfoResponse;
  2019. PREQ_QUERY_PATH_INFORMATION pQueryFilePathRequest = NULL;
  2020. PVOID pSendParameterBuffer;
  2021. ULONG SendParameterBufferLength;
  2022. PAGED_CODE();
  2023. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  2024. FileInformationClass = RxContext->Info.FileInformationClass;
  2025. pBuffer = RxContext->Info.Buffer;
  2026. pLengthRemaining = &RxContext->Info.LengthRemaining;
  2027. RxDbgTrace(+1, Dbg, ("MRxSmbQueryFileInformation: class=%08lx\n",FileInformationClass));
  2028. //CODE.IMPROVEMENT.ASHAMED it is a real SHAME is that we don't do a SMB_QUERY_FILE_ALL_INFO
  2029. // in response to a FileAllInformation request. what we should do is to call down with all_info;
  2030. // if the mini returns SNI then we do the individual pieces. the problem with all_info is that
  2031. // it contains the name and that might cause it to overflow my buffer! however, a name can only be 32k
  2032. // so i could waltz around that with a big buffer.
  2033. TURN_BACK_ASYNCHRONOUS_OPERATIONS();
  2034. /*
  2035. // begin init code to replace switch with table lookup
  2036. #define SMB_QUERY_FILE_INFO_INVALID_REQ 0xFFF
  2037. #define SMB_QUERY_FILE_INFO_PIPE_REQ 0xFFE
  2038. USHORT NtToSmbQueryFileInfo[FileMaximumInformation];
  2039. for (i=0; i < FileMaximumInformation; i++) {
  2040. NtToSmbQueryFileInfo[i] = SMB_QUERY_FILE_INFO_INVALID_REQ;
  2041. }
  2042. NtToSmbQueryFileInfo[FileBasicInformation] = SMB_QUERY_FILE_BASIC_INFO;
  2043. NtToSmbQueryFileInfo[FileStandardInformation] = SMB_QUERY_FILE_STANDARD_INFO;
  2044. NtToSmbQueryFileInfo[FileEaInformation] = SMB_QUERY_FILE_EA_INFO;
  2045. NtToSmbQueryFileInfo[FileAllocationInformation] = SMB_QUERY_FILE_ALLOCATION_INFO;
  2046. NtToSmbQueryFileInfo[FileEndOfFileInformation] = SMB_QUERY_FILE_END_OF_FILEINFO;
  2047. NtToSmbQueryFileInfo[FileAlternateNameInformation] = SMB_QUERY_FILE_ALT_NAME_INFO;
  2048. NtToSmbQueryFileInfo[FileStreamInformation] = SMB_QUERY_FILE_STREAM_INFO;
  2049. NtToSmbQueryFileInfo[FilePipeInformation] = SMB_QUERY_FILE_INFO_PIPE_REQ;
  2050. NtToSmbQueryFileInfo[FilePipeLocalInformation] = SMB_QUERY_FILE_INFO_PIPE_REQ;
  2051. NtToSmbQueryFileInfo[FilePipeRemoteInformation] = SMB_QUERY_FILE_INFO_PIPE_REQ;
  2052. NtToSmbQueryFileInfo[FileCompressionInformation] = SMB_QUERY_FILE_COMPRESSION_INFO;
  2053. // end init
  2054. if (FileInformationClass < FileMaximumInformation) {
  2055. SmbFileInfoLevel = NtToSmbQueryFileInfo[FileInformationClass];
  2056. } else {
  2057. SmbFileInfoLevel = SMB_QUERY_FILE_INFO_INVALID_REQ;
  2058. }
  2059. if (SmbFileInfoLevel == SMB_QUERY_FILE_INFO_PIPE_REQ) {
  2060. //CODE.IMPROVEMENT the last thress params should not be passed...........
  2061. return MRxSmbQueryNamedPipeInformation(RxContext,FileInformationClass,pBuffer,pLengthRemaining);
  2062. } else if (SmbFileInfoLevel == SMB_QUERY_FILE_INFO_INVALID_REQ) {
  2063. RxDbgTrace( 0, Dbg, ("MRxSmbQueryFile: Invalid FS information class\n"));
  2064. Status = STATUS_INVALID_PARAMETER;
  2065. goto FINALLY;
  2066. }
  2067. */
  2068. if( FileInformationClass == FilePipeLocalInformation ||
  2069. FileInformationClass == FilePipeInformation ||
  2070. FileInformationClass == FilePipeRemoteInformation ) {
  2071. return MRxSmbQueryNamedPipeInformation(
  2072. RxContext,
  2073. FileInformationClass,
  2074. pBuffer,
  2075. pLengthRemaining);
  2076. }
  2077. Status = STATUS_SUCCESS;
  2078. switch (FileInformationClass) {
  2079. case FileEaInformation:
  2080. if (smbSrvOpen->IsNtCreate &&
  2081. smbSrvOpen->FileStatusFlags & SMB_FSF_NO_EAS &&
  2082. (smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_BATCH ||
  2083. smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_EXCLUSIVE)) {
  2084. PFILE_EA_INFORMATION EaBuffer = (PFILE_EA_INFORMATION)pBuffer;
  2085. if (RxContext->Info.LengthRemaining >= sizeof(FILE_EA_INFORMATION)) {
  2086. EaBuffer->EaSize = 0;
  2087. RxContext->Info.LengthRemaining -= sizeof(FILE_EA_INFORMATION);
  2088. } else {
  2089. Status = STATUS_BUFFER_TOO_SMALL;
  2090. }
  2091. goto FINALLY;
  2092. }
  2093. break;
  2094. case FileStreamInformation:
  2095. if (pSmbNetRoot->NetRootFileSystem == NET_ROOT_FILESYSTEM_FAT) {
  2096. // FAT doesn't have the stream
  2097. Status = STATUS_INVALID_PARAMETER;
  2098. goto FINALLY;
  2099. }
  2100. break;
  2101. case FileAttributeTagInformation:
  2102. if (pSmbNetRoot->NetRootFileSystem == NET_ROOT_FILESYSTEM_FAT ||
  2103. !(smbSrvOpen->FileInfo.Basic.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ||
  2104. smbSrvOpen->IsNtCreate &&
  2105. smbSrvOpen->FileStatusFlags & SMB_FSF_NO_REPARSETAG &&
  2106. (smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_BATCH ||
  2107. smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_EXCLUSIVE)) {
  2108. PFILE_ATTRIBUTE_TAG_INFORMATION TagBuffer = (PFILE_ATTRIBUTE_TAG_INFORMATION)pBuffer;
  2109. if (RxContext->Info.LengthRemaining >= sizeof(FILE_ATTRIBUTE_TAG_INFORMATION)) {
  2110. TagBuffer->FileAttributes = smbSrvOpen->FileInfo.Basic.FileAttributes;
  2111. TagBuffer->ReparseTag = 0;
  2112. RxContext->Info.LengthRemaining -= sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
  2113. } else {
  2114. Status = STATUS_BUFFER_TOO_SMALL;
  2115. }
  2116. goto FINALLY;
  2117. }
  2118. }
  2119. if( MRxSmbForceCoreInfo ||
  2120. !FlagOn( pServerEntry->Server.DialectFlags, DF_NT_INFO_PASSTHROUGH ) ||
  2121. MRxSmbIsThisADisconnectedOpen(capFobx->pSrvOpen)) {
  2122. switch (FileInformationClass) {
  2123. case FileBasicInformation:
  2124. SmbFileInfoLevel = SMB_QUERY_FILE_BASIC_INFO;
  2125. break;
  2126. case FileStandardInformation:
  2127. SmbFileInfoLevel = SMB_QUERY_FILE_STANDARD_INFO;
  2128. break;
  2129. case FileEaInformation:
  2130. SmbFileInfoLevel = SMB_QUERY_FILE_EA_INFO;
  2131. break;
  2132. case FileAllocationInformation:
  2133. SmbFileInfoLevel = SMB_QUERY_FILE_ALLOCATION_INFO;
  2134. break;
  2135. case FileEndOfFileInformation:
  2136. SmbFileInfoLevel = SMB_QUERY_FILE_END_OF_FILEINFO;
  2137. break;
  2138. case FileAlternateNameInformation:
  2139. SmbFileInfoLevel = SMB_QUERY_FILE_ALT_NAME_INFO;
  2140. break;
  2141. case FileStreamInformation:
  2142. SmbFileInfoLevel = SMB_QUERY_FILE_STREAM_INFO;
  2143. break;
  2144. case FileCompressionInformation:
  2145. SmbFileInfoLevel = SMB_QUERY_FILE_COMPRESSION_INFO;
  2146. break;
  2147. case FileInternalInformation:
  2148. {
  2149. PFILE_INTERNAL_INFORMATION UsersBuffer = (PFILE_INTERNAL_INFORMATION)pBuffer;
  2150. //
  2151. // Note: We use the address of the FCB to determine the
  2152. // index number of the file. If we have to maintain persistance between
  2153. // file opens for this request, then we might have to do something
  2154. // like checksuming the reserved fields on a FUNIQUE SMB response.
  2155. //
  2156. //
  2157. // NT64: the address of capFcb used to be stuffed into
  2158. // IndexNumber.LowPart, with HighPart being zeroed.
  2159. //
  2160. // Whoever is asking for this pointer value should be
  2161. // prepared to deal with the returned 64-bit value.
  2162. //
  2163. UsersBuffer->IndexNumber.QuadPart = (ULONG_PTR)capFcb;
  2164. *pLengthRemaining -= sizeof(FILE_INTERNAL_INFORMATION);
  2165. Status = STATUS_SUCCESS;
  2166. }
  2167. goto FINALLY;
  2168. default:
  2169. RxDbgTrace( 0, Dbg, ("MRxSmbQueryFile: Invalid FS information class\n"));
  2170. Status = STATUS_INVALID_PARAMETER;
  2171. goto FINALLY;
  2172. }
  2173. } else {
  2174. //
  2175. // This server supports transparent NT information level passthrough. So
  2176. // just pass the request on to the server.
  2177. //
  2178. SmbFileInfoLevel = FileInformationClass + SMB_INFO_PASSTHROUGH;
  2179. }
  2180. IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC{
  2181. NOTHING;
  2182. } else {
  2183. if (CscPerformOperationInDisconnectedMode(RxContext) ||
  2184. FlagOn(smbSrvOpen->Flags, SMB_SRVOPEN_FLAG_LOCAL_OPEN)){
  2185. NTSTATUS QFINtStatus;
  2186. QFINtStatus = MRxSmbDCscQueryFileInfo(RxContext);
  2187. if (QFINtStatus != STATUS_MORE_PROCESSING_REQUIRED) {
  2188. RxDbgTrace(0, Dbg,
  2189. ("MRxSmbQueryFileInformation returningDCON with status=%08lx\n",
  2190. QFINtStatus ));
  2191. Status = QFINtStatus;
  2192. goto FINALLY;
  2193. }
  2194. }
  2195. }
  2196. if (MRxSmbIsFileNotFoundCached(RxContext)) {
  2197. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  2198. RxDbgTrace( 0, Dbg, ("MRxSmbQueryFileInformation: FNF cached\n"));
  2199. goto FINALLY;
  2200. }
  2201. // Don't use cached information for the request from create against an aliased server
  2202. // so that we can be sure if it exists on the server.
  2203. if ((!pServerEntry->Server.AliasedServers ||
  2204. !FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_MINIRDR_INITIATED)) &&
  2205. (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN) ||
  2206. FlagOn(capFcb->FcbState,FCB_STATE_FILESIZECACHEING_ENABLED) ||
  2207. FileInformationClass == FileInternalInformation)) {
  2208. switch (FileInformationClass) {
  2209. case FileBasicInformation:
  2210. if (RxContext->Info.LengthRemaining >= sizeof(FILE_BASIC_INFORMATION)) {
  2211. if (MRxSmbIsBasicFileInfoCacheFound(RxContext,
  2212. (PFILE_BASIC_INFORMATION)pBuffer,
  2213. &Status,
  2214. NULL)) {
  2215. *pLengthRemaining -= sizeof(FILE_BASIC_INFORMATION);
  2216. RxDbgTrace( 0, Dbg, ("MRxSmbQueryFileInformation: Local Basic Info\n"));
  2217. return Status;
  2218. }
  2219. } else {
  2220. Status = STATUS_BUFFER_TOO_SMALL;
  2221. }
  2222. break;
  2223. case FileStandardInformation:
  2224. if (RxContext->Info.LengthRemaining >= sizeof(FILE_STANDARD_INFORMATION)) {
  2225. if (MRxSmbIsStandardFileInfoCacheFound(RxContext,
  2226. (PFILE_STANDARD_INFORMATION)pBuffer,
  2227. &Status,
  2228. NULL)) {
  2229. *pLengthRemaining -= sizeof(FILE_STANDARD_INFORMATION);
  2230. RxDbgTrace( 0, Dbg, ("MRxSmbQueryFileInformation: Local Standard Info\n"));
  2231. return Status;
  2232. }
  2233. } else {
  2234. Status = STATUS_BUFFER_TOO_SMALL;
  2235. }
  2236. break;
  2237. case FileEndOfFileInformation:
  2238. if (RxContext->Info.LengthRemaining >= sizeof(FILE_END_OF_FILE_INFORMATION)) {
  2239. FILE_STANDARD_INFORMATION Standard;
  2240. if (MRxSmbIsStandardFileInfoCacheFound(RxContext,
  2241. &Standard,
  2242. &Status,
  2243. NULL)){
  2244. ((PFILE_END_OF_FILE_INFORMATION)pBuffer)->EndOfFile.QuadPart = Standard.EndOfFile.QuadPart;
  2245. *pLengthRemaining -= sizeof(FILE_END_OF_FILE_INFORMATION);
  2246. RxDbgTrace( 0, Dbg, ("MRxSmbQueryFileInformation: Local EndOfFile Info\n"));
  2247. return Status;
  2248. }
  2249. } else {
  2250. Status = STATUS_BUFFER_TOO_SMALL;
  2251. }
  2252. break;
  2253. case FileInternalInformation:
  2254. if (RxContext->Info.LengthRemaining >= sizeof(FILE_INTERNAL_INFORMATION)) {
  2255. if (MRxSmbIsInternalFileInfoCacheFound(RxContext,
  2256. (PFILE_INTERNAL_INFORMATION)pBuffer,
  2257. &Status,
  2258. NULL)){
  2259. *pLengthRemaining -= sizeof(FILE_INTERNAL_INFORMATION);
  2260. RxDbgTrace( 0, Dbg, ("MRxSmbQueryFileInformation: Local Internal Info\n"));
  2261. return Status;
  2262. }
  2263. } else {
  2264. Status = STATUS_BUFFER_TOO_SMALL;
  2265. }
  2266. break;
  2267. }
  2268. }
  2269. // The crux of being here is:
  2270. // If somebody deleted a file that's in the Dir Cache, FnotF will have had
  2271. // a note of it. Well, if somebody had created a file that was previously
  2272. // deleted, the basic-info cache above would have that. So, we'll serve
  2273. // files that have not been tinkered with and that are fresh QPIs. Neat.
  2274. // Also, since this cache is hidden behind the above, we don't need to update
  2275. // basic info on create path!!
  2276. if ((MRxSmbNonTrivialFileName(RxContext)) &&
  2277. (!pServerEntry->Server.AliasedServers) &&
  2278. (FileInformationClass== FileBasicInformation) &&
  2279. // (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_MINIRDR_INITIATED)) &&
  2280. // (FileInformationClass != FileInternalInformation) &&
  2281. TRUE) {
  2282. // So what if this is MiniRdr initiated. We have a valid dir cache
  2283. // and we are going to look through it. This is ok for File_not_found.
  2284. // But not for serving attributes.
  2285. BOOLEAN FileFound = FALSE;
  2286. if ( MRxSmbIsFileInFullDirectoryCache(RxContext, &FileFound,
  2287. (PFILE_BASIC_INFORMATION) pBuffer) ) {
  2288. if ( !(FileFound) ) {
  2289. RxDbgTrace( 0, Dbg, ("QueryPathInfo OBJ_NOT_FOUND Saved :%wZ:\n",RemainingName));
  2290. SmbLog(LOG,MRxSmbQPINFSaved,
  2291. LOGUSTR(*RemainingName));
  2292. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  2293. goto AHEAD_OF_CACHE;
  2294. } else {
  2295. // CODE.IMPROVEMENT
  2296. // If we need to serve Basic or Std. attributes from the
  2297. // cache, we need to let MiniRdr-Initiated calls fall through
  2298. // Also, we need to pay heed to NAMES_INFO_ONLY flag and use
  2299. // only if not set.
  2300. // We can't serve if (FileInformationClass == FileInternalInformation),
  2301. *pLengthRemaining -= sizeof(FILE_BASIC_INFORMATION);
  2302. RxDbgTrace( 0, Dbg, ("QueryBasicInfo to Server Saved :%wZ:\n",RemainingName));
  2303. SmbLog(LOG,MRxSmbQueryBasicInfoSaved,
  2304. LOGUSTR(*RemainingName));
  2305. Status = STATUS_SUCCESS;
  2306. goto AHEAD_OF_CACHE;
  2307. }
  2308. }
  2309. }
  2310. if (MRxSmbForceCoreInfo ||
  2311. FlagOn(pServerEntry->Server.DialectFlags,DF_W95) ||
  2312. !FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
  2313. // Win9x server supports NT SMB but doesn't support transact2. Therefore we use core.
  2314. BufferLength = *pLengthRemaining;
  2315. Status = MRxSmbCoreInformation(
  2316. RxContext,
  2317. (ULONG)SmbFileInfoLevel,
  2318. pBuffer,
  2319. pLengthRemaining,
  2320. SMBPSE_OE_FROM_QUERYFILEINFO
  2321. );
  2322. if( NT_SUCCESS( Status ) ) {
  2323. Status = FsRtlValidateFileInformationBuffer( FileInformationClass, pBuffer, BufferLength );
  2324. return Status;
  2325. }
  2326. }
  2327. Status = STATUS_SUCCESS;
  2328. if (!FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  2329. //here, the FID is valid. do a t2_QFI
  2330. Setup = TRANS2_QUERY_FILE_INFORMATION;
  2331. QueryFileInfoRequest.Fid = smbSrvOpen->Fid;
  2332. QueryFileInfoRequest.InformationLevel = SmbFileInfoLevel;
  2333. pSendParameterBuffer = &QueryFileInfoRequest;
  2334. SendParameterBufferLength = sizeof(QueryFileInfoRequest);
  2335. RxDbgTrace(0, Dbg, (" fid,smbclass=%08lx,%08lx\n",smbSrvOpen->Fid,SmbFileInfoLevel));
  2336. } else {
  2337. OEM_STRING OemName;
  2338. BOOLEAN FreeOemName = FALSE;
  2339. Setup = TRANS2_QUERY_PATH_INFORMATION;
  2340. if (!FlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE)) {
  2341. if (FlagOn(pServerEntry->Server.DialectFlags,DF_LONGNAME)) {
  2342. Status = RtlUnicodeStringToOemString(&OemName, RemainingName, TRUE);
  2343. } else {
  2344. Status = RtlUpcaseUnicodeStringToOemString(&OemName, RemainingName, TRUE);
  2345. }
  2346. if (Status == STATUS_SUCCESS) {
  2347. SendParameterBufferLength = FIELD_OFFSET(REQ_QUERY_PATH_INFORMATION,Buffer[0])
  2348. + OemName.Length + sizeof(CHAR); //null-terminated
  2349. FreeOemName = TRUE;
  2350. }
  2351. } else {
  2352. SendParameterBufferLength = FIELD_OFFSET(REQ_QUERY_PATH_INFORMATION,Buffer[0])
  2353. + RemainingName->Length + sizeof(WCHAR); //null-terminated
  2354. }
  2355. if (Status == STATUS_SUCCESS) {
  2356. pSendParameterBuffer = RxAllocatePoolWithTag(PagedPool,
  2357. SendParameterBufferLength,
  2358. MRXSMB_QPINFO_POOLTAG);
  2359. pQueryFilePathRequest = pSendParameterBuffer;
  2360. if (pQueryFilePathRequest != NULL) {
  2361. pQueryFilePathRequest->InformationLevel = SmbFileInfoLevel;
  2362. SmbPutUlong(&pQueryFilePathRequest->Reserved,0);
  2363. if (FlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE)) {
  2364. RtlCopyMemory(&pQueryFilePathRequest->Buffer[0],RemainingName->Buffer,RemainingName->Length);
  2365. *((PWCHAR)(&pQueryFilePathRequest->Buffer[RemainingName->Length])) = 0;
  2366. } else {
  2367. RtlCopyMemory(&pQueryFilePathRequest->Buffer[0],OemName.Buffer,OemName.Length);
  2368. *((PCHAR)(&pQueryFilePathRequest->Buffer[OemName.Length])) = 0;
  2369. }
  2370. } else {
  2371. Status = STATUS_INSUFFICIENT_RESOURCES;
  2372. }
  2373. }
  2374. if (FreeOemName) {
  2375. RtlFreeOemString(&OemName);
  2376. }
  2377. }
  2378. if (Status == STATUS_SUCCESS) {
  2379. Status = SmbCeTransact(
  2380. RxContext,
  2381. pTransactionOptions,
  2382. &Setup,
  2383. sizeof(Setup),
  2384. NULL,
  2385. 0,
  2386. pSendParameterBuffer,
  2387. SendParameterBufferLength,
  2388. &QueryFileInfoResponse,
  2389. sizeof(QueryFileInfoResponse),
  2390. NULL,
  2391. 0,
  2392. pBuffer,
  2393. *pLengthRemaining,
  2394. &ResumptionContext);
  2395. if ( NT_SUCCESS( Status ) ) {
  2396. Status = FsRtlValidateFileInformationBuffer( FileInformationClass, pBuffer, *pLengthRemaining );
  2397. }
  2398. if ( NT_SUCCESS( Status ) ) {
  2399. *pLengthRemaining -= ResumptionContext.DataBytesReceived;
  2400. }
  2401. }
  2402. //
  2403. // Check for file not found status. If this is the case then create a
  2404. // name cache entry in the NetRoot name cache and record the status,
  2405. // the smb received count and set the expiration time for 5 seconds.
  2406. // Why: NB4 case of back to back srv reqs with 2nd req upcased.
  2407. //
  2408. AHEAD_OF_CACHE:
  2409. if (NT_SUCCESS(Status)) {
  2410. //
  2411. // The request succeeded so free up the name cache entry.
  2412. //
  2413. MRxSmbInvalidateFileNotFoundCache(RxContext);
  2414. // cache the file info returned from the server.
  2415. switch (FileInformationClass) {
  2416. case FileBasicInformation:
  2417. MRxSmbCreateBasicFileInfoCache(RxContext,
  2418. (PFILE_BASIC_INFORMATION)pBuffer,
  2419. pServerEntry,
  2420. Status);
  2421. break;
  2422. case FileStandardInformation:
  2423. if (FlagOn(capFcb->FcbState,FCB_STATE_WRITEBUFFERING_ENABLED) &&
  2424. !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  2425. PFILE_STANDARD_INFORMATION Standard = (PFILE_STANDARD_INFORMATION)pBuffer;
  2426. RxGetFileSizeWithLock((PFCB)capFcb,&Standard->EndOfFile.QuadPart);
  2427. }
  2428. MRxSmbCreateStandardFileInfoCache(RxContext,
  2429. (PFILE_STANDARD_INFORMATION)pBuffer,
  2430. pServerEntry,
  2431. Status);
  2432. break;
  2433. case FileEndOfFileInformation:
  2434. MRxSmbUpdateFileInfoCacheFileSize(RxContext,
  2435. &((PFILE_END_OF_FILE_INFORMATION)pBuffer)->EndOfFile);
  2436. break;
  2437. case FileInternalInformation:
  2438. MRxSmbCreateInternalFileInfoCache(RxContext,
  2439. (PFILE_INTERNAL_INFORMATION)pBuffer,
  2440. pServerEntry,
  2441. Status);
  2442. break;
  2443. }
  2444. } else {
  2445. if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
  2446. Status == STATUS_OBJECT_PATH_NOT_FOUND) {
  2447. // create the name based file not found cache
  2448. MRxSmbCacheFileNotFound(RxContext);
  2449. } else {
  2450. // invalid the name based file not found cache if other error happens
  2451. MRxSmbInvalidateFileNotFoundCache(RxContext);
  2452. }
  2453. // invalid the name based file info cache
  2454. MRxSmbInvalidateFileInfoCache(RxContext);
  2455. // Trounce FullDir Cache
  2456. RxDbgTrace( 0, Dbg, ("TROUNCE from SetFileInfo\n"));
  2457. SmbLog(LOG,MRxSmbTrounceSetFileInfo,LOGNOTHING);
  2458. MRxSmbInvalidateFullDirectoryCacheParent(RxContext, FALSE);
  2459. }
  2460. FINALLY:
  2461. if (pQueryFilePathRequest != NULL) {
  2462. RxFreePool(pQueryFilePathRequest);
  2463. }
  2464. if (!NT_SUCCESS(Status)) {
  2465. RxDbgTrace( 0, Dbg, ("MRxSmbQueryFile: Failed .. returning %lx\n",Status));
  2466. }
  2467. RxDbgTraceUnIndent(-1,Dbg);
  2468. return Status;
  2469. }
  2470. NTSTATUS
  2471. MRxSmbQueryFileInformationFromPseudoOpen(
  2472. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
  2473. FILE_INFORMATION_CLASS FileInformationClass
  2474. )
  2475. /*++
  2476. Routine Description:
  2477. This routine does a query file basic info from pseudo open.
  2478. Arguments:
  2479. RxContext - the RDBSS context
  2480. Return Value:
  2481. NTSTATUS - The return status for the operation
  2482. --*/
  2483. {
  2484. NTSTATUS Status;
  2485. PRX_CONTEXT LocalRxContext;
  2486. PAGED_CODE();
  2487. LocalRxContext = RxAllocatePoolWithTag(NonPagedPool,
  2488. sizeof(RX_CONTEXT),
  2489. MRXSMB_RXCONTEXT_POOLTAG);
  2490. if (LocalRxContext == NULL) {
  2491. Status = STATUS_INSUFFICIENT_RESOURCES;
  2492. } else {
  2493. RtlZeroMemory(
  2494. LocalRxContext,
  2495. sizeof(RX_CONTEXT));
  2496. RxInitializeContext(
  2497. NULL,
  2498. RxContext->RxDeviceObject,
  2499. 0,
  2500. LocalRxContext );
  2501. LocalRxContext->pFcb = RxContext->pFcb;
  2502. LocalRxContext->pFobx = RxContext->pFobx;
  2503. LocalRxContext->CurrentIrp = RxContext->CurrentIrp;
  2504. LocalRxContext->CurrentIrpSp = RxContext->CurrentIrpSp;
  2505. LocalRxContext->NonPagedFcb = RxContext->NonPagedFcb;
  2506. LocalRxContext->MajorFunction = IRP_MJ_CREATE;
  2507. LocalRxContext->pRelevantSrvOpen = RxContext->pRelevantSrvOpen;;
  2508. LocalRxContext->Flags = RX_CONTEXT_FLAG_MINIRDR_INITIATED|RX_CONTEXT_FLAG_WAIT|RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
  2509. switch (FileInformationClass) {
  2510. case FileBasicInformation:
  2511. LocalRxContext->Info.LengthRemaining = sizeof(FILE_BASIC_INFORMATION);
  2512. LocalRxContext->Info.Buffer = &OrdinaryExchange->Create.FileInfo.Basic;
  2513. break;
  2514. case FileInternalInformation:
  2515. LocalRxContext->Info.LengthRemaining = sizeof(FILE_INTERNAL_INFORMATION);
  2516. LocalRxContext->Info.Buffer = &OrdinaryExchange->Create.FileInfo.Internal;
  2517. //DbgPrint("Query file internal information from create\n");
  2518. break;
  2519. }
  2520. LocalRxContext->Info.FileInformationClass = FileInformationClass;
  2521. LocalRxContext->Create = RxContext->Create;
  2522. Status = MRxSmbQueryFileInformation(LocalRxContext);
  2523. RxFreePool(LocalRxContext);
  2524. }
  2525. if ((Status == STATUS_SUCCESS) &&
  2526. (FileInformationClass == FileBasicInformation)) {
  2527. OrdinaryExchange->Create.FileInfo.Standard.Directory =
  2528. BooleanFlagOn(OrdinaryExchange->Create.FileInfo.Basic.FileAttributes,FILE_ATTRIBUTE_DIRECTORY);
  2529. OrdinaryExchange->Create.StorageTypeFromGFA =
  2530. OrdinaryExchange->Create.FileInfo.Standard.Directory ?
  2531. FileTypeDirectory : FileTypeFile;
  2532. }
  2533. return Status;
  2534. }
  2535. typedef enum _INTERESTING_SFI_FOLLOWONS {
  2536. SFI_FOLLOWON_NOTHING,
  2537. SFI_FOLLOWON_DISPOSITION_SENT
  2538. } INTERESTING_SFI_FOLLOWONS;
  2539. NTSTATUS
  2540. MRxSmbSetFileInformation (
  2541. IN PRX_CONTEXT RxContext
  2542. )
  2543. /*++
  2544. Routine Description:
  2545. This routine does a set file info. Only the NT-->NT path is implemented.
  2546. The NT-->NT path works by just remoting the call basically without further ado.
  2547. The file is not really open if it is created for delete. In this case, set dispostion info
  2548. will be delayed until file is closed.
  2549. Arguments:
  2550. RxContext - the RDBSS context
  2551. Return Value:
  2552. RXSTATUS - The return status for the operation
  2553. --*/
  2554. {
  2555. NTSTATUS Status = STATUS_SUCCESS;
  2556. RxCaptureFcb;
  2557. RxCaptureFobx;
  2558. FILE_INFORMATION_CLASS FileInformationClass;
  2559. PVOID pBuffer;
  2560. ULONG BufferLength;
  2561. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  2562. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  2563. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  2564. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  2565. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)SrvOpen->pVNetRoot->Context;
  2566. PSMBCE_NET_ROOT pSmbNetRoot = &pVNetRootContext->pNetRootEntry->NetRoot;
  2567. PSMBCEDB_SERVER_ENTRY pServerEntry;
  2568. USHORT SmbFileInfoLevel;
  2569. USHORT Setup;
  2570. INTERESTING_SFI_FOLLOWONS FollowOn = SFI_FOLLOWON_NOTHING;
  2571. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  2572. PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
  2573. REQ_SET_FILE_INFORMATION SetFileInfoRequest;
  2574. RESP_SET_FILE_INFORMATION SetFileInfoResponse;
  2575. PREQ_SET_PATH_INFORMATION pSetFilePathRequest = NULL;
  2576. PVOID pSendParameterBuffer;
  2577. ULONG SendParameterBufferLength;
  2578. BOOLEAN fDoneCSCPart=FALSE;
  2579. BOOLEAN UseCore = FALSE;
  2580. PAGED_CODE();
  2581. TURN_BACK_ASYNCHRONOUS_OPERATIONS();
  2582. FileInformationClass = RxContext->Info.FileInformationClass;
  2583. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  2584. pBuffer = RxContext->Info.Buffer;
  2585. BufferLength = RxContext->Info.Length;
  2586. RxDbgTrace(+1, Dbg, ("MRxSmbSetFile: Class %08lx size %08lx\n",FileInformationClass,BufferLength));
  2587. IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC{
  2588. NOTHING;
  2589. } else {
  2590. if (CscPerformOperationInDisconnectedMode(RxContext)){
  2591. NTSTATUS SFINtStatus;
  2592. SFINtStatus = MRxSmbDCscSetFileInfo(RxContext);
  2593. fDoneCSCPart = TRUE;
  2594. if (SFINtStatus != STATUS_MORE_PROCESSING_REQUIRED) {
  2595. RxDbgTrace(0, Dbg,
  2596. ("MRxSmbSetFileInformation returningDCON with status=%08lx\n",
  2597. SFINtStatus ));
  2598. #ifdef LocalOpen
  2599. if (FlagOn(smbSrvOpen->Flags, SMB_SRVOPEN_FLAG_LOCAL_OPEN)) {
  2600. switch( FileInformationClass ) {
  2601. case FileRenameInformation:
  2602. MRxSmbRename( RxContext );
  2603. break;
  2604. }
  2605. }
  2606. #endif
  2607. Status = SFINtStatus;
  2608. goto FINALLY;
  2609. } else {
  2610. NOTHING;
  2611. }
  2612. }
  2613. else if (FileInformationClass == FileDispositionInformation)
  2614. {
  2615. if(CSCCheckLocalOpens(RxContext))
  2616. {
  2617. // disallow deletes if there are local open on this file
  2618. // This happens only on a VDO marked share
  2619. Status = STATUS_ACCESS_DENIED;
  2620. goto FINALLY;
  2621. }
  2622. }
  2623. }
  2624. RxDbgTrace( 0, Dbg, ("Check FNOTF from SetFileInfo :%wZ:\n", GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext)));
  2625. SmbLog(LOG,MRxSmbCheckFNOTFFromSFI,
  2626. LOGUSTR(*GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext)));
  2627. if (MRxSmbIsFileNotFoundCached(RxContext)) {
  2628. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  2629. RxDbgTrace( 0, Dbg, ("MRxSmbSetFileInformation: FNF cached\n"));
  2630. goto FINALLY;
  2631. }
  2632. if (FileInformationClass != FileBasicInformation &&
  2633. FileInformationClass != FileDispositionInformation &&
  2634. FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  2635. Status = MRxSmbDeferredCreate(RxContext);
  2636. if (Status != STATUS_SUCCESS) {
  2637. goto FINALLY;
  2638. }
  2639. }
  2640. if( FileInformationClass == FilePipeLocalInformation ||
  2641. FileInformationClass == FilePipeInformation ||
  2642. FileInformationClass == FilePipeRemoteInformation ) {
  2643. return MRxSmbSetNamedPipeInformation(
  2644. RxContext,
  2645. FileInformationClass,
  2646. pBuffer,
  2647. BufferLength);
  2648. }
  2649. if (!MRxSmbForceCoreInfo &&
  2650. !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN) &&
  2651. FlagOn( pServerEntry->Server.DialectFlags, DF_NT_INFO_PASSTHROUGH)) {
  2652. SmbFileInfoLevel = FileInformationClass + SMB_INFO_PASSTHROUGH;
  2653. if( FileInformationClass == FileRenameInformation ) {
  2654. PFILE_RENAME_INFORMATION pRenameInformation;
  2655. // The current implementation of pass through for rename information
  2656. // on the server does not go all the way in implementing the
  2657. // NT_TRANSACT, NT_RENAME function defined in SMBs. Therefore we need
  2658. // to special case the code to accomodate the server implementation
  2659. // The two cases that are not permitted are relative renames,
  2660. // specifying a non null root directory and deep renames which
  2661. // transcend the current directory structure. For these cases we will
  2662. // have to revert back to what we had before.
  2663. pRenameInformation = (PFILE_RENAME_INFORMATION)pBuffer;
  2664. if (pRenameInformation->RootDirectory == NULL) {
  2665. // Scan the name given for rename to determine if it is in
  2666. // some other directory.
  2667. ULONG NameLengthInBytes = pRenameInformation->FileNameLength;
  2668. PWCHAR pRenameTarget = pRenameInformation->FileName;
  2669. while ((NameLengthInBytes > 0) &&
  2670. (*pRenameTarget != OBJ_NAME_PATH_SEPARATOR)) {
  2671. NameLengthInBytes -= sizeof(WCHAR);
  2672. }
  2673. if (NameLengthInBytes > 0) {
  2674. UseCore = TRUE;
  2675. }
  2676. } else {
  2677. UseCore = TRUE;
  2678. }
  2679. #ifdef _WIN64
  2680. // Don't thunk the data if we're going to take the downlevel path (since the data will be mapped into an SMB_RENAME
  2681. if( !(UseCore ||
  2682. MRxSmbForceCoreInfo ||
  2683. !FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS) ||
  2684. FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) )
  2685. {
  2686. PBYTE pNewBuffer = Smb64ThunkFileRenameInfo( pRenameInformation, &BufferLength, &Status );
  2687. if( !NT_SUCCESS(Status) )
  2688. {
  2689. goto FINALLY;
  2690. }
  2691. else
  2692. {
  2693. pBuffer = pNewBuffer;
  2694. }
  2695. }
  2696. #endif
  2697. }
  2698. if (FileInformationClass == FileLinkInformation) {
  2699. UseCore = TRUE;
  2700. }
  2701. } else {
  2702. switch( FileInformationClass ) {
  2703. case FileBasicInformation:
  2704. SmbFileInfoLevel = SMB_SET_FILE_BASIC_INFO;
  2705. break;
  2706. case FileDispositionInformation:
  2707. SmbFileInfoLevel = SMB_SET_FILE_DISPOSITION_INFO;
  2708. break;
  2709. case FileAllocationInformation:
  2710. SmbFileInfoLevel = SMB_SET_FILE_ALLOCATION_INFO;
  2711. break;
  2712. case FileEndOfFileInformation:
  2713. SmbFileInfoLevel = SMB_SET_FILE_END_OF_FILE_INFO;
  2714. break;
  2715. case FileLinkInformation:
  2716. case FileRenameInformation:
  2717. UseCore = TRUE;
  2718. break;
  2719. default:
  2720. Status = STATUS_INVALID_PARAMETER;
  2721. goto FINALLY;
  2722. }
  2723. }
  2724. if (UseCore ||
  2725. MRxSmbForceCoreInfo ||
  2726. !FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS) ||
  2727. FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  2728. if (FileInformationClass == FileLinkInformation ||
  2729. FileInformationClass == FileRenameInformation) {
  2730. Status = MRxSmbBypassDownLevelRename ?
  2731. STATUS_INVALID_PARAMETER :
  2732. MRxSmbRename( RxContext );
  2733. } else {
  2734. Status = MRxSmbCoreInformation(
  2735. RxContext,
  2736. FileInformationClass,
  2737. pBuffer,
  2738. &BufferLength,
  2739. SMBPSE_OE_FROM_SETFILEINFO
  2740. );
  2741. }
  2742. goto FINALLY;
  2743. }
  2744. Setup = TRANS2_SET_FILE_INFORMATION;
  2745. SetFileInfoRequest.Fid = smbSrvOpen->Fid;
  2746. SetFileInfoRequest.InformationLevel = SmbFileInfoLevel;
  2747. SetFileInfoRequest.Flags = 0;
  2748. pSendParameterBuffer = &SetFileInfoRequest;
  2749. SendParameterBufferLength = sizeof(SetFileInfoRequest);
  2750. RxDbgTrace(0, Dbg, (" fid,smbclass=%08lx,%08lx\n",smbSrvOpen->Fid,SmbFileInfoLevel));
  2751. Status = SmbCeTransact(
  2752. RxContext,
  2753. pTransactionOptions,
  2754. &Setup,
  2755. sizeof(Setup),
  2756. NULL,
  2757. 0,
  2758. pSendParameterBuffer,
  2759. SendParameterBufferLength,
  2760. &SetFileInfoResponse,
  2761. sizeof(SetFileInfoResponse),
  2762. pBuffer,
  2763. BufferLength,
  2764. NULL,
  2765. 0,
  2766. &ResumptionContext);
  2767. if (Status == STATUS_SUCCESS &&
  2768. (FileInformationClass == FileRenameInformation ||
  2769. FileInformationClass == FileDispositionInformation)) {
  2770. // create the name based file not found cache
  2771. MRxSmbCacheFileNotFound(RxContext);
  2772. // invalidate the name based file info cache
  2773. MRxSmbInvalidateFileInfoCache(RxContext);
  2774. MRxSmbInvalidateInternalFileInfoCache(RxContext);
  2775. // Trounce FullDir Cache
  2776. RxDbgTrace( 0, Dbg, ("TROUNCE from SetFileInfo\n"));
  2777. SmbLog(LOG,MRxSmbTrounceSetFileInfo,LOGNOTHING);
  2778. MRxSmbInvalidateFullDirectoryCacheParent(RxContext, FALSE);
  2779. if (FileInformationClass == FileDispositionInformation) {
  2780. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  2781. SetFlag((((PMRX_SMB_FCB)smbFcb)->MFlags),SMB_FCB_FLAG_SENT_DISPOSITION_INFO);
  2782. SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_FILE_DELETED);
  2783. } else if( FileInformationClass == FileRenameInformation) {
  2784. MRxSmbInvalidateFileNotFoundCacheForRename(RxContext);
  2785. MRxSmbInvalidateFullDirectoryCacheParentForRename(RxContext, FALSE);
  2786. }
  2787. }
  2788. FINALLY:
  2789. if (NT_SUCCESS(Status)) {
  2790. switch(FileInformationClass) {
  2791. case FileBasicInformation:
  2792. if (pServerEntry->Server.Dialect == NTLANMAN_DIALECT &&
  2793. pSmbNetRoot->NetRootFileSystem == NET_ROOT_FILESYSTEM_NTFS) {
  2794. MRxSmbUpdateBasicFileInfoCacheAll(RxContext,
  2795. (PFILE_BASIC_INFORMATION)pBuffer);
  2796. } else {
  2797. // some file system, i.e. FAT, has the time stamp with granularity of 2 seconds.
  2798. // RDR cannot predict what the time stamp on the server, therefore invalid the cache
  2799. MRxSmbInvalidateBasicFileInfoCache(RxContext);
  2800. }
  2801. break;
  2802. case FileEndOfFileInformation:
  2803. MRxSmbUpdateFileInfoCacheFileSize(RxContext,
  2804. &((PFILE_END_OF_FILE_INFORMATION)pBuffer)->EndOfFile);
  2805. break;
  2806. case FileStandardInformation:
  2807. MRxSmbUpdateStandardFileInfoCache(RxContext,
  2808. (PFILE_STANDARD_INFORMATION)pBuffer,
  2809. FALSE);
  2810. break;
  2811. case FileEaInformation:
  2812. smbSrvOpen->FileStatusFlags &= ~SMB_FSF_NO_EAS;
  2813. break;
  2814. case FileAttributeTagInformation:
  2815. smbSrvOpen->FileStatusFlags &= ~SMB_FSF_NO_REPARSETAG;
  2816. break;
  2817. #ifdef _WIN64
  2818. case FileRenameInformation:
  2819. // Clean up the Thunk data if necessary
  2820. if( pBuffer != RxContext->Info.Buffer )
  2821. {
  2822. Smb64ReleaseThunkData( pBuffer );
  2823. pBuffer = RxContext->Info.Buffer;
  2824. }
  2825. break;
  2826. #endif
  2827. }
  2828. } else {
  2829. #ifdef _WIN64
  2830. // Clean up the Thunk data if necessary
  2831. if(FileInformationClass == FileRenameInformation) {
  2832. if( pBuffer != RxContext->Info.Buffer )
  2833. {
  2834. Smb64ReleaseThunkData( pBuffer );
  2835. pBuffer = RxContext->Info.Buffer;
  2836. }
  2837. }
  2838. #endif
  2839. if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
  2840. Status == STATUS_OBJECT_PATH_NOT_FOUND) {
  2841. // create the name based file not found cache
  2842. MRxSmbCacheFileNotFound(RxContext);
  2843. } else {
  2844. // invalid the name based file not found cache if other error happens
  2845. MRxSmbInvalidateFileNotFoundCache(RxContext);
  2846. }
  2847. // invalid the name based file info cache
  2848. MRxSmbInvalidateFileInfoCache(RxContext);
  2849. // Trounce FullDir Cache
  2850. RxDbgTrace( 0, Dbg, ("TROUNCE from SetFileInfo\n"));
  2851. SmbLog(LOG,MRxSmbTrounceSetFileInfo,LOGNOTHING);
  2852. MRxSmbInvalidateFullDirectoryCacheParent(RxContext, FALSE);
  2853. RxDbgTrace( 0, Dbg, ("MRxSmbSetFile: Failed .. returning %lx\n",Status));
  2854. }
  2855. // update shadow as appropriate. This needs to be done only for NT servers
  2856. // since pinning/CSC is not supported against non NT servers.
  2857. IF_NOT_MRXSMB_CSC_ENABLED{
  2858. ASSERT(MRxSmbGetSrvOpenExtension(SrvOpen)->hfShadow == 0);
  2859. } else {
  2860. if (!fDoneCSCPart) {
  2861. if (FileInformationClass == FileRenameInformation) {
  2862. MRxSmbCscRenameEpilogue(RxContext,&Status);
  2863. } else {
  2864. MRxSmbCscSetFileInfoEpilogue(RxContext, &Status);
  2865. }
  2866. }
  2867. }
  2868. RxDbgTraceUnIndent(-1,Dbg);
  2869. return Status;
  2870. }
  2871. NTSTATUS
  2872. MRxSmbQueryNamedPipeInformation(
  2873. IN PRX_CONTEXT RxContext,
  2874. IN FILE_INFORMATION_CLASS FileInformationClass,
  2875. IN OUT PVOID pBuffer,
  2876. IN OUT PULONG pLengthRemaining)
  2877. {
  2878. RxCaptureFobx;
  2879. PMRX_SMB_SRV_OPEN pSmbSrvOpen;
  2880. NTSTATUS Status;
  2881. USHORT Setup[2];
  2882. USHORT Level;
  2883. PBYTE pInputDataBuffer = NULL;
  2884. PBYTE pOutputParamBuffer = NULL;
  2885. PBYTE pOutputDataBuffer = NULL;
  2886. ULONG OutputParamBufferLength = 0;
  2887. ULONG InputDataBufferLength = 0;
  2888. ULONG OutputDataBufferLength = 0;
  2889. ULONG SmbPipeInformationLength;
  2890. PNAMED_PIPE_INFORMATION_1 pSmbPipeInformation;
  2891. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  2892. SMB_TRANSACTION_OPTIONS TransactionOptions;
  2893. PAGED_CODE();
  2894. if (*pLengthRemaining < sizeof(FILE_PIPE_LOCAL_INFORMATION)) {
  2895. return STATUS_BUFFER_TOO_SMALL;
  2896. }
  2897. if (capFobx == NULL) {
  2898. return STATUS_INVALID_PARAMETER;
  2899. }
  2900. pSmbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
  2901. // The SMB data structures defines a response that is significantly different from the
  2902. // FILE_PIPE_LOCAL_INFORMATION data structures. This mismatch is resolved by obtaining
  2903. // the SMB results in a different buffer and then copying the relevant pieces of
  2904. // information onto the query information buffer. SInce the SMB definition involves the
  2905. // pipe name as well a buffer that is large enough to hold the path name needs to be
  2906. // defined.
  2907. SmbPipeInformationLength = sizeof(NAMED_PIPE_INFORMATION_1) +
  2908. MAXIMUM_FILENAME_LENGTH;
  2909. pSmbPipeInformation = RxAllocatePoolWithTag(
  2910. PagedPool,
  2911. SmbPipeInformationLength,
  2912. MRXSMB_PIPEINFO_POOLTAG);
  2913. if (pSmbPipeInformation == NULL) {
  2914. return STATUS_INSUFFICIENT_RESOURCES;
  2915. }
  2916. Setup[0] = TRANS_QUERY_NMPIPE_INFO;
  2917. Setup[1] = pSmbSrvOpen->Fid;
  2918. Level = 1; // Information Level Desired
  2919. TransactionOptions = RxDefaultTransactionOptions;
  2920. TransactionOptions.pTransactionName = &s_NamedPipeTransactionName;
  2921. Status = SmbCeTransact(
  2922. RxContext, // the RXContext for the transaction
  2923. &TransactionOptions, // transaction options
  2924. Setup, // the setup buffer
  2925. sizeof(Setup), // setup buffer length
  2926. NULL,
  2927. 0,
  2928. &Level, // Input Param Buffer
  2929. sizeof(Level), // Input param buffer length
  2930. pOutputParamBuffer, // Output param buffer
  2931. OutputParamBufferLength, // output param buffer length
  2932. pInputDataBuffer, // Input data buffer
  2933. InputDataBufferLength, // Input data buffer length
  2934. pSmbPipeInformation, // output data buffer
  2935. SmbPipeInformationLength, // output data buffer length
  2936. &ResumptionContext // the resumption context
  2937. );
  2938. if (NT_SUCCESS(Status)) {
  2939. PFILE_PIPE_LOCAL_INFORMATION pFilePipeInformation = (PFILE_PIPE_LOCAL_INFORMATION)pBuffer;
  2940. // MaximumInstances and CurrentInstances are UCHAR fields ...
  2941. pFilePipeInformation->MaximumInstances = (ULONG)pSmbPipeInformation->MaximumInstances;
  2942. pFilePipeInformation->CurrentInstances = (ULONG)pSmbPipeInformation->CurrentInstances;
  2943. pFilePipeInformation->InboundQuota = SmbGetUshort(&pSmbPipeInformation->InputBufferSize);
  2944. pFilePipeInformation->ReadDataAvailable = 0xffffffff;
  2945. pFilePipeInformation->OutboundQuota = SmbGetUshort(&pSmbPipeInformation->OutputBufferSize);
  2946. pFilePipeInformation->WriteQuotaAvailable = 0xffffffff;
  2947. pFilePipeInformation->NamedPipeState = FILE_PIPE_CONNECTED_STATE;// Since no error
  2948. pFilePipeInformation->NamedPipeEnd = FILE_PIPE_CLIENT_END;
  2949. RxDbgTrace( 0, Dbg, ("MRxSmbQueryNamedPipeInformation: Pipe Name .. %s\n",pSmbPipeInformation->PipeName));
  2950. *pLengthRemaining -= sizeof(FILE_PIPE_LOCAL_INFORMATION);
  2951. }
  2952. RxFreePool(pSmbPipeInformation);
  2953. RxDbgTrace( 0, Dbg, ("MRxSmbQueryNamedPipeInformation: ...returning %lx\n",Status));
  2954. return Status;
  2955. }
  2956. NTSTATUS
  2957. MRxSmbSetNamedPipeInformation(
  2958. IN PRX_CONTEXT RxContext,
  2959. IN FILE_INFORMATION_CLASS FileInformationClass,
  2960. IN PVOID pBuffer,
  2961. IN ULONG BufferLength)
  2962. {
  2963. RxCaptureFobx;
  2964. PMRX_SMB_SRV_OPEN pSmbSrvOpen;
  2965. NTSTATUS Status;
  2966. USHORT Setup[2];
  2967. USHORT NewState;
  2968. PBYTE pInputDataBuffer = NULL;
  2969. PBYTE pOutputParamBuffer = NULL;
  2970. PBYTE pOutputDataBuffer = NULL;
  2971. ULONG OutputParamBufferLength = 0;
  2972. ULONG InputDataBufferLength = 0;
  2973. ULONG OutputDataBufferLength = 0;
  2974. PFILE_PIPE_INFORMATION pPipeInformation;
  2975. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  2976. SMB_TRANSACTION_OPTIONS TransactionOptions;
  2977. PAGED_CODE();
  2978. pSmbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
  2979. if (BufferLength < sizeof(FILE_PIPE_INFORMATION)) {
  2980. return STATUS_BUFFER_TOO_SMALL;
  2981. }
  2982. if (FileInformationClass != FilePipeInformation) {
  2983. return STATUS_INVALID_PARAMETER;
  2984. }
  2985. pPipeInformation = (PFILE_PIPE_INFORMATION)pBuffer;
  2986. NewState = 0;
  2987. if (pPipeInformation->ReadMode == FILE_PIPE_MESSAGE_MODE) {
  2988. NewState |= SMB_PIPE_READMODE_MESSAGE;
  2989. }
  2990. if (pPipeInformation->CompletionMode == FILE_PIPE_COMPLETE_OPERATION) {
  2991. NewState |= SMB_PIPE_NOWAIT;
  2992. }
  2993. Setup[0] = TRANS_SET_NMPIPE_STATE;
  2994. Setup[1] = pSmbSrvOpen->Fid;
  2995. TransactionOptions = RxDefaultTransactionOptions;
  2996. TransactionOptions.pTransactionName = &s_NamedPipeTransactionName;
  2997. Status = SmbCeTransact(
  2998. RxContext, // the RXContext for the transaction
  2999. &TransactionOptions, // transaction options
  3000. Setup, // the setup buffer
  3001. sizeof(Setup), // setup buffer length
  3002. NULL,
  3003. 0,
  3004. &NewState, // Input Param Buffer
  3005. sizeof(NewState), // Input param buffer length
  3006. pOutputParamBuffer, // Output param buffer
  3007. OutputParamBufferLength, // output param buffer length
  3008. pInputDataBuffer, // Input data buffer
  3009. InputDataBufferLength, // Input data buffer length
  3010. pOutputDataBuffer, // output data buffer
  3011. OutputDataBufferLength, // output data buffer length
  3012. &ResumptionContext // the resumption context
  3013. );
  3014. RxDbgTrace( 0, Dbg, ("MRxSmbQueryNamedPipeInformation: ...returning %lx\n",Status));
  3015. return Status;
  3016. }
  3017. NTSTATUS
  3018. MRxSmbSetFileInformationAtCleanup(
  3019. IN PRX_CONTEXT RxContext
  3020. )
  3021. /*++
  3022. Routine Description:
  3023. This routine sets the file information on cleanup. the old rdr just swallows this operation (i.e.
  3024. it doesn't generate it). we are doing the same..........
  3025. Arguments:
  3026. pRxContext - the RDBSS context
  3027. Return Value:
  3028. NTSTATUS - The return status for the operation
  3029. --*/
  3030. {
  3031. return STATUS_SUCCESS;
  3032. }
  3033. NTSTATUS
  3034. MRxSmbIsValidDirectory(
  3035. IN OUT PRX_CONTEXT RxContext,
  3036. IN PUNICODE_STRING DirectoryName
  3037. )
  3038. /*++
  3039. Routine Description:
  3040. This routine checks a remote directory.
  3041. Arguments:
  3042. RxContext - the RDBSS context
  3043. DirectoryName - the directory needs to be checked
  3044. Return Value:
  3045. RXSTATUS - The return status for the operation
  3046. --*/
  3047. {
  3048. NTSTATUS Status;
  3049. BOOLEAN FinalizationComplete;
  3050. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = NULL;
  3051. PSMBSTUFFER_BUFFER_STATE StufferState;
  3052. KEVENT SyncEvent;
  3053. PAGED_CODE();
  3054. RxDbgTrace(+1, Dbg, ("MRxSmbIsValidDirectory\n", 0 ));
  3055. IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC{
  3056. NOTHING;
  3057. } else {
  3058. PSMBCEDB_SERVER_ENTRY pServerEntry;
  3059. pServerEntry = SmbCeGetAssociatedServerEntry(RxContext->Create.pSrvCall);
  3060. if (SmbCeIsServerInDisconnectedMode(pServerEntry)){
  3061. NTSTATUS CscStatus;
  3062. CscStatus = MRxSmbDCscIsValidDirectory(RxContext,DirectoryName);
  3063. if (CscStatus != STATUS_MORE_PROCESSING_REQUIRED) {
  3064. RxDbgTrace(0, Dbg,
  3065. ("MRxSmbQueryVolumeInfo returningDCON with status=%08lx\n",
  3066. CscStatus ));
  3067. Status = CscStatus;
  3068. goto FINALLY;
  3069. } else {
  3070. NOTHING;
  3071. }
  3072. }
  3073. }
  3074. Status = SmbCeReconnect(RxContext->Create.pVNetRoot);
  3075. if (Status != STATUS_SUCCESS) {
  3076. goto FINALLY;
  3077. }
  3078. Status= SmbPseCreateOrdinaryExchange(
  3079. RxContext,
  3080. RxContext->Create.pVNetRoot,
  3081. SMBPSE_OE_FROM_CREATE,
  3082. MRxSmbCoreCheckPath,
  3083. &OrdinaryExchange
  3084. );
  3085. if (Status != STATUS_SUCCESS) {
  3086. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  3087. goto FINALLY;
  3088. }
  3089. OrdinaryExchange->pPathArgument1 = DirectoryName;
  3090. OrdinaryExchange->SmbCeFlags |= SMBCE_EXCHANGE_ATTEMPT_RECONNECTS;
  3091. OrdinaryExchange->AssociatedStufferState.CurrentCommand = SMB_COM_NO_ANDX_COMMAND;
  3092. OrdinaryExchange->pSmbCeSynchronizationEvent = &SyncEvent;
  3093. StufferState = &OrdinaryExchange->AssociatedStufferState;
  3094. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
  3095. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  3096. ASSERT(Status != STATUS_PENDING);
  3097. if (Status != STATUS_SUCCESS) {
  3098. Status = STATUS_BAD_NETWORK_PATH;
  3099. }
  3100. FinalizationComplete = SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  3101. ASSERT(FinalizationComplete);
  3102. FINALLY:
  3103. RxDbgTrace(-1, Dbg, ("MRxSmbIsValidDirectory exit with status=%08lx\n", Status ));
  3104. return(Status);
  3105. }