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.

2459 lines
90 KiB

  1. /*++
  2. Copyright (c) 1989 - 1999 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. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. #pragma warning(error:4101) // Unreferenced local variable
  12. RXDT_DefineCategory(DIRCTRL);
  13. #define Dbg (DEBUG_TRACE_DIRCTRL)
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, __MRxSmbAllocateSideBuffer)
  16. #pragma alloc_text(PAGE, MRxSmbDeallocateSideBuffer)
  17. #pragma alloc_text(PAGE, MRxSmbTranslateLanManFindBuffer)
  18. #pragma alloc_text(PAGE, MrxSmbUnalignedDirEntryCopyTail)
  19. #pragma alloc_text(PAGE, MRxSmbQueryDirectory)
  20. #pragma alloc_text(PAGE, MRxSmbQueryVolumeInformation)
  21. #pragma alloc_text(PAGE, MRxSmbQueryVolumeInformationWithFullBuffer)
  22. #pragma alloc_text(PAGE, MRxSmbSetVolumeInformation)
  23. #pragma alloc_text(PAGE, MRxSmbQueryFileInformation)
  24. #pragma alloc_text(PAGE, MRxSmbSetFileInformation)
  25. #pragma alloc_text(PAGE, MRxSmbSetFileInformationAtCleanup)
  26. #pragma alloc_text(PAGE, MRxSmbIsValidDirectory)
  27. #pragma alloc_text(PAGE, MRxSmbQueryFileInformationFromPseudoOpen)
  28. #endif
  29. #define MRxSmbForceCoreInfo FALSE
  30. //#define FORCECOREINFO
  31. #if DBG
  32. #ifdef FORCECOREINFO
  33. #undef MRxSmbForceCoreInfo
  34. BOOLEAN MRxSmbForceCoreInfo = TRUE;
  35. #endif
  36. #endif
  37. BOOLEAN MRxSmbBypassDownLevelRename = FALSE;
  38. //BOOLEAN MRxSmbBypassDownLevelRename = TRUE;
  39. ULONG UnalignedDirEntrySideBufferSize = 16384;
  40. //
  41. // All T2Find requests to the remote server request the 32 bit resume key
  42. // so SMB_RFIND_BUFFER2 is used instead of SMB_FIND_BUFFER2.
  43. //
  44. typedef struct _SMB_FIND_BUFFER2_WITH_RESUME {
  45. _ULONG( ResumeKey );
  46. SMB_FIND_BUFFER2;
  47. } SMB_FIND_BUFFER2_WITH_RESUME;
  48. typedef SMB_FIND_BUFFER2_WITH_RESUME SMB_UNALIGNED *PSMB_FIND_BUFFER2_WITH_RESUME;
  49. LIST_ENTRY MRxSmbSideBuffersList = {NULL,NULL};
  50. ULONG MRxSmbSideBuffersSpinLock = 0;
  51. ULONG MRxSmbSideBuffersCount = 0;
  52. ULONG MRxSmbSideBuffersSerialNumber = 0;
  53. BOOLEAN MRxSmbLoudSideBuffers = FALSE;
  54. typedef struct _SIDE_BUFFER {
  55. ULONG Signature;
  56. LIST_ENTRY ListEntry;
  57. PMRX_FCB Fcb;
  58. PMRX_FOBX Fobx;
  59. PMRX_SMB_FOBX smbFobx;
  60. ULONG SerialNumber;
  61. BYTE Buffer;
  62. } SIDE_BUFFER, *PSIDE_BUFFER;
  63. #if DBG
  64. #define MRxSmbAllocateSideBuffer(a,b,c,d) __MRxSmbAllocateSideBuffer(a,b,c,d)
  65. #else
  66. #define MRxSmbAllocateSideBuffer(a,b,c,d) __MRxSmbAllocateSideBuffer(a,b,c)
  67. #endif
  68. NTSTATUS
  69. MRxSmbCoreCheckPath(
  70. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  71. );
  72. VOID
  73. __MRxSmbAllocateSideBuffer(
  74. IN OUT PRX_CONTEXT RxContext,
  75. IN OUT PMRX_SMB_FOBX smbFobx,
  76. IN USHORT Setup
  77. #if DBG
  78. ,IN PUNICODE_STRING smbtemplate
  79. #endif
  80. )
  81. {
  82. RxCaptureFcb;RxCaptureFobx;
  83. PSIDE_BUFFER SideBuffer;
  84. ULONG SideBufferSize = UnalignedDirEntrySideBufferSize+sizeof(SIDE_BUFFER);
  85. POOL_TYPE PoolType;
  86. PAGED_CODE();
  87. ASSERT( smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL);
  88. #ifdef _WIN64
  89. //
  90. // NT64: When PagedPool is used here, we get memory corruption on
  91. // some findfirst/findnext operations. Find out why.
  92. //
  93. PoolType = NonPagedPool;
  94. #else
  95. PoolType = PagedPool;
  96. #endif
  97. SideBuffer = (PSIDE_BUFFER)RxAllocatePoolWithTag(
  98. PoolType,
  99. SideBufferSize,
  100. MRXSMB_DIRCTL_POOLTAG);
  101. if (SideBuffer==NULL) {
  102. return;
  103. }
  104. ASSERT( smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL);
  105. SideBuffer->Signature = 'JLBS';
  106. SideBuffer->smbFobx = smbFobx;
  107. SideBuffer->Fobx = capFobx;
  108. SideBuffer->Fcb = capFcb;
  109. smbFobx->Enumeration.UnalignedDirEntrySideBuffer = &SideBuffer->Buffer;
  110. RxLog(("Allocsidebuf %lx fo/f=%lx,%lx\n",
  111. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  112. capFobx,capFcb));
  113. smbFobx->Enumeration.SerialNumber = SideBuffer->SerialNumber = InterlockedIncrement(&MRxSmbSideBuffersSerialNumber);
  114. InterlockedIncrement(&MRxSmbSideBuffersCount);
  115. if (MRxSmbSideBuffersList.Flink==NULL) {
  116. InitializeListHead(&MRxSmbSideBuffersList);
  117. }
  118. ExAcquireFastMutex(&MRxSmbSerializationMutex);
  119. InsertTailList(&MRxSmbSideBuffersList,&SideBuffer->ListEntry);
  120. ExReleaseFastMutex(&MRxSmbSerializationMutex);
  121. if (!MRxSmbLoudSideBuffers) return;
  122. KdPrint(("Allocating side buffer %08lx %08lx %08lx %08lx %08lxon <%wZ> %s %wZ\n",
  123. &SideBuffer->Buffer,
  124. MRxSmbSideBuffersCount,
  125. smbFobx,capFobx,capFobx->pSrvOpen,
  126. GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext),
  127. (Setup == TRANS2_FIND_FIRST2)?"First":"Next",
  128. smbtemplate
  129. ));
  130. }
  131. VOID
  132. MRxSmbDeallocateSideBuffer(
  133. IN OUT PRX_CONTEXT RxContext,
  134. IN OUT PMRX_SMB_FOBX smbFobx,
  135. IN PSZ where
  136. )
  137. {
  138. PSIDE_BUFFER SideBuffer;
  139. RxCaptureFcb;RxCaptureFobx;
  140. PAGED_CODE();
  141. if( smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL) return;
  142. SideBuffer = CONTAINING_RECORD(smbFobx->Enumeration.UnalignedDirEntrySideBuffer,SIDE_BUFFER,Buffer);
  143. if (MRxSmbLoudSideBuffers){
  144. DbgPrint("D--------- side buffer %08lx %08lx %08lx %08lx %08lxon <%wZ> %s\n",
  145. &SideBuffer->Buffer,
  146. MRxSmbSideBuffersCount,
  147. smbFobx,capFobx,capFobx->pSrvOpen,
  148. GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext),
  149. where
  150. );
  151. }
  152. ASSERT(SideBuffer->Signature == 'JLBS');
  153. ASSERT(SideBuffer->Fobx == capFobx);
  154. ASSERT(SideBuffer->Fcb == capFcb);
  155. ASSERT(SideBuffer->smbFobx == smbFobx);
  156. ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
  157. ExAcquireFastMutex(&MRxSmbSerializationMutex);
  158. InterlockedDecrement(&MRxSmbSideBuffersCount);
  159. RemoveEntryList(&SideBuffer->ListEntry);
  160. ExReleaseFastMutex(&MRxSmbSerializationMutex);
  161. RxLog(("Deallocsidebuf %lx fo/f=%lx,%lx\n",
  162. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  163. capFobx,capFcb));
  164. RxFreePool(SideBuffer);
  165. smbFobx->Enumeration.UnalignedDirEntrySideBuffer = NULL;
  166. }
  167. VOID
  168. MRxSmbTranslateLanManFindBuffer(
  169. PRX_CONTEXT RxContext,
  170. PULONG PreviousReturnedEntry,
  171. PBYTE ThisEntryInBuffer
  172. )
  173. {
  174. RxCaptureFcb; RxCaptureFobx;
  175. PSMBCEDB_SERVER_ENTRY pServerEntry;
  176. PSMBCE_SERVER Server;
  177. ULONG FileInformationClass = RxContext->Info.FileInformationClass;
  178. PFILE_FULL_DIR_INFORMATION NtBuffer = (PFILE_FULL_DIR_INFORMATION)PreviousReturnedEntry;
  179. PSMB_FIND_BUFFER2_WITH_RESUME SmbBuffer = (PSMB_FIND_BUFFER2_WITH_RESUME)ThisEntryInBuffer;
  180. SMB_TIME Time;
  181. SMB_DATE Date;
  182. PAGED_CODE();
  183. if (FileInformationClass==FileNamesInformation) { return; }
  184. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  185. Server = &pServerEntry->Server;
  186. SmbMoveTime (&Time, &SmbBuffer->CreationTime);
  187. SmbMoveDate (&Date, &SmbBuffer->CreationDate);
  188. NtBuffer->CreationTime = MRxSmbConvertSmbTimeToTime(Server, Time, Date);
  189. SmbMoveTime (&Time, &SmbBuffer->LastAccessTime);
  190. SmbMoveDate (&Date, &SmbBuffer->LastAccessDate);
  191. NtBuffer->LastAccessTime = MRxSmbConvertSmbTimeToTime(Server, Time, Date);
  192. SmbMoveTime (&Time, &SmbBuffer->LastWriteTime);
  193. SmbMoveDate (&Date, &SmbBuffer->LastWriteDate);
  194. NtBuffer->LastWriteTime = MRxSmbConvertSmbTimeToTime(Server, Time, Date);
  195. NtBuffer->ChangeTime.QuadPart = 0;
  196. NtBuffer->EndOfFile.QuadPart = SmbGetUlong(&SmbBuffer->DataSize);
  197. NtBuffer->AllocationSize.QuadPart = SmbGetUlong(&SmbBuffer->AllocationSize);
  198. NtBuffer->FileAttributes = MRxSmbMapSmbAttributes(SmbBuffer->Attributes);
  199. if ((FileInformationClass==FileFullDirectoryInformation)
  200. || (FileInformationClass==FileBothDirectoryInformation)) {
  201. NtBuffer->EaSize = SmbGetUlong(&SmbBuffer->EaSize);
  202. }
  203. }
  204. NTSTATUS
  205. MrxSmbUnalignedDirEntryCopyTail(
  206. IN OUT PRX_CONTEXT RxContext,
  207. IN FILE_INFORMATION_CLASS FileInformationClass,
  208. IN OUT PVOID pBuffer,
  209. IN OUT PULONG pLengthRemaining,
  210. IN OUT PMRX_SMB_FOBX smbFobx
  211. )
  212. /*++
  213. Routine Description:
  214. This routine copies the data from the side buffer into the users buffer and adjusts the
  215. lengths remaining appropriately. this is called either if the server doesn't do unicode (w95) OR
  216. if the server does not promise to quadalign entries OR if the user's buffer is not quadaligned.
  217. this routine can be entered after a T2 finishes or to copy the last entries from a previous T2. in the second case, the
  218. pUnalignedDirEntrySideBuffer ptr will be null and it will go to acquire the correct pointer from the smbFobx.
  219. this routine has the responsibility to free the sidebufferptr when it is exhausted.
  220. Arguments:
  221. RxContext - the RDBSS context
  222. Return Value:
  223. RXSTATUS - The return status for the operation
  224. --*/
  225. {
  226. NTSTATUS Status = STATUS_SUCCESS;
  227. RxCaptureFcb;
  228. ULONG i,NameSizeInUnicode;
  229. LONG LocalLengthRemaining; //signed arithmetic makes it easier
  230. PULONG PreviousReturnedEntry = NULL;
  231. ULONG FileNameLengthOffset = smbFobx->Enumeration.FileNameLengthOffset;
  232. ULONG FileNameOffset = smbFobx->Enumeration.FileNameOffset;
  233. PBYTE UnalignedDirEntrySideBuffer = smbFobx->Enumeration.UnalignedDirEntrySideBuffer;
  234. BOOLEAN IsUnicode = smbFobx->Enumeration.IsUnicode;
  235. BOOLEAN IsNonNtT2Find = smbFobx->Enumeration.IsNonNtT2Find;
  236. PMRX_SMB_DIRECTORY_RESUME_INFO ResumeInfo = smbFobx->Enumeration.ResumeInfo;
  237. ULONG FilesReturned = smbFobx->Enumeration.FilesReturned;
  238. ULONG EntryOffset = smbFobx->Enumeration.EntryOffset;
  239. ULONG ReturnedEntryOffset = 0;// = smbFobx->Enumeration.ReturnedEntryOffset;
  240. BOOLEAN EndOfSearchReached = smbFobx->Enumeration.EndOfSearchReached;
  241. ULONG TotalDataBytesReturned = smbFobx->Enumeration.TotalDataBytesReturned;
  242. BOOLEAN FilterFailure = FALSE;
  243. PAGED_CODE();
  244. LocalLengthRemaining = (LONG)(*pLengthRemaining);
  245. //
  246. // keep looping until we've filled in all we can or there're no more entries
  247. for (i=ReturnedEntryOffset=0;;) {
  248. ULONG FileNameLength,ThisEntrySize; PCHAR FileNameBuffer;
  249. UNICODE_STRING ReturnedFileName;
  250. OEM_STRING FileName;
  251. NTSTATUS StringStatus;
  252. BOOLEAN TwoExtraBytes = TRUE;
  253. ULONG resumekey,NextEntryOffsetinBuffer;
  254. PULONG PreviousPreviousReturnedEntry = NULL;
  255. PBYTE ThisEntryInBuffer = UnalignedDirEntrySideBuffer+EntryOffset;
  256. //
  257. // don't EVER let yourself get past the data returned...servers return funny stuff.......
  258. if (EntryOffset>=TotalDataBytesReturned){
  259. FilterFailure = TRUE;
  260. FilesReturned = i; //we're done with this buffer........
  261. break;
  262. }
  263. //
  264. // find the name, the length, and the resume key based on whether it is a NT-T2find or a nonNT
  265. if (!IsNonNtT2Find) {
  266. //
  267. // NT, we use the offsets that we stored earlier.........
  268. FileNameLength = SmbGetUlong(ThisEntryInBuffer+FileNameLengthOffset);
  269. FileNameBuffer = ThisEntryInBuffer+FileNameOffset;
  270. resumekey = SmbGetUlong(ThisEntryInBuffer
  271. +FIELD_OFFSET(FILE_FULL_DIR_INFORMATION,FileIndex));
  272. NextEntryOffsetinBuffer = SmbGetUlong(ThisEntryInBuffer);
  273. } else {
  274. //
  275. // for lanman, we always ask for stuff using the SMB_FIND_BUFFER2 to which
  276. // we have prepended a resume key. so, the name is always at a fixed offset.
  277. // Also, for nonNT we have read all the files and must filter out correctly; we
  278. // save where we are in the user's buffer so that we can roll back.
  279. FileNameLength = *(ThisEntryInBuffer
  280. +FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,FileNameLength));
  281. FileNameBuffer = ThisEntryInBuffer
  282. +FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,FileName[0]);
  283. resumekey = SmbGetUlong(ThisEntryInBuffer+
  284. +FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,ResumeKey));
  285. NextEntryOffsetinBuffer = FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,FileName[0])
  286. + FileNameLength + 1; //the +1 is for the null..we could have said Filename{1]
  287. PreviousPreviousReturnedEntry = PreviousReturnedEntry; //save this for rollback on filterfail
  288. }
  289. // some servers lie about how many entries were returned and/or send partial entries
  290. // dont let them trick us..........
  291. if (EntryOffset+NextEntryOffsetinBuffer>TotalDataBytesReturned){
  292. FilterFailure = TRUE;
  293. FilesReturned = i; //we're done with this buffer........
  294. break;
  295. }
  296. FileName.Buffer = FileNameBuffer;
  297. FileName.Length = (USHORT)FileNameLength;
  298. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: EO,REO=%08lx,%08lx\n",
  299. EntryOffset,ReturnedEntryOffset));
  300. //check to see if this entry will fit
  301. if (IsUnicode) {
  302. NameSizeInUnicode = FileNameLength;
  303. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: length=%08lx/%08lx, name = %wZ\n",
  304. FileNameLength,NameSizeInUnicode,&FileName));
  305. } else {
  306. NameSizeInUnicode = RtlxOemStringToUnicodeSize(&FileName)-sizeof(WCHAR);
  307. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: length=%08lx/%08lx, name = %.*s\n",
  308. FileNameLength,NameSizeInUnicode,FileNameLength,FileNameBuffer));
  309. }
  310. //
  311. // now that we know the size of the name and its location, we need to copy it
  312. // to the user's buffer
  313. ThisEntrySize = FileNameOffset+NameSizeInUnicode;
  314. if (((LONG)ThisEntrySize)>LocalLengthRemaining) {
  315. break;
  316. }
  317. if (((LONG)ThisEntrySize)>LocalLengthRemaining-(LONG)sizeof(WCHAR)) {
  318. TwoExtraBytes = FALSE;
  319. }
  320. ThisEntrySize = LongAlign(ThisEntrySize);
  321. PreviousReturnedEntry = (PULONG)(((PBYTE)pBuffer)+ReturnedEntryOffset);
  322. //
  323. // next we compute where the next entry after this one will start. the definition is
  324. // that it must be 8-byte aligned. we know already that it's 4byte aligned.
  325. if (!IsPtrQuadAligned((PCHAR)(PreviousReturnedEntry)+ThisEntrySize) ){
  326. ThisEntrySize += sizeof(ULONG);
  327. }
  328. if (i!=0) {
  329. ASSERT(IsPtrQuadAligned(PreviousReturnedEntry));
  330. }
  331. //
  332. // if this is an NT find, we can copy in the data now. for lanman, we
  333. // copy in the data later........
  334. if (!IsNonNtT2Find) {
  335. //copy everything in the entry up to but not including the name info
  336. RtlCopyMemory(PreviousReturnedEntry,UnalignedDirEntrySideBuffer+EntryOffset,FileNameOffset);
  337. } else {
  338. // clear out all fields i cannot support.
  339. RtlZeroMemory(PreviousReturnedEntry,FileNameOffset);
  340. }
  341. // store the length of this entry and the size of the name...if this is the last
  342. // entry returned, then the offset field will be cleared later
  343. *PreviousReturnedEntry = ThisEntrySize;
  344. *((PULONG)(((PBYTE)PreviousReturnedEntry)+FileNameLengthOffset)) = NameSizeInUnicode;
  345. //copy in the name .........this is made difficult by the oem-->unicode routine that
  346. // requires space for a NULL!
  347. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: REO/buf/pentry=%08lx/%08lx/%08lx\n",
  348. pBuffer,ReturnedEntryOffset,PreviousReturnedEntry));
  349. ReturnedFileName.Buffer = (PWCH)(((PBYTE)PreviousReturnedEntry)+FileNameOffset);
  350. if (!IsUnicode) {
  351. if (TwoExtraBytes) {
  352. ReturnedFileName.MaximumLength = sizeof(WCHAR)+(USHORT)NameSizeInUnicode;
  353. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: filenamebuf,length=%08lx/%08lx\n",
  354. ReturnedFileName.Buffer,ReturnedFileName.MaximumLength));
  355. StringStatus = RtlOemStringToUnicodeString(&ReturnedFileName,&FileName,FALSE); //false means don;t allocate
  356. } else {
  357. OEM_STRING LastChar;
  358. UNICODE_STRING LastCharInUnicode;
  359. WCHAR UnicodeCharBuffer[2];
  360. ReturnedFileName.MaximumLength = (USHORT)NameSizeInUnicode;
  361. FileName.Length -= 1;
  362. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: filenamebuf,length=%08lx/%08lx\n",
  363. ReturnedFileName.Buffer,ReturnedFileName.MaximumLength));
  364. StringStatus = RtlOemStringToUnicodeString(&ReturnedFileName,&FileName,FALSE); //false means don;t allocate
  365. ASSERT(StringStatus==STATUS_SUCCESS);
  366. LastChar.Buffer = FileName.Buffer+FileName.Length;
  367. LastChar.Length = 1;
  368. LastCharInUnicode.Buffer = (PWCH)UnicodeCharBuffer;
  369. //LastCharInUnicode.Buffer = (PWCH)(((PBYTE)ReturnedFileName.Buffer)+ReturnedFileName.Length);
  370. LastCharInUnicode.MaximumLength = sizeof(UnicodeCharBuffer);
  371. StringStatus = RtlOemStringToUnicodeString(&LastCharInUnicode,&LastChar,FALSE); //false means don;t allocate
  372. *((PWCH)(((PBYTE)ReturnedFileName.Buffer)+ReturnedFileName.Length)) = UnicodeCharBuffer[0];
  373. }
  374. ASSERT(StringStatus==STATUS_SUCCESS);
  375. // Win95 returns the shortname in ascii....spread it out
  376. if ((FileInformationClass == FileBothDirectoryInformation) && !IsNonNtT2Find) {
  377. PFILE_BOTH_DIR_INFORMATION BothInfo = (PFILE_BOTH_DIR_INFORMATION)PreviousReturnedEntry;
  378. OEM_STRING oemName;
  379. UNICODE_STRING UnicodeName;
  380. WCHAR wcharBuffer[MAX_PATH];
  381. oemName.Buffer = (PBYTE)(&BothInfo->ShortName[0]);
  382. oemName.Length =
  383. oemName.MaximumLength = BothInfo->ShortNameLength;
  384. UnicodeName.Buffer = wcharBuffer;
  385. UnicodeName.Length = 0;
  386. UnicodeName.MaximumLength = MAX_PATH * sizeof(WCHAR);
  387. StringStatus = RtlOemStringToUnicodeString(&UnicodeName, &oemName, FALSE);
  388. ASSERT(StringStatus==STATUS_SUCCESS);
  389. BothInfo->ShortNameLength = (CHAR)UnicodeName.Length;
  390. RtlCopyMemory(BothInfo->ShortName, UnicodeName.Buffer, UnicodeName.Length);
  391. IF_DEBUG {
  392. UNICODE_STRING LastName;
  393. LastName.Buffer = (PWCHAR)wcharBuffer;
  394. LastName.Length = (USHORT)UnicodeName.Length;
  395. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: unicodeshortnamename = %wZ\n", &LastName));
  396. }
  397. }
  398. } else {
  399. //here, it's already unicode.....just copy the bytes
  400. RtlCopyMemory(ReturnedFileName.Buffer,FileName.Buffer,FileName.Length);
  401. }
  402. IF_DEBUG {
  403. UNICODE_STRING LastName;
  404. LastName.Buffer = ReturnedFileName.Buffer;
  405. LastName.Length = (USHORT)NameSizeInUnicode;
  406. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: unicodename = %wZ\n", &LastName));
  407. }
  408. //now...setup to resume based on this entry
  409. if (ResumeInfo != NULL) {
  410. PREQ_FIND_NEXT2 pFindNext2Request = &ResumeInfo->FindNext2_Request;
  411. //ULONG resumekey = ((PFILE_FULL_DIR_INFORMATION)PreviousReturnedEntry)->FileIndex;
  412. pFindNext2Request->ResumeKey = resumekey;
  413. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: resumekey = %08lx\n", resumekey));
  414. RtlCopyMemory(&pFindNext2Request->Buffer[0],FileNameBuffer,FileNameLength);
  415. //buffer is a UCHAR...not WCHAR
  416. if (IsUnicode) {
  417. // In the case of UNICODE strings an additional NULL is required ( WCHAR NULL )
  418. pFindNext2Request->Buffer[FileNameLength] = 0; //nullterminated
  419. pFindNext2Request->Buffer[FileNameLength + 1] = 0; //nullterminated
  420. smbFobx->Enumeration.ResumeInfo->ParametersLength
  421. = (USHORT)(&pFindNext2Request->Buffer[FileNameLength+2] - (PBYTE)pFindNext2Request);
  422. } else {
  423. pFindNext2Request->Buffer[FileNameLength] = 0; //nullterminated
  424. smbFobx->Enumeration.ResumeInfo->ParametersLength
  425. = (USHORT)(&pFindNext2Request->Buffer[FileNameLength+1] - (PBYTE)pFindNext2Request);
  426. }
  427. }
  428. //ASSERT(!IsNonNtT2Find);
  429. //at this point, we have copied the name and the resume key. BUT, for nonnt we have to
  430. //filter the names so we still may have to roll back
  431. if (!IsNonNtT2Find) {
  432. //no need for filtering on NT
  433. FilterFailure = FALSE;
  434. } else {
  435. // here we have to filter out based on the template
  436. RxCaptureFobx; //do this here so it's not on the NT path
  437. FilterFailure = FALSE;
  438. if (smbFobx->Enumeration.WildCardsFound ) {
  439. FilterFailure = !FsRtlIsNameInExpression(
  440. &capFobx->UnicodeQueryTemplate,
  441. &ReturnedFileName,
  442. TRUE,
  443. NULL );
  444. } else {
  445. FilterFailure = !RtlEqualUnicodeString(
  446. &capFobx->UnicodeQueryTemplate,
  447. &ReturnedFileName,
  448. TRUE ); //case-insensitive
  449. }
  450. if (!FilterFailure) {
  451. // since we didn't copy the data before, we have to copy it now...
  452. MRxSmbTranslateLanManFindBuffer(RxContext,PreviousReturnedEntry,ThisEntryInBuffer);
  453. } else {
  454. PreviousReturnedEntry = PreviousPreviousReturnedEntry; //rollback on filterfail
  455. }
  456. }
  457. if (!FilterFailure) {
  458. // filtering succeeded..... adjust returned sizes and counts
  459. LocalLengthRemaining -= ThisEntrySize;
  460. i++;
  461. ReturnedEntryOffset += ThisEntrySize;
  462. } else {
  463. FilesReturned--; //we exit the loop if i passes filesreturned
  464. }
  465. //
  466. // complicated test to keep going.......
  467. //EntryOffset += SmbGetUlong(UnalignedDirEntrySideBuffer+EntryOffset);
  468. EntryOffset += NextEntryOffsetinBuffer;
  469. if ((i>=FilesReturned)
  470. ||(LocalLengthRemaining<0)
  471. || (RxContext->QueryDirectory.ReturnSingleEntry&&(i>0)) ) {
  472. break;
  473. }
  474. }
  475. //
  476. // if we are not returning even one entry, either we didn't have space for even one entry
  477. // OR we're filtering and no guys passed the filter. return an appropriate error in each case
  478. if (i==0) {
  479. Status = FilterFailure?STATUS_MORE_PROCESSING_REQUIRED:STATUS_BUFFER_OVERFLOW;
  480. } else {
  481. *PreviousReturnedEntry = 0; // this clears the "next" link for the last returned entry
  482. }
  483. //
  484. // send back the right size
  485. if (LocalLengthRemaining <= 0) {
  486. *pLengthRemaining = 0;
  487. } else {
  488. *pLengthRemaining = (ULONG)LocalLengthRemaining;
  489. }
  490. //
  491. // if we're finished with the sidebuffer, deallocate it.
  492. // otherwise setup to resume........
  493. if (i>=FilesReturned) {
  494. RxLog(("sidebufdealloc %lx %lx\n",RxContext,smbFobx));
  495. MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"Tail");
  496. if (EndOfSearchReached) {
  497. //smbFobx->Enumeration.Flags &= ~SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN;
  498. //we will close the search handle when the user's handle closes
  499. smbFobx->Enumeration.ErrorStatus = STATUS_NO_MORE_FILES;
  500. }
  501. } else {
  502. //set up to resume here
  503. ASSERT(smbFobx->Enumeration.UnalignedDirEntrySideBuffer == UnalignedDirEntrySideBuffer);
  504. smbFobx->Enumeration.EntryOffset = EntryOffset;
  505. smbFobx->Enumeration.FilesReturned = FilesReturned - i;
  506. }
  507. return(Status);
  508. }
  509. ULONG MRxSmbWin95Retries = 0;
  510. NTSTATUS
  511. MRxSmbQueryDirectory(
  512. IN OUT PRX_CONTEXT RxContext
  513. )
  514. /*++
  515. Routine Description:
  516. This routine does a directory query. Only the NT-->NT path is implemented.
  517. Arguments:
  518. RxContext - the RDBSS context
  519. Return Value:
  520. RXSTATUS - The return status for the operation
  521. --*/
  522. {
  523. NTSTATUS Status;
  524. RxCaptureFcb;
  525. RxCaptureFobx;
  526. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  527. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  528. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  529. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  530. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = SmbCeGetAssociatedVNetRootContext(SrvOpen->pVNetRoot);
  531. PSMBCE_SESSION pSession = &pVNetRootContext->pSessionEntry->Session;
  532. FILE_INFORMATION_CLASS FileInformationClass;
  533. PVOID Buffer;
  534. PULONG pLengthRemaining;
  535. USHORT SmbFileInfoLevel;
  536. ULONG FilesReturned;
  537. ULONG RetryCount = 0;
  538. USHORT Setup;
  539. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  540. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  541. PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
  542. //REQ_FIND_NEXT2 FindNext2Request;
  543. PREQ_FIND_FIRST2 pFindFirst2Request = NULL;
  544. PBYTE SendParamsBuffer,ReceiveParamsBuffer;
  545. PBYTE UnalignedDirEntrySideBuffer;
  546. BOOLEAN DirEntriesAreUaligned = FALSE;
  547. BOOLEAN IsUnicode = TRUE;
  548. BOOLEAN IsNonNtT2Find;
  549. USHORT SearchFlags = SMB_FIND_CLOSE_AT_EOS|SMB_FIND_RETURN_RESUME_KEYS;
  550. USHORT NumEntries;
  551. ULONG SendParamsBufferLength,ReceiveParamsBufferLength;
  552. RESP_FIND_FIRST2 FindFirst2Response;
  553. UNICODE_STRING FileName = {0,0,NULL};
  554. struct {
  555. RESP_FIND_NEXT2 FindNext2Response;
  556. ULONG Pad; //nonnt needs this
  557. } XX;
  558. #if DBG
  559. UNICODE_STRING smbtemplate = {0,0,NULL};
  560. #endif
  561. PAGED_CODE();
  562. TURN_BACK_ASYNCHRONOUS_OPERATIONS();
  563. FileInformationClass = RxContext->Info.FileInformationClass;
  564. Buffer = RxContext->Info.Buffer;
  565. pLengthRemaining = &RxContext->Info.LengthRemaining;
  566. RxDbgTrace(+1, Dbg, ("MRxSmbQueryDirectory: directory=<%wZ>\n",
  567. GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext)
  568. ));
  569. #define __GET_NAME_PARAMS_FOR_TYPE(___type___) { \
  570. smbFobx->Enumeration.FileNameOffset = (USHORT)FIELD_OFFSET(___type___,FileName[0]); \
  571. smbFobx->Enumeration.FileNameLengthOffset = (USHORT)FIELD_OFFSET(___type___,FileNameLength); \
  572. }
  573. switch (FileInformationClass) {
  574. case FileDirectoryInformation:
  575. SmbFileInfoLevel = SMB_FIND_FILE_DIRECTORY_INFO;
  576. __GET_NAME_PARAMS_FOR_TYPE(FILE_DIRECTORY_INFORMATION);
  577. break;
  578. case FileFullDirectoryInformation:
  579. SmbFileInfoLevel = SMB_FIND_FILE_FULL_DIRECTORY_INFO;
  580. __GET_NAME_PARAMS_FOR_TYPE(FILE_FULL_DIR_INFORMATION);
  581. break;
  582. case FileBothDirectoryInformation:
  583. SmbFileInfoLevel = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
  584. __GET_NAME_PARAMS_FOR_TYPE(FILE_BOTH_DIR_INFORMATION);
  585. break;
  586. case FileNamesInformation:
  587. SmbFileInfoLevel = SMB_FIND_FILE_NAMES_INFO;
  588. __GET_NAME_PARAMS_FOR_TYPE(FILE_NAMES_INFORMATION);
  589. break;
  590. default:
  591. RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: Invalid FS information class\n"));
  592. Status = STATUS_INVALID_PARAMETER;
  593. goto FINALLY;
  594. }
  595. #if DBG
  596. if (MRxSmbLoudSideBuffers) {
  597. SetFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_LOUD_FINALIZE);
  598. }
  599. #endif
  600. if (FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_NO_WILDCARD) ||
  601. FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE)) {
  602. // if the FindFirst has been satisfied basied on local file information cache,
  603. // we should fail the FindNext since the file has been found with the exact name.
  604. Status = STATUS_NO_MORE_FILES;
  605. smbFobx->Enumeration.EndOfSearchReached = TRUE;
  606. smbFobx->Enumeration.ErrorStatus = STATUS_NO_MORE_FILES;
  607. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE);
  608. goto FINALLY;
  609. }
  610. if (capFobx->UnicodeQueryTemplate.Length != 0 &&
  611. !FsRtlDoesNameContainWildCards(&capFobx->UnicodeQueryTemplate) &&
  612. !FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST)) {
  613. // if it is the FindFirst, we try to find the file on local file information cache.
  614. PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  615. PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate;
  616. UNICODE_STRING TargetName = {0,0,NULL};
  617. TargetName.Length = DirectoryName->Length + Template->Length + sizeof(WCHAR);
  618. TargetName.MaximumLength = TargetName.Length;
  619. TargetName.Buffer = (PWCHAR)RxAllocatePoolWithTag(PagedPool,
  620. TargetName.Length,
  621. MRXSMB_DIRCTL_POOLTAG);
  622. if (TargetName.Buffer == NULL) {
  623. Status = STATUS_INSUFFICIENT_RESOURCES;
  624. goto FINALLY;
  625. }
  626. RtlCopyMemory(TargetName.Buffer,
  627. DirectoryName->Buffer,
  628. DirectoryName->Length);
  629. TargetName.Buffer[DirectoryName->Length/sizeof(WCHAR)] = L'\\';
  630. RtlCopyMemory(&TargetName.Buffer[DirectoryName->Length/sizeof(WCHAR)+1],
  631. Template->Buffer,
  632. Template->Length);
  633. RxFreePool(TargetName.Buffer);
  634. SearchFlags |= SMB_FIND_CLOSE_AFTER_REQUEST;
  635. SetFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_NO_WILDCARD);
  636. }
  637. if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_DEFERRED_OPEN)) {
  638. BOOLEAN AcquireExclusive = RxIsFcbAcquiredExclusive(capFcb);
  639. BOOLEAN AcquireShare = RxIsFcbAcquiredShared(capFcb) > 0;
  640. if (AcquireExclusive || AcquireShare) {
  641. RxReleaseFcbResourceInMRx(capFcb );
  642. }
  643. // connection could have been timed out, try to reconnect.
  644. Status = SmbCeReconnect(SrvOpen->pVNetRoot);
  645. if (AcquireExclusive) {
  646. RxAcquireExclusiveFcbResourceInMRx( capFcb );
  647. } else if (AcquireShare) {
  648. RxAcquireExclusiveFcbResourceInMRx( capFcb );
  649. }
  650. if (Status != STATUS_SUCCESS) {
  651. // connection cannot be recovered.
  652. goto FINALLY;
  653. }
  654. }
  655. if (MRxSmbForceCoreInfo ||
  656. !(pServerEntry->Server.DialectFlags&(DF_NT_SMBS|DF_W95|DF_LANMAN20))) {
  657. return MRxSmbCoreInformation(RxContext,
  658. (ULONG)SmbFileInfoLevel,
  659. Buffer,
  660. pLengthRemaining,
  661. SMBPSE_OE_FROM_QUERYDIRECTORY
  662. );
  663. }
  664. if (smbFobx->Enumeration.UnalignedDirEntrySideBuffer != NULL){
  665. RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: win95 internal resume\n"));
  666. Status = MrxSmbUnalignedDirEntryCopyTail(
  667. /*IN OUT PRX_CONTEXT */ RxContext,
  668. /*IN FILE_INFORMATION_CLASS */ FileInformationClass,
  669. /*IN OUT PVOID */ Buffer,
  670. /*IN OUT PULONG */ pLengthRemaining,
  671. /*IN OUT PMRX_SMB_FOBX */ smbFobx
  672. );
  673. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  674. return(Status);
  675. } else {
  676. Status = STATUS_SUCCESS;
  677. }
  678. }
  679. NumEntries = RxContext->QueryDirectory.ReturnSingleEntry?1:2000;
  680. IsUnicode = BooleanFlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE);
  681. IsNonNtT2Find = !(pServerEntry->Server.Dialect==NTLANMAN_DIALECT);
  682. if (TRUE || FlagOn(pServerEntry->Server.DialectFlags,DF_W95)){
  683. DirEntriesAreUaligned = TRUE;
  684. //SearchFlags = SMB_FIND_RETURN_RESUME_KEYS;
  685. //SearchFlags = SMB_FIND_CLOSE_AT_EOS;
  686. NumEntries = (USHORT)(1+ UnalignedDirEntrySideBufferSize
  687. /(IsNonNtT2Find?FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME, FileName)
  688. :FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName)));
  689. }
  690. if (FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)
  691. && FlagOn(capFobx->Flags,FOBX_FLAG_BACKUP_INTENT)){
  692. SearchFlags |= SMB_FIND_WITH_BACKUP_INTENT;
  693. }
  694. if (IsNonNtT2Find) {
  695. SearchFlags &= ~(SMB_FIND_CLOSE_AT_EOS | SMB_FIND_CLOSE_AFTER_REQUEST);
  696. }
  697. RETRY_____:
  698. if (!FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST)) {
  699. //this is the first time thru
  700. PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  701. PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate;
  702. ULONG DirectoryNameLength,TemplateLength,AllocationLength;
  703. PBYTE SmbFileName;
  704. RxDbgTrace(0, Dbg, ("-->FINFDIRST\n"));
  705. smbFobx->Enumeration.ErrorStatus = STATUS_SUCCESS;
  706. if (smbFobx->Enumeration.WildCardsFound = FsRtlDoesNameContainWildCards(Template)){
  707. //we need an upcased template for
  708. RtlUpcaseUnicodeString( Template, Template, FALSE );
  709. }
  710. Setup = TRANS2_FIND_FIRST2;
  711. DirectoryNameLength = DirectoryName->Length;
  712. TemplateLength = Template->Length;
  713. AllocationLength = sizeof(REQ_FIND_FIRST2) //NOTE: this buffer is bigger than w95 needs
  714. +2*sizeof(WCHAR)
  715. +DirectoryNameLength
  716. +TemplateLength;
  717. pFindFirst2Request = (PREQ_FIND_FIRST2)RxAllocatePoolWithTag(
  718. PagedPool,
  719. AllocationLength,
  720. MRXSMB_DIRCTL_POOLTAG);
  721. if (pFindFirst2Request==NULL) {
  722. RxDbgTrace(0, Dbg, (" --> Couldn't get the pFindFirst2Request!\n"));
  723. Status = STATUS_INSUFFICIENT_RESOURCES;
  724. goto FINALLY;
  725. }
  726. SmbFileName = &pFindFirst2Request->Buffer[0];
  727. if (IsUnicode) {
  728. RtlCopyMemory(SmbFileName,DirectoryName->Buffer,DirectoryNameLength);
  729. SmbFileName += DirectoryNameLength;
  730. if (*((PWCHAR)(SmbFileName-sizeof(WCHAR))) != L'\\') {
  731. *((PWCHAR)SmbFileName) = L'\\'; SmbFileName+= sizeof(WCHAR);
  732. }
  733. RtlCopyMemory(SmbFileName,Template->Buffer,TemplateLength);
  734. SmbFileName += TemplateLength;
  735. *((PWCHAR)SmbFileName) = 0; SmbFileName+= sizeof(WCHAR); //trailing NULL;
  736. IF_DEBUG {
  737. DbgDoit(smbtemplate.Buffer = (PWCHAR)&pFindFirst2Request->Buffer[0];);
  738. DbgDoit(smbtemplate.Length = (USHORT)(SmbFileName - (PBYTE)smbtemplate.Buffer););
  739. RxDbgTrace(0, Dbg, (" --> smbtemplate <%wZ>!\n",&smbtemplate));
  740. }
  741. } else {
  742. ULONG BufSize = AllocationLength;
  743. PUNICODE_STRING FinalTemplate = Template;
  744. UNICODE_STRING AllFiles;
  745. SmbPutUnicodeStringAsOemString(&SmbFileName,DirectoryName,&AllocationLength);
  746. // append a backslash if it doesn't exist in the unicode version
  747. // NB !!! Don't compare with OEM string
  748. // it busts DBCS characters with 0x5c at the end
  749. if (!DirectoryName->Length || (DirectoryName->Buffer[(DirectoryName->Length/sizeof(USHORT))-1] != (USHORT)'\\'))
  750. {
  751. *(SmbFileName-1) = '\\';
  752. }
  753. else
  754. {
  755. // there is already a backslash, backup one character
  756. SmbFileName -= 1; AllocationLength += 1;
  757. }
  758. if (IsNonNtT2Find) {
  759. //we'll get them all and filter on out side
  760. RtlInitUnicodeString(&AllFiles, L"*.*");
  761. FinalTemplate = &AllFiles;
  762. }
  763. SmbPutUnicodeStringAsOemString(&SmbFileName,FinalTemplate,&AllocationLength);
  764. //already padded *SmbFileName = 0; SmbFileName+= sizeof(CHAR); //trailing NULL;
  765. IF_DEBUG {
  766. DbgDoit(smbtemplate.Buffer = (PWCHAR)&pFindFirst2Request->Buffer[0];);
  767. DbgDoit(smbtemplate.Length = (USHORT)(SmbFileName - (PBYTE)smbtemplate.Buffer););
  768. RxDbgTrace(0, Dbg, (" --> smbtemplate <%s>!\n",&pFindFirst2Request->Buffer[0]));
  769. }
  770. }
  771. // SearchAttributes is hardcoded to the magic number 0x16
  772. pFindFirst2Request->SearchAttributes =
  773. (SMB_FILE_ATTRIBUTE_DIRECTORY
  774. | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN);
  775. pFindFirst2Request->SearchCount = NumEntries;
  776. pFindFirst2Request->Flags = SearchFlags;
  777. pFindFirst2Request->InformationLevel = IsNonNtT2Find?SMB_INFO_QUERY_EA_SIZE:SmbFileInfoLevel;
  778. pFindFirst2Request->SearchStorageType = 0;
  779. SendParamsBuffer = (PBYTE)pFindFirst2Request;
  780. SendParamsBufferLength = (ULONG)(SmbFileName - SendParamsBuffer);
  781. ReceiveParamsBuffer = (PBYTE)&FindFirst2Response;
  782. ReceiveParamsBufferLength = sizeof(FindFirst2Response);
  783. } else {
  784. if (smbFobx->Enumeration.ResumeInfo!=NULL) {
  785. PREQ_FIND_NEXT2 pFindNext2Request;
  786. RxDbgTrace(0, Dbg, ("-->FINDNEXT\n"));
  787. if (smbFobx->Enumeration.ErrorStatus != STATUS_SUCCESS) {
  788. Status = smbFobx->Enumeration.ErrorStatus;
  789. RxDbgTrace(0, Dbg, ("-->ERROR EARLY OUT\n"));
  790. goto FINALLY;
  791. }
  792. Setup = TRANS2_FIND_NEXT2;
  793. pFindNext2Request = &smbFobx->Enumeration.ResumeInfo->FindNext2_Request;
  794. pFindNext2Request->Sid = smbFobx->Enumeration.SearchHandle;
  795. pFindNext2Request->SearchCount = NumEntries;
  796. pFindNext2Request->InformationLevel = IsNonNtT2Find?SMB_INFO_QUERY_EA_SIZE:SmbFileInfoLevel;
  797. //pFindNext2Request->ResumeKey and pFindNext2Request->Buffer are setup by the previous pass
  798. pFindNext2Request->Flags = SearchFlags;
  799. SendParamsBuffer = (PBYTE)pFindNext2Request;
  800. SendParamsBufferLength = smbFobx->Enumeration.ResumeInfo->ParametersLength;
  801. ReceiveParamsBuffer = (PBYTE)&XX.FindNext2Response;
  802. ReceiveParamsBufferLength = sizeof(XX.FindNext2Response);
  803. if (IsNonNtT2Find) {
  804. //
  805. // The LMX server wants this to be 10 instead of 8, for some reason.
  806. // If you set it to 8, the server gets very confused. Also, warp.
  807. //
  808. ReceiveParamsBufferLength = 10; //....sigh
  809. }
  810. } else {
  811. // if the ResumeInfo buffer was not allocated, the end of the search has been reached.
  812. Status = STATUS_NO_MORE_FILES;
  813. smbFobx->Enumeration.EndOfSearchReached = TRUE;
  814. smbFobx->Enumeration.ErrorStatus = STATUS_NO_MORE_FILES;
  815. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE);
  816. goto FINALLY;
  817. }
  818. }
  819. if ((DirEntriesAreUaligned) &&
  820. (smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL)) {
  821. MRxSmbAllocateSideBuffer(RxContext,smbFobx,
  822. Setup, &smbtemplate
  823. );
  824. if (smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL) {
  825. RxDbgTrace(0, Dbg, (" --> Couldn't get the win95 sidebuffer!\n"));
  826. Status = STATUS_INSUFFICIENT_RESOURCES;
  827. goto FINALLY;
  828. }
  829. UnalignedDirEntrySideBuffer = smbFobx->Enumeration.UnalignedDirEntrySideBuffer;
  830. smbFobx->Enumeration.IsUnicode = IsUnicode;
  831. smbFobx->Enumeration.IsNonNtT2Find = IsNonNtT2Find;
  832. }
  833. {
  834. PSIDE_BUFFER SideBuffer;
  835. SideBuffer = (PSIDE_BUFFER)CONTAINING_RECORD(
  836. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  837. SIDE_BUFFER,
  838. Buffer);
  839. ASSERT(SideBuffer->Signature == 'JLBS');
  840. ASSERT(SideBuffer->Fobx == capFobx);
  841. ASSERT(SideBuffer->Fcb == capFcb);
  842. ASSERT(SideBuffer->smbFobx == smbFobx);
  843. ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
  844. }
  845. Status = SmbCeTransact(
  846. RxContext,
  847. pTransactionOptions,
  848. &Setup,
  849. sizeof(Setup),
  850. NULL,
  851. 0,
  852. SendParamsBuffer,
  853. SendParamsBufferLength,
  854. ReceiveParamsBuffer,
  855. ReceiveParamsBufferLength,
  856. NULL,
  857. 0,
  858. DirEntriesAreUaligned?UnalignedDirEntrySideBuffer:Buffer, // the buffer for data
  859. DirEntriesAreUaligned?UnalignedDirEntrySideBufferSize:*pLengthRemaining, // the length of the buffer
  860. &ResumptionContext);
  861. if (NT_SUCCESS(Status)) {
  862. BOOLEAN EndOfSearchReached;
  863. {
  864. PSIDE_BUFFER SideBuffer;
  865. SideBuffer = (PSIDE_BUFFER)CONTAINING_RECORD(
  866. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  867. SIDE_BUFFER,
  868. Buffer);
  869. ASSERT(SideBuffer->Signature == 'JLBS');
  870. ASSERT(SideBuffer->Fobx == capFobx);
  871. ASSERT(SideBuffer->Fcb == capFcb);
  872. ASSERT(SideBuffer->smbFobx == smbFobx);
  873. ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
  874. }
  875. if (NT_SUCCESS(Status)) {
  876. // a) need to set the length remaining correctly
  877. // b) need to setup for a resume and see if the search was closed
  878. ULONG LastNameOffset=0;
  879. PMRX_SMB_DIRECTORY_RESUME_INFO ResumeInfo = NULL;
  880. ULONG OriginalBufferLength = *pLengthRemaining;
  881. IF_DEBUG { LastNameOffset = 0x40000000; }
  882. RetryCount = 0;
  883. smbFobx->Enumeration.Flags |= SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST;
  884. smbFobx->Enumeration.TotalDataBytesReturned = ResumptionContext.DataBytesReceived;
  885. if (Setup == TRANS2_FIND_FIRST2) {
  886. smbFobx->Enumeration.SearchHandle = FindFirst2Response.Sid;
  887. smbFobx->Enumeration.Version = ResumptionContext.ServerVersion;
  888. smbFobx->Enumeration.Flags |= SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN; //but look right below
  889. EndOfSearchReached = (BOOLEAN)FindFirst2Response.EndOfSearch;
  890. FilesReturned = FindFirst2Response.SearchCount;
  891. LastNameOffset = FindFirst2Response.LastNameOffset;
  892. } else {
  893. EndOfSearchReached = (BOOLEAN)XX.FindNext2Response.EndOfSearch;
  894. FilesReturned = XX.FindNext2Response.SearchCount;
  895. LastNameOffset = XX.FindNext2Response.LastNameOffset;
  896. }
  897. //
  898. // Please note: LANMAN 2.x servers prematurely set the
  899. // EndOfSearch flag, so we must ignore it on LM 2.x servers.
  900. //
  901. // NT Returns the correct information, none of the LM varients
  902. // appear to do so.
  903. //
  904. if (IsNonNtT2Find) {
  905. EndOfSearchReached = FALSE;
  906. }
  907. if (Status==STATUS_SUCCESS && FilesReturned==0) {
  908. RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: no files returned...switch status\n"));
  909. EndOfSearchReached = TRUE;
  910. Status = STATUS_NO_MORE_FILES;
  911. }
  912. if (!DirEntriesAreUaligned) {
  913. *pLengthRemaining -= ResumptionContext.DataBytesReceived;
  914. if (EndOfSearchReached) {
  915. smbFobx->Enumeration.ErrorStatus = STATUS_NO_MORE_FILES;
  916. }
  917. }
  918. if (EndOfSearchReached ||
  919. SearchFlags & SMB_FIND_CLOSE_AFTER_REQUEST) {
  920. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN);
  921. }
  922. if (FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN)) {
  923. //if the search handle is open, then we set up to resume
  924. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectory: rinfo = %08lx\n", smbFobx->Enumeration.ResumeInfo));
  925. if (smbFobx->Enumeration.ResumeInfo==NULL) {
  926. smbFobx->Enumeration.ResumeInfo =
  927. (PMRX_SMB_DIRECTORY_RESUME_INFO)RxAllocatePoolWithTag(
  928. PagedPool,
  929. sizeof(MRX_SMB_DIRECTORY_RESUME_INFO),
  930. MRXSMB_DIRCTL_POOLTAG);
  931. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectory: allocatedinfo = %08lx\n", ResumeInfo));
  932. if (smbFobx->Enumeration.ResumeInfo == NULL) {
  933. Status = STATUS_INSUFFICIENT_RESOURCES;
  934. goto FINALLY;
  935. }
  936. }
  937. ResumeInfo = smbFobx->Enumeration.ResumeInfo;
  938. ASSERT (ResumeInfo!=NULL);
  939. {
  940. PSIDE_BUFFER SideBuffer;
  941. SideBuffer = (PSIDE_BUFFER)CONTAINING_RECORD(
  942. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  943. SIDE_BUFFER,
  944. Buffer);
  945. ASSERT(SideBuffer->Signature == 'JLBS');
  946. ASSERT(SideBuffer->Fobx == capFobx);
  947. ASSERT(SideBuffer->Fcb == capFcb);
  948. ASSERT(SideBuffer->smbFobx == smbFobx);
  949. ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
  950. }
  951. RxLog(("MRxqdir: rinfo = %lx", smbFobx->Enumeration.ResumeInfo));
  952. RxLog(("MRxqdir2: olen = %lx, thisl = %lx",
  953. OriginalBufferLength, ResumptionContext.DataBytesReceived));
  954. if (!DirEntriesAreUaligned) {
  955. PBYTE LastEntry = ((PBYTE)Buffer)+LastNameOffset;
  956. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectory: lastentry = %08lx\n", LastEntry));
  957. //this is for NT....the data is already in the buffer.......just setup the resume info
  958. if (SmbFileInfoLevel>=SMB_FIND_FILE_DIRECTORY_INFO) { //we may start sending nonNT levels...could be an assert
  959. PREQ_FIND_NEXT2 pFindNext2Request = &ResumeInfo->FindNext2_Request;
  960. ULONG resumekey = ((PFILE_FULL_DIR_INFORMATION)LastEntry)->FileIndex;
  961. ULONG FileNameLength; PWCHAR FileNameBuffer;
  962. pFindNext2Request->ResumeKey = resumekey;
  963. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectory: resumekey = %08lx\n", resumekey));
  964. FileNameLength = *((PULONG)(LastEntry+smbFobx->Enumeration.FileNameLengthOffset));
  965. FileNameBuffer = (PWCHAR)(LastEntry+smbFobx->Enumeration.FileNameOffset);
  966. IF_DEBUG {
  967. UNICODE_STRING LastName;
  968. LastName.Buffer = FileNameBuffer;
  969. LastName.Length = (USHORT)FileNameLength;
  970. RxDbgTrace(0,Dbg,("MRxSmbQueryDirectory: resumename = %wZ\n", &LastName));
  971. }
  972. ASSERT ( (((PBYTE)FileNameBuffer)+FileNameLength)
  973. <=(((PBYTE)Buffer)+OriginalBufferLength) );
  974. RtlCopyMemory(&pFindNext2Request->Buffer[0],FileNameBuffer,FileNameLength);
  975. //buffer is a UCHAR...not WCHAR
  976. pFindNext2Request->Buffer[FileNameLength] = 0; //nullterminated in unicode
  977. pFindNext2Request->Buffer[FileNameLength+1] = 0; //nullterminated in unicode
  978. smbFobx->Enumeration.ResumeInfo->ParametersLength
  979. = (USHORT)(&pFindNext2Request->Buffer[FileNameLength+2] - (PBYTE)pFindNext2Request);
  980. } else {
  981. ASSERT(!"don't know how to get resume key/name for nonNT");
  982. }
  983. }
  984. }
  985. {
  986. PSIDE_BUFFER SideBuffer;
  987. SideBuffer = (PSIDE_BUFFER)CONTAINING_RECORD(
  988. smbFobx->Enumeration.UnalignedDirEntrySideBuffer,
  989. SIDE_BUFFER,
  990. Buffer);
  991. ASSERT(SideBuffer->Signature == 'JLBS');
  992. ASSERT(SideBuffer->Fobx == capFobx);
  993. ASSERT(SideBuffer->Fcb == capFcb);
  994. ASSERT(SideBuffer->smbFobx == smbFobx);
  995. ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
  996. }
  997. //for NT we are finished. for win95 we have to go thru the side buffer and
  998. // 1) copy in the data transforming ascii->unicode on the names, and
  999. // 2) remember the resume key and the filename of the last guy that we process
  1000. // because win95 doesn't 8byte aling things and because of unicode, we could end up
  1001. // with more data in the sidebuffer than we can return.
  1002. // the code is moved down because we want to do it after the unlock
  1003. }
  1004. if (DirEntriesAreUaligned && (Status == STATUS_SUCCESS)) {
  1005. smbFobx->Enumeration.FilesReturned = FilesReturned;
  1006. smbFobx->Enumeration.EntryOffset = 0;
  1007. //smbFobx->Enumeration.ReturnedEntryOffset = 0;
  1008. smbFobx->Enumeration.EndOfSearchReached = EndOfSearchReached;
  1009. //smbFobx->Enumeration.UnalignedDirEntrySideBuffer = UnalignedDirEntrySideBuffer;
  1010. Status = MrxSmbUnalignedDirEntryCopyTail(
  1011. /*IN OUT PRX_CONTEXT */ RxContext,
  1012. /*IN FILE_INFORMATION_CLASS */ FileInformationClass,
  1013. /*IN OUT PVOID */ Buffer,
  1014. /*IN OUT PULONG */ pLengthRemaining,
  1015. /*IN OUT PMRX_SMB_FOBX */ smbFobx
  1016. );
  1017. }
  1018. } else {
  1019. // CODE IMPROVEMENT we should cache the file not found for findfirst as well
  1020. }
  1021. FINALLY:
  1022. //for downlevel-T2, we will have to go back to the server for some more.....sigh.......
  1023. if (Status==STATUS_MORE_PROCESSING_REQUIRED) {
  1024. goto RETRY_____;
  1025. }
  1026. //
  1027. // under stress, the win95 server returns this......
  1028. if ( (Status == STATUS_UNEXPECTED_NETWORK_ERROR)
  1029. && FlagOn(pServerEntry->Server.DialectFlags,DF_W95)
  1030. && (RetryCount < 10) ) {
  1031. RetryCount++;
  1032. MRxSmbWin95Retries++;
  1033. goto RETRY_____;
  1034. }
  1035. if (pFindFirst2Request) RxFreePool(pFindFirst2Request);
  1036. if (!NT_SUCCESS(Status)) {
  1037. RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: Failed .. returning %lx\n",Status));
  1038. //smbFobx->Enumeration.Flags &= ~SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN;
  1039. smbFobx->Enumeration.ErrorStatus = Status; //keep returning this
  1040. MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"ErrOut");
  1041. if (smbFobx->Enumeration.ResumeInfo!=NULL) {
  1042. RxFreePool(smbFobx->Enumeration.ResumeInfo);
  1043. smbFobx->Enumeration.ResumeInfo = NULL;
  1044. }
  1045. }
  1046. RxDbgTraceUnIndent(-1,Dbg);
  1047. return Status;
  1048. }
  1049. RXDT_DefineCategory(VOLINFO);
  1050. #undef Dbg
  1051. #define Dbg (DEBUG_TRACE_VOLINFO)
  1052. NTSTATUS
  1053. MRxSmbQueryVolumeInformationWithFullBuffer(
  1054. IN OUT PRX_CONTEXT RxContext
  1055. );
  1056. NTSTATUS
  1057. MRxSmbQueryVolumeInformation(
  1058. IN OUT PRX_CONTEXT RxContext
  1059. )
  1060. /*++
  1061. Routine Description:
  1062. This routine queries the volume information. Since the NT server does not
  1063. handle bufferoverflow gracefully on query-fs-info, we allocate a buffer here
  1064. that is big enough to hold anything passed back; then we call the "real"
  1065. queryvolinfo routine.
  1066. Arguments:
  1067. pRxContext - the RDBSS context
  1068. Return Value:
  1069. RXSTATUS - The return status for the operation
  1070. --*/
  1071. {
  1072. NTSTATUS Status;
  1073. RxCaptureFcb; RxCaptureFobx;
  1074. PVOID OriginalBuffer;
  1075. ULONG OriginalLength = RxContext->Info.LengthRemaining;
  1076. ULONG ReturnedLength;
  1077. BOOLEAN UsingSideBuffer = FALSE;
  1078. struct {
  1079. union {
  1080. FILE_FS_LABEL_INFORMATION labelinfo;
  1081. FILE_FS_VOLUME_INFORMATION volumeinfo;
  1082. FILE_FS_SIZE_INFORMATION sizeinfo;
  1083. FILE_FS_DEVICE_INFORMATION deviceinfo;
  1084. FILE_FS_ATTRIBUTE_INFORMATION attributeinfo;
  1085. } Info;
  1086. WCHAR VolumeName[MAXIMUM_FILENAME_LENGTH];
  1087. } SideBuffer;
  1088. PAGED_CODE();
  1089. if( RxContext->Info.LengthRemaining < sizeof( SideBuffer ) ) {
  1090. //
  1091. // i replace the buffer and length in the context with my stuff.
  1092. // This, of course, means that we can't go async....for that we'd
  1093. // have to allocate instead of using a stack-allocated buffer.
  1094. UsingSideBuffer = TRUE;
  1095. OriginalBuffer = RxContext->Info.Buffer;
  1096. RxContext->Info.Buffer = &SideBuffer;
  1097. RxContext->Info.LengthRemaining = sizeof(SideBuffer);
  1098. }
  1099. Status = MRxSmbQueryVolumeInformationWithFullBuffer(RxContext);
  1100. if (Status != STATUS_SUCCESS) {
  1101. goto FINALLY;
  1102. }
  1103. if( UsingSideBuffer == TRUE ) {
  1104. ReturnedLength = sizeof(SideBuffer) - RxContext->Info.LengthRemaining;
  1105. } else {
  1106. ReturnedLength = OriginalLength - RxContext->Info.LengthRemaining;
  1107. }
  1108. if (ReturnedLength > OriginalLength) {
  1109. Status = STATUS_BUFFER_OVERFLOW;
  1110. ReturnedLength = OriginalLength;
  1111. }
  1112. if( UsingSideBuffer == TRUE ) {
  1113. RtlCopyMemory(OriginalBuffer,&SideBuffer,ReturnedLength);
  1114. }
  1115. RxContext->Info.LengthRemaining = OriginalLength - ReturnedLength;
  1116. FINALLY:
  1117. return Status;
  1118. }
  1119. NTSTATUS
  1120. MRxSmbQueryVolumeInformationWithFullBuffer(
  1121. IN OUT PRX_CONTEXT RxContext
  1122. )
  1123. /*++
  1124. Routine Description:
  1125. This routine queries the volume information
  1126. Arguments:
  1127. pRxContext - the RDBSS context
  1128. FsInformationClass - the kind of Fs information desired.
  1129. pBuffer - the buffer for copying the information
  1130. pBufferLength - the buffer length ( set to buffer length on input and set
  1131. to the remaining length on output)
  1132. Return Value:
  1133. RXSTATUS - The return status for the operation
  1134. --*/
  1135. {
  1136. NTSTATUS Status;
  1137. RxCaptureFcb;
  1138. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  1139. RxCaptureFobx;
  1140. FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
  1141. PVOID pBuffer = RxContext->Info.Buffer;
  1142. PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
  1143. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1144. BOOLEAN DoAsDownLevel;
  1145. PVOID pInputParamBuffer;
  1146. ULONG InputParamBufferLength;
  1147. USHORT InformationLevel;
  1148. USHORT Setup;
  1149. REQ_QUERY_FS_INFORMATION QueryFsInformationRequest;
  1150. REQ_QUERY_FS_INFORMATION_FID DfsQueryFsInformationRequest;
  1151. PAGED_CODE();
  1152. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1153. if ( FsInformationClass == FileFsDeviceInformation ) {
  1154. PFILE_FS_DEVICE_INFORMATION UsersBuffer = (PFILE_FS_DEVICE_INFORMATION)pBuffer;
  1155. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1156. UsersBuffer->Characteristics = FILE_REMOTE_DEVICE;
  1157. if (NetRoot->Type==NET_ROOT_PIPE) {
  1158. NetRoot->DeviceType = RxDeviceType(NAMED_PIPE);
  1159. return STATUS_INVALID_PARAMETER;
  1160. }
  1161. else
  1162. {
  1163. UsersBuffer->DeviceType = NetRoot->DeviceType;
  1164. *pLengthRemaining -= (sizeof(FILE_FS_DEVICE_INFORMATION));
  1165. RxDbgTrace( 0, Dbg, ("MRxSmbQueryVolumeInformation: devinfo .. returning\n"));
  1166. return STATUS_SUCCESS;
  1167. }
  1168. }
  1169. if (capFobx == NULL) {
  1170. return STATUS_INVALID_PARAMETER;
  1171. }
  1172. TURN_BACK_ASYNCHRONOUS_OPERATIONS();
  1173. for (;;) {
  1174. if (capFobx != NULL) {
  1175. PMRX_V_NET_ROOT pVNetRoot;
  1176. // Avoid device opens for which the FOBX is the VNET_ROOT instance
  1177. pVNetRoot = (PMRX_V_NET_ROOT)capFobx;
  1178. if (NodeType(pVNetRoot) != RDBSS_NTC_V_NETROOT) {
  1179. PUNICODE_STRING AlreadyPrefixedName =
  1180. GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1181. ULONG FcbAlreadyPrefixedNameLength = AlreadyPrefixedName->Length;
  1182. ULONG NetRootInnerNamePrefixLength = capFcb->pNetRoot->InnerNamePrefix.Length;
  1183. PWCHAR pName = AlreadyPrefixedName->Buffer;
  1184. // If an FSCTL is being attempted against the root of a share.
  1185. // The AlreadyPrefixedName associated with the FCB is the same as
  1186. // the AlreadyPrefixedName length associated with the NET_ROOT instance
  1187. // or atmost one character greater than it ( appending a \) try and
  1188. // reestablish the connection before attempting the FSCTL.
  1189. // This solves thorny issues regarding deletion/creation of shares
  1190. // on the server sides, DFS referrals etc.
  1191. if ((FcbAlreadyPrefixedNameLength == NetRootInnerNamePrefixLength) ||
  1192. ((FcbAlreadyPrefixedNameLength == NetRootInnerNamePrefixLength + sizeof(WCHAR)) &&
  1193. (*((PCHAR)pName + FcbAlreadyPrefixedNameLength - sizeof(WCHAR)) ==
  1194. L'\\'))) {
  1195. Status = SmbCeReconnect(capFobx->pSrvOpen->pVNetRoot);
  1196. }
  1197. }
  1198. }
  1199. DoAsDownLevel = MRxSmbForceCoreInfo;
  1200. if (!FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
  1201. DoAsDownLevel = TRUE;
  1202. }
  1203. if (FlagOn(pServerEntry->Server.DialectFlags,DF_W95)
  1204. && (FsInformationClass==FileFsAttributeInformation)){ //use uplevel for w95 attribute info
  1205. DoAsDownLevel = FALSE;
  1206. }
  1207. if (DoAsDownLevel) {
  1208. return MRxSmbCoreInformation(RxContext,
  1209. (ULONG)FsInformationClass,
  1210. pBuffer,
  1211. pLengthRemaining,
  1212. SMBPSE_OE_FROM_QUERYVOLUMEINFO
  1213. );
  1214. }
  1215. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1216. switch (FsInformationClass) {
  1217. case FileFsVolumeInformation :
  1218. InformationLevel = SMB_QUERY_FS_VOLUME_INFO;
  1219. break;
  1220. case FileFsLabelInformation :
  1221. InformationLevel = SMB_QUERY_FS_LABEL_INFO;
  1222. break;
  1223. case FileFsSizeInformation :
  1224. InformationLevel = SMB_QUERY_FS_SIZE_INFO;
  1225. break;
  1226. case FileFsAttributeInformation :
  1227. InformationLevel = SMB_QUERY_FS_ATTRIBUTE_INFO;
  1228. break;
  1229. default:
  1230. if( FlagOn( pServerEntry->Server.DialectFlags, DF_NT_INFO_PASSTHROUGH ) ) {
  1231. InformationLevel = FsInformationClass + SMB_INFO_PASSTHROUGH;
  1232. } else {
  1233. RxDbgTrace( 0, Dbg, ("MRxSmbQueryVolumeInformation: Invalid FS information class\n"));
  1234. Status = STATUS_INVALID_PARAMETER;
  1235. }
  1236. break;
  1237. }
  1238. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1239. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  1240. PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
  1241. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  1242. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1243. if (!FlagOn(pServerEntry->Server.DialectFlags,DF_DFS_TRANS2)) {
  1244. Setup = TRANS2_QUERY_FS_INFORMATION;
  1245. QueryFsInformationRequest.InformationLevel = InformationLevel;
  1246. pInputParamBuffer = &QueryFsInformationRequest;
  1247. InputParamBufferLength = sizeof(QueryFsInformationRequest);
  1248. } else {
  1249. Setup = TRANS2_QUERY_FS_INFORMATION_FID;
  1250. DfsQueryFsInformationRequest.InformationLevel = InformationLevel;
  1251. DfsQueryFsInformationRequest.Fid = smbSrvOpen->Fid;
  1252. pInputParamBuffer = &DfsQueryFsInformationRequest;
  1253. InputParamBufferLength = sizeof(DfsQueryFsInformationRequest);
  1254. }
  1255. Status = SmbCeTransact(
  1256. RxContext,
  1257. pTransactionOptions,
  1258. &Setup,
  1259. sizeof(Setup),
  1260. NULL,
  1261. 0,
  1262. pInputParamBuffer,
  1263. InputParamBufferLength,
  1264. NULL,
  1265. 0,
  1266. NULL,
  1267. 0,
  1268. pBuffer,
  1269. *pLengthRemaining,
  1270. &ResumptionContext);
  1271. if (NT_SUCCESS(Status)) {
  1272. *pLengthRemaining -= ResumptionContext.DataBytesReceived;
  1273. }
  1274. }
  1275. if (!NT_SUCCESS(Status)) {
  1276. RxDbgTrace( 0, Dbg, ("MRxSmbQueryVolumeInformation: Failed .. returning %lx\n",Status));
  1277. }
  1278. if (Status != STATUS_NETWORK_NAME_DELETED) {
  1279. break;
  1280. }
  1281. }
  1282. return Status;
  1283. }
  1284. NTSTATUS
  1285. MRxSmbSetVolumeInformation(
  1286. IN OUT PRX_CONTEXT RxContext
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. This routine sets the volume information
  1291. Arguments:
  1292. pRxContext - the RDBSS context
  1293. FsInformationClass - the kind of Fs information desired.
  1294. pBuffer - the buffer for copying the information
  1295. BufferLength - the buffer length
  1296. Return Value:
  1297. RXSTATUS - The return status for the operation
  1298. --*/
  1299. {
  1300. NTSTATUS Status;
  1301. RxCaptureFcb;
  1302. RxCaptureFobx;
  1303. FILE_INFORMATION_CLASS FileInformationClass;
  1304. PVOID pBuffer;
  1305. ULONG BufferLength;
  1306. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1307. BOOLEAN ServerSupportsPassThroughForSetInfo = FALSE;
  1308. PAGED_CODE();
  1309. TURN_BACK_ASYNCHRONOUS_OPERATIONS();
  1310. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1311. FileInformationClass = RxContext->Info.FileInformationClass;
  1312. pBuffer = RxContext->Info.Buffer;
  1313. BufferLength = RxContext->Info.Length;
  1314. if (!MRxSmbForceCoreInfo &&
  1315. FlagOn( pServerEntry->Server.DialectFlags, DF_NT_INFO_PASSTHROUGH)) {
  1316. ServerSupportsPassThroughForSetInfo = TRUE;
  1317. }
  1318. if (ServerSupportsPassThroughForSetInfo) {
  1319. USHORT Setup = TRANS2_SET_FS_INFORMATION;
  1320. REQ_SET_FS_INFORMATION SetFsInfoRequest;
  1321. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  1322. PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
  1323. if (capFobx != NULL) {
  1324. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  1325. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1326. SetFsInfoRequest.Fid = smbSrvOpen->Fid;
  1327. SetFsInfoRequest.InformationLevel = FileInformationClass +
  1328. SMB_INFO_PASSTHROUGH;
  1329. Status = SmbCeTransact(
  1330. RxContext,
  1331. pTransactionOptions,
  1332. &Setup,
  1333. sizeof(Setup),
  1334. NULL,
  1335. 0,
  1336. &SetFsInfoRequest,
  1337. sizeof(SetFsInfoRequest),
  1338. NULL,
  1339. 0,
  1340. pBuffer,
  1341. BufferLength,
  1342. NULL,
  1343. 0,
  1344. &ResumptionContext);
  1345. } else {
  1346. Status = STATUS_INVALID_PARAMETER;
  1347. }
  1348. } else {
  1349. Status = STATUS_NOT_SUPPORTED;
  1350. }
  1351. if (!NT_SUCCESS(Status)) {
  1352. RxDbgTrace( 0, Dbg, ("MRxSmbSetFile: Failed .. returning %lx\n",Status));
  1353. }
  1354. RxDbgTraceUnIndent(-1,Dbg);
  1355. return Status;
  1356. }
  1357. RXDT_DefineCategory(FILEINFO);
  1358. #undef Dbg
  1359. #define Dbg (DEBUG_TRACE_FILEINFO)
  1360. LONG GFAFromLocal;
  1361. NTSTATUS
  1362. MRxSmbQueryFileInformation(
  1363. IN PRX_CONTEXT RxContext )
  1364. /*++
  1365. Routine Description:
  1366. This routine does a query file info.
  1367. Arguments:
  1368. RxContext - the RDBSS context
  1369. Return Value:
  1370. NTSTATUS - The return status for the operation
  1371. --*/
  1372. {
  1373. NTSTATUS Status;
  1374. RxCaptureFcb;
  1375. RxCaptureFobx;
  1376. FILE_INFORMATION_CLASS FileInformationClass;
  1377. PVOID pBuffer;
  1378. PULONG pLengthRemaining;
  1379. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1380. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  1381. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  1382. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  1383. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1384. PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1385. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1386. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)SrvOpen->pVNetRoot->Context;
  1387. PSMBCE_NET_ROOT pSmbNetRoot = &pVNetRootContext->pNetRootEntry->NetRoot;
  1388. USHORT SmbFileInfoLevel;
  1389. USHORT Setup;
  1390. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  1391. PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
  1392. REQ_QUERY_FILE_INFORMATION QueryFileInfoRequest;
  1393. RESP_QUERY_FILE_INFORMATION QueryFileInfoResponse;
  1394. PREQ_QUERY_PATH_INFORMATION pQueryFilePathRequest = NULL;
  1395. PVOID pSendParameterBuffer;
  1396. ULONG SendParameterBufferLength;
  1397. PAGED_CODE();
  1398. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1399. FileInformationClass = RxContext->Info.FileInformationClass;
  1400. pBuffer = RxContext->Info.Buffer;
  1401. pLengthRemaining = &RxContext->Info.LengthRemaining;
  1402. RxDbgTrace(+1, Dbg, ("MRxSmbQueryFileInformation: class=%08lx\n",FileInformationClass));
  1403. TURN_BACK_ASYNCHRONOUS_OPERATIONS();
  1404. Status = STATUS_SUCCESS;
  1405. switch (FileInformationClass) {
  1406. case FilePipeLocalInformation:
  1407. case FilePipeInformation:
  1408. case FilePipeRemoteInformation:
  1409. Status = STATUS_INVALID_PARAMETER;
  1410. goto FINALLY;
  1411. break;
  1412. case FileEaInformation:
  1413. if (smbSrvOpen->IsNtCreate &&
  1414. smbSrvOpen->FileStatusFlags & SMB_FSF_NO_EAS &&
  1415. (smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_BATCH ||
  1416. smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_EXCLUSIVE)) {
  1417. PFILE_EA_INFORMATION EaBuffer = (PFILE_EA_INFORMATION)pBuffer;
  1418. EaBuffer->EaSize = 0;
  1419. RxContext->Info.LengthRemaining -= sizeof(FILE_EA_INFORMATION);
  1420. goto FINALLY;
  1421. }
  1422. break;
  1423. case FileStreamInformation:
  1424. if (pSmbNetRoot->NetRootFileSystem == NET_ROOT_FILESYSTEM_FAT) {
  1425. // FAT doesn't have the stream
  1426. Status = STATUS_INVALID_PARAMETER;
  1427. goto FINALLY;
  1428. }
  1429. break;
  1430. case FileAttributeTagInformation:
  1431. if (pSmbNetRoot->NetRootFileSystem == NET_ROOT_FILESYSTEM_FAT ||
  1432. smbSrvOpen->IsNtCreate &&
  1433. smbSrvOpen->FileStatusFlags & SMB_FSF_NO_REPARSETAG &&
  1434. (smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_BATCH ||
  1435. smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_EXCLUSIVE)) {
  1436. PFILE_ATTRIBUTE_TAG_INFORMATION TagBuffer = (PFILE_ATTRIBUTE_TAG_INFORMATION)pBuffer;
  1437. TagBuffer->FileAttributes = smbSrvOpen->FileInfo.Basic.FileAttributes;
  1438. TagBuffer->ReparseTag = 0;
  1439. RxContext->Info.LengthRemaining -= sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
  1440. goto FINALLY;
  1441. }
  1442. }
  1443. if( MRxSmbForceCoreInfo ||
  1444. !FlagOn( pServerEntry->Server.DialectFlags, DF_NT_INFO_PASSTHROUGH )) {
  1445. switch (FileInformationClass) {
  1446. case FileBasicInformation:
  1447. SmbFileInfoLevel = SMB_QUERY_FILE_BASIC_INFO;
  1448. break;
  1449. case FileStandardInformation:
  1450. SmbFileInfoLevel = SMB_QUERY_FILE_STANDARD_INFO;
  1451. break;
  1452. case FileEaInformation:
  1453. SmbFileInfoLevel = SMB_QUERY_FILE_EA_INFO;
  1454. break;
  1455. case FileAllocationInformation:
  1456. SmbFileInfoLevel = SMB_QUERY_FILE_ALLOCATION_INFO;
  1457. break;
  1458. case FileEndOfFileInformation:
  1459. SmbFileInfoLevel = SMB_QUERY_FILE_END_OF_FILEINFO;
  1460. break;
  1461. case FileAlternateNameInformation:
  1462. SmbFileInfoLevel = SMB_QUERY_FILE_ALT_NAME_INFO;
  1463. break;
  1464. case FileStreamInformation:
  1465. SmbFileInfoLevel = SMB_QUERY_FILE_STREAM_INFO;
  1466. break;
  1467. case FileCompressionInformation:
  1468. SmbFileInfoLevel = SMB_QUERY_FILE_COMPRESSION_INFO;
  1469. break;
  1470. case FileInternalInformation:
  1471. {
  1472. PFILE_INTERNAL_INFORMATION UsersBuffer = (PFILE_INTERNAL_INFORMATION)pBuffer;
  1473. //
  1474. // Note: We use the address of the FCB to determine the
  1475. // index number of the file. If we have to maintain persistance between
  1476. // file opens for this request, then we might have to do something
  1477. // like checksuming the reserved fields on a FUNIQUE SMB response.
  1478. //
  1479. //
  1480. // NT64: the address of capFcb used to be stuffed into
  1481. // IndexNumber.LowPart, with HighPart being zeroed.
  1482. //
  1483. // Whoever is asking for this pointer value should be
  1484. // prepared to deal with the returned 64-bit value.
  1485. //
  1486. UsersBuffer->IndexNumber.QuadPart = (ULONG_PTR)capFcb;
  1487. *pLengthRemaining -= sizeof(FILE_INTERNAL_INFORMATION);
  1488. Status = STATUS_SUCCESS;
  1489. }
  1490. goto FINALLY;
  1491. default:
  1492. RxDbgTrace( 0, Dbg, ("MRxSmbQueryFile: Invalid FS information class\n"));
  1493. Status = STATUS_INVALID_PARAMETER;
  1494. goto FINALLY;
  1495. }
  1496. } else {
  1497. //
  1498. // This server supports transparent NT information level passthrough. So
  1499. // just pass the request on to the server.
  1500. //
  1501. SmbFileInfoLevel = FileInformationClass + SMB_INFO_PASSTHROUGH;
  1502. }
  1503. if (MRxSmbForceCoreInfo ||
  1504. FlagOn(pServerEntry->Server.DialectFlags,DF_W95) ||
  1505. !FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
  1506. // Win9x server supports NT SMB but doesn't support transact2. Therefore we use core.
  1507. return MRxSmbCoreInformation(
  1508. RxContext,
  1509. (ULONG)SmbFileInfoLevel,
  1510. pBuffer,
  1511. pLengthRemaining,
  1512. SMBPSE_OE_FROM_QUERYFILEINFO
  1513. );
  1514. }
  1515. Status = STATUS_SUCCESS;
  1516. if (!FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  1517. //here, the FID is valid. do a t2_QFI
  1518. Setup = TRANS2_QUERY_FILE_INFORMATION;
  1519. QueryFileInfoRequest.Fid = smbSrvOpen->Fid;
  1520. QueryFileInfoRequest.InformationLevel = SmbFileInfoLevel;
  1521. pSendParameterBuffer = &QueryFileInfoRequest;
  1522. SendParameterBufferLength = sizeof(QueryFileInfoRequest);
  1523. RxDbgTrace(0, Dbg, (" fid,smbclass=%08lx,%08lx\n",smbSrvOpen->Fid,SmbFileInfoLevel));
  1524. } else {
  1525. OEM_STRING OemName;
  1526. BOOLEAN FreeOemName = FALSE;
  1527. Setup = TRANS2_QUERY_PATH_INFORMATION;
  1528. if (!FlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE)) {
  1529. if (FlagOn(pServerEntry->Server.DialectFlags,DF_LONGNAME)) {
  1530. Status = RtlUnicodeStringToOemString(&OemName, RemainingName, TRUE);
  1531. } else {
  1532. Status = RtlUpcaseUnicodeStringToOemString(&OemName, RemainingName, TRUE);
  1533. }
  1534. if (Status == STATUS_SUCCESS) {
  1535. SendParameterBufferLength = FIELD_OFFSET(REQ_QUERY_PATH_INFORMATION,Buffer[0])
  1536. + OemName.Length + sizeof(CHAR); //null-terminated
  1537. FreeOemName = TRUE;
  1538. }
  1539. } else {
  1540. SendParameterBufferLength = FIELD_OFFSET(REQ_QUERY_PATH_INFORMATION,Buffer[0])
  1541. + RemainingName->Length + sizeof(WCHAR); //null-terminated
  1542. }
  1543. if (Status == STATUS_SUCCESS) {
  1544. pSendParameterBuffer = RxAllocatePoolWithTag(PagedPool,
  1545. SendParameterBufferLength,
  1546. MRXSMB_QPINFO_POOLTAG);
  1547. pQueryFilePathRequest = pSendParameterBuffer;
  1548. if (pQueryFilePathRequest != NULL) {
  1549. pQueryFilePathRequest->InformationLevel = SmbFileInfoLevel;
  1550. SmbPutUlong(&pQueryFilePathRequest->Reserved,0);
  1551. if (FlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE)) {
  1552. RtlCopyMemory(&pQueryFilePathRequest->Buffer[0],RemainingName->Buffer,RemainingName->Length);
  1553. *((PWCHAR)(&pQueryFilePathRequest->Buffer[RemainingName->Length])) = 0;
  1554. } else {
  1555. RtlCopyMemory(&pQueryFilePathRequest->Buffer[0],OemName.Buffer,OemName.Length);
  1556. *((PCHAR)(&pQueryFilePathRequest->Buffer[OemName.Length])) = 0;
  1557. }
  1558. } else {
  1559. Status = STATUS_INSUFFICIENT_RESOURCES;
  1560. }
  1561. }
  1562. if (FreeOemName) {
  1563. RtlFreeOemString(&OemName);
  1564. }
  1565. }
  1566. if (Status == STATUS_SUCCESS) {
  1567. Status = SmbCeTransact(
  1568. RxContext,
  1569. pTransactionOptions,
  1570. &Setup,
  1571. sizeof(Setup),
  1572. NULL,
  1573. 0,
  1574. pSendParameterBuffer,
  1575. SendParameterBufferLength,
  1576. &QueryFileInfoResponse,
  1577. sizeof(QueryFileInfoResponse),
  1578. NULL,
  1579. 0,
  1580. pBuffer,
  1581. *pLengthRemaining,
  1582. &ResumptionContext);
  1583. if (NT_SUCCESS(Status)) {
  1584. *pLengthRemaining -= ResumptionContext.DataBytesReceived;
  1585. }
  1586. }
  1587. //
  1588. // Check for file not found status. If this is the case then create a
  1589. // name cache entry in the NetRoot name cache and record the status,
  1590. // the smb received count and set the expiration time for 5 seconds.
  1591. // Why: NB4 case of back to back srv reqs with 2nd req upcased.
  1592. //
  1593. FINALLY:
  1594. if (pQueryFilePathRequest != NULL) {
  1595. RxFreePool(pQueryFilePathRequest);
  1596. }
  1597. if (!NT_SUCCESS(Status)) {
  1598. RxDbgTrace( 0, Dbg, ("MRxSmbQueryFile: Failed .. returning %lx\n",Status));
  1599. }
  1600. RxDbgTraceUnIndent(-1,Dbg);
  1601. return Status;
  1602. }
  1603. NTSTATUS
  1604. MRxSmbQueryFileInformationFromPseudoOpen(
  1605. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  1606. )
  1607. /*++
  1608. Routine Description:
  1609. This routine does a query file basic info from pseudo open.
  1610. Arguments:
  1611. RxContext - the RDBSS context
  1612. Return Value:
  1613. NTSTATUS - The return status for the operation
  1614. --*/
  1615. {
  1616. NTSTATUS Status;
  1617. PRX_CONTEXT LocalRxContext;
  1618. PAGED_CODE();
  1619. LocalRxContext = RxAllocatePoolWithTag(NonPagedPool,
  1620. sizeof(RX_CONTEXT),
  1621. MRXSMB_RXCONTEXT_POOLTAG);
  1622. if (LocalRxContext == NULL) {
  1623. Status = STATUS_INSUFFICIENT_RESOURCES;
  1624. } else {
  1625. RtlZeroMemory(
  1626. LocalRxContext,
  1627. sizeof(RX_CONTEXT));
  1628. RxInitializeContext(
  1629. NULL,
  1630. RxContext->RxDeviceObject,
  1631. 0,
  1632. LocalRxContext );
  1633. LocalRxContext->pFcb = RxContext->pFcb;
  1634. LocalRxContext->pFobx = RxContext->pFobx;
  1635. LocalRxContext->CurrentIrp = RxContext->CurrentIrp;
  1636. LocalRxContext->CurrentIrpSp = RxContext->CurrentIrpSp;
  1637. LocalRxContext->NonPagedFcb = RxContext->NonPagedFcb;
  1638. LocalRxContext->MajorFunction = IRP_MJ_CREATE;
  1639. LocalRxContext->pRelevantSrvOpen = RxContext->pRelevantSrvOpen;;
  1640. LocalRxContext->Flags = RX_CONTEXT_FLAG_MINIRDR_INITIATED|RX_CONTEXT_FLAG_WAIT|RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
  1641. LocalRxContext->Info.FileInformationClass = FileBasicInformation;
  1642. LocalRxContext->Info.LengthRemaining = sizeof(FILE_BASIC_INFORMATION);
  1643. LocalRxContext->Info.Buffer = &OrdinaryExchange->Create.FileInfo.Basic;
  1644. LocalRxContext->Create = RxContext->Create;
  1645. Status = MRxSmbQueryFileInformation(LocalRxContext);
  1646. RxFreePool(LocalRxContext);
  1647. }
  1648. if (Status == STATUS_SUCCESS) {
  1649. OrdinaryExchange->Create.FileInfo.Standard.Directory =
  1650. BooleanFlagOn(OrdinaryExchange->Create.FileInfo.Basic.FileAttributes,FILE_ATTRIBUTE_DIRECTORY);
  1651. OrdinaryExchange->Create.StorageTypeFromGFA =
  1652. OrdinaryExchange->Create.FileInfo.Standard.Directory ?
  1653. FileTypeDirectory : FileTypeFile;
  1654. }
  1655. return Status;
  1656. }
  1657. typedef enum _INTERESTING_SFI_FOLLOWONS {
  1658. SFI_FOLLOWON_NOTHING,
  1659. SFI_FOLLOWON_DISPOSITION_SENT
  1660. } INTERESTING_SFI_FOLLOWONS;
  1661. NTSTATUS
  1662. MRxSmbSetFileInformation (
  1663. IN PRX_CONTEXT RxContext
  1664. )
  1665. /*++
  1666. Routine Description:
  1667. This routine does a set file info. Only the NT-->NT path is implemented.
  1668. The NT-->NT path works by just remoting the call basically without further ado.
  1669. The file is not really open if it is created for delete. In this case, set dispostion info
  1670. will be delayed until file is closed.
  1671. Arguments:
  1672. RxContext - the RDBSS context
  1673. Return Value:
  1674. RXSTATUS - The return status for the operation
  1675. --*/
  1676. {
  1677. NTSTATUS Status = STATUS_SUCCESS;
  1678. RxCaptureFcb;
  1679. RxCaptureFobx;
  1680. FILE_INFORMATION_CLASS FileInformationClass;
  1681. PVOID pBuffer;
  1682. ULONG BufferLength;
  1683. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  1684. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  1685. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  1686. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1687. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)SrvOpen->pVNetRoot->Context;
  1688. PSMBCE_NET_ROOT pSmbNetRoot = &pVNetRootContext->pNetRootEntry->NetRoot;
  1689. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1690. USHORT SmbFileInfoLevel;
  1691. USHORT Setup;
  1692. INTERESTING_SFI_FOLLOWONS FollowOn = SFI_FOLLOWON_NOTHING;
  1693. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  1694. PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
  1695. REQ_SET_FILE_INFORMATION SetFileInfoRequest;
  1696. RESP_SET_FILE_INFORMATION SetFileInfoResponse;
  1697. PREQ_SET_PATH_INFORMATION pSetFilePathRequest = NULL;
  1698. PVOID pSendParameterBuffer;
  1699. ULONG SendParameterBufferLength;
  1700. BOOLEAN UseCore = FALSE;
  1701. PAGED_CODE();
  1702. TURN_BACK_ASYNCHRONOUS_OPERATIONS();
  1703. FileInformationClass = RxContext->Info.FileInformationClass;
  1704. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1705. pBuffer = RxContext->Info.Buffer;
  1706. BufferLength = RxContext->Info.Length;
  1707. RxDbgTrace(+1, Dbg, ("MRxSmbSetFile: Class %08lx size %08lx\n",FileInformationClass,BufferLength));
  1708. if (FileInformationClass != FileBasicInformation &&
  1709. FileInformationClass != FileDispositionInformation &&
  1710. FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  1711. Status = MRxSmbDeferredCreate(RxContext);
  1712. if (Status != STATUS_SUCCESS) {
  1713. goto FINALLY;
  1714. }
  1715. }
  1716. if( FileInformationClass == FilePipeLocalInformation ||
  1717. FileInformationClass == FilePipeInformation ||
  1718. FileInformationClass == FilePipeRemoteInformation ) {
  1719. Status = STATUS_INVALID_PARAMETER;
  1720. goto FINALLY;
  1721. }
  1722. if (!MRxSmbForceCoreInfo &&
  1723. !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN) &&
  1724. FlagOn( pServerEntry->Server.DialectFlags, DF_NT_INFO_PASSTHROUGH)) {
  1725. SmbFileInfoLevel = FileInformationClass + SMB_INFO_PASSTHROUGH;
  1726. if( FileInformationClass == FileRenameInformation ) {
  1727. PFILE_RENAME_INFORMATION pRenameInformation;
  1728. // The current implementation of pass through for rename information
  1729. // on the server does not go all the way in implementing the
  1730. // NT_TRANSACT, NT_RENAME function defined in SMBs. Therefore we need
  1731. // to special case the code to accomodate the server implementation
  1732. // The two cases that are not permitted are relative renames,
  1733. // specifying a non null root directory and deep renames which
  1734. // transcend the current directory structure. For these cases we will
  1735. // have to revert back to what we had before.
  1736. pRenameInformation = (PFILE_RENAME_INFORMATION)pBuffer;
  1737. if (pRenameInformation->RootDirectory == NULL) {
  1738. // Scan the name given for rename to determine if it is in
  1739. // some other directory.
  1740. ULONG NameLengthInBytes = pRenameInformation->FileNameLength;
  1741. PWCHAR pRenameTarget = pRenameInformation->FileName;
  1742. while ((NameLengthInBytes > 0) &&
  1743. (*pRenameTarget != OBJ_NAME_PATH_SEPARATOR)) {
  1744. NameLengthInBytes -= sizeof(WCHAR);
  1745. }
  1746. if (NameLengthInBytes > 0) {
  1747. UseCore = TRUE;
  1748. }
  1749. } else {
  1750. UseCore = TRUE;
  1751. }
  1752. }
  1753. if (FileInformationClass == FileLinkInformation) {
  1754. UseCore = TRUE;
  1755. }
  1756. } else {
  1757. switch( FileInformationClass ) {
  1758. case FileBasicInformation:
  1759. SmbFileInfoLevel = SMB_SET_FILE_BASIC_INFO;
  1760. break;
  1761. case FileDispositionInformation:
  1762. SmbFileInfoLevel = SMB_SET_FILE_DISPOSITION_INFO;
  1763. break;
  1764. case FileAllocationInformation:
  1765. SmbFileInfoLevel = SMB_SET_FILE_ALLOCATION_INFO;
  1766. break;
  1767. case FileEndOfFileInformation:
  1768. SmbFileInfoLevel = SMB_SET_FILE_END_OF_FILE_INFO;
  1769. break;
  1770. case FileLinkInformation:
  1771. case FileRenameInformation:
  1772. UseCore = TRUE;
  1773. break;
  1774. default:
  1775. Status = STATUS_INVALID_PARAMETER;
  1776. goto FINALLY;
  1777. }
  1778. }
  1779. if (UseCore ||
  1780. MRxSmbForceCoreInfo ||
  1781. !FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS) ||
  1782. FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  1783. if (FileInformationClass == FileLinkInformation ||
  1784. FileInformationClass == FileRenameInformation) {
  1785. Status = MRxSmbBypassDownLevelRename ?
  1786. STATUS_INVALID_PARAMETER :
  1787. MRxSmbRename( RxContext );
  1788. } else {
  1789. Status = MRxSmbCoreInformation(
  1790. RxContext,
  1791. FileInformationClass,
  1792. pBuffer,
  1793. &BufferLength,
  1794. SMBPSE_OE_FROM_SETFILEINFO
  1795. );
  1796. }
  1797. goto FINALLY;
  1798. }
  1799. Setup = TRANS2_SET_FILE_INFORMATION;
  1800. SetFileInfoRequest.Fid = smbSrvOpen->Fid;
  1801. SetFileInfoRequest.InformationLevel = SmbFileInfoLevel;
  1802. SetFileInfoRequest.Flags = 0;
  1803. pSendParameterBuffer = &SetFileInfoRequest;
  1804. SendParameterBufferLength = sizeof(SetFileInfoRequest);
  1805. RxDbgTrace(0, Dbg, (" fid,smbclass=%08lx,%08lx\n",smbSrvOpen->Fid,SmbFileInfoLevel));
  1806. Status = SmbCeTransact(
  1807. RxContext,
  1808. pTransactionOptions,
  1809. &Setup,
  1810. sizeof(Setup),
  1811. NULL,
  1812. 0,
  1813. pSendParameterBuffer,
  1814. SendParameterBufferLength,
  1815. &SetFileInfoResponse,
  1816. sizeof(SetFileInfoResponse),
  1817. pBuffer,
  1818. BufferLength,
  1819. NULL,
  1820. 0,
  1821. &ResumptionContext);
  1822. if (Status == STATUS_SUCCESS &&
  1823. FileInformationClass == FileDispositionInformation ) {
  1824. smbFcb = MRxSmbGetFcbExtension(capFcb);
  1825. SetFlag((((PMRX_SMB_FCB)smbFcb)->MFlags),SMB_FCB_FLAG_SENT_DISPOSITION_INFO);
  1826. SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_FILE_DELETED);
  1827. }
  1828. FINALLY:
  1829. if (NT_SUCCESS(Status)) {
  1830. switch(FileInformationClass) {
  1831. case FileBasicInformation:
  1832. break;
  1833. case FileEndOfFileInformation:
  1834. break;
  1835. case FileStandardInformation:
  1836. break;
  1837. case FileEaInformation:
  1838. smbSrvOpen->FileStatusFlags &= ~SMB_FSF_NO_EAS;
  1839. break;
  1840. case FileAttributeTagInformation:
  1841. smbSrvOpen->FileStatusFlags &= ~SMB_FSF_NO_REPARSETAG;
  1842. break;
  1843. }
  1844. } else {
  1845. RxDbgTrace( 0, Dbg, ("MRxSmbSetFile: Failed .. returning %lx\n",Status));
  1846. }
  1847. RxDbgTraceUnIndent(-1,Dbg);
  1848. return Status;
  1849. }
  1850. NTSTATUS
  1851. MRxSmbSetFileInformationAtCleanup(
  1852. IN PRX_CONTEXT RxContext
  1853. )
  1854. /*++
  1855. Routine Description:
  1856. This routine sets the file information on cleanup. the old rdr just swallows this operation (i.e.
  1857. it doesn't generate it). we are doing the same..........
  1858. Arguments:
  1859. pRxContext - the RDBSS context
  1860. Return Value:
  1861. NTSTATUS - The return status for the operation
  1862. --*/
  1863. {
  1864. return STATUS_SUCCESS;
  1865. }
  1866. NTSTATUS
  1867. MRxSmbIsValidDirectory(
  1868. IN OUT PRX_CONTEXT RxContext,
  1869. IN PUNICODE_STRING DirectoryName
  1870. )
  1871. /*++
  1872. Routine Description:
  1873. This routine checks a remote directory.
  1874. Arguments:
  1875. RxContext - the RDBSS context
  1876. DirectoryName - the directory needs to be checked
  1877. Return Value:
  1878. RXSTATUS - The return status for the operation
  1879. --*/
  1880. {
  1881. NTSTATUS Status;
  1882. BOOLEAN FinalizationComplete;
  1883. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = NULL;
  1884. PSMBSTUFFER_BUFFER_STATE StufferState;
  1885. KEVENT SyncEvent;
  1886. PAGED_CODE();
  1887. RxDbgTrace(+1, Dbg, ("MRxSmbIsValidDirectory\n", 0 ));
  1888. Status = SmbCeReconnect(RxContext->Create.pVNetRoot);
  1889. if (Status != STATUS_SUCCESS) {
  1890. goto FINALLY;
  1891. }
  1892. Status= SmbPseCreateOrdinaryExchange(
  1893. RxContext,
  1894. RxContext->Create.pVNetRoot,
  1895. SMBPSE_OE_FROM_CREATE,
  1896. MRxSmbCoreCheckPath,
  1897. &OrdinaryExchange
  1898. );
  1899. if (Status != STATUS_SUCCESS) {
  1900. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  1901. goto FINALLY;
  1902. }
  1903. OrdinaryExchange->pPathArgument1 = DirectoryName;
  1904. OrdinaryExchange->SmbCeFlags |= SMBCE_EXCHANGE_ATTEMPT_RECONNECTS;
  1905. OrdinaryExchange->AssociatedStufferState.CurrentCommand = SMB_COM_NO_ANDX_COMMAND;
  1906. OrdinaryExchange->pSmbCeSynchronizationEvent = &SyncEvent;
  1907. StufferState = &OrdinaryExchange->AssociatedStufferState;
  1908. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
  1909. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  1910. ASSERT(Status != STATUS_PENDING);
  1911. if (Status != STATUS_SUCCESS) {
  1912. Status = STATUS_BAD_NETWORK_PATH;
  1913. }
  1914. FinalizationComplete = SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  1915. ASSERT(FinalizationComplete);
  1916. FINALLY:
  1917. RxDbgTrace(-1, Dbg, ("MRxSmbIsValidDirectory exit with status=%08lx\n", Status ));
  1918. return(Status);
  1919. }
  1920.