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.

1969 lines
74 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. querydir.c
  5. Abstract:
  6. This module implements the DAV mini redirector call down routines pertaining
  7. to query directory.
  8. Author:
  9. Joe Linn
  10. Rohan Kumar [RohanK] 20-Sept-1999
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "webdav.h"
  16. //
  17. // Mentioned below are the prototypes of functions tht are used only within
  18. // this module (file). These functions should not be exposed outside.
  19. //
  20. NTSTATUS
  21. MRxDAVQueryDirectoryContinuation(
  22. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  23. );
  24. NTSTATUS
  25. MRxDAVFormatUserModeQueryDirectoryRequest(
  26. IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  27. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  28. IN ULONG WorkItemLength,
  29. OUT PULONG_PTR ReturnedLength
  30. );
  31. BOOL
  32. MRxDAVPrecompleteUserModeQueryDirectoryRequest(
  33. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  34. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  35. ULONG WorkItemLength,
  36. BOOL OperationCancelled
  37. );
  38. NTSTATUS
  39. MRxDAVQueryDirectoryFromCache(
  40. IN PRX_CONTEXT RxContext,
  41. IN PBYTE Buffer,
  42. IN PFILE_BASIC_INFORMATION Basic,
  43. IN PFILE_STANDARD_INFORMATION Standard,
  44. IN ULONG FileIndex
  45. );
  46. #ifdef ALLOC_PRAGMA
  47. #pragma alloc_text(PAGE, MRxDAVQueryDirectory)
  48. #pragma alloc_text(PAGE, MRxDAVQueryDirectoryFromCache)
  49. #pragma alloc_text(PAGE, MRxDAVQueryDirectoryContinuation)
  50. #pragma alloc_text(PAGE, MRxDAVFormatUserModeQueryDirectoryRequest)
  51. #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeQueryDirectoryRequest)
  52. #endif
  53. //
  54. // Implementation of functions begins here.
  55. //
  56. NTSTATUS
  57. MRxDAVQueryDirectory(
  58. IN PRX_CONTEXT RxContext
  59. )
  60. /*++
  61. Routine Description:
  62. This routine handles querydir requests for the DAV mini--redir.
  63. Arguments:
  64. RxContext - The RDBSS context.
  65. Return Value:
  66. RXSTATUS - The return status for the operation
  67. --*/
  68. {
  69. NTSTATUS NtStatus = STATUS_SUCCESS;
  70. RxCaptureFcb;
  71. RxCaptureFobx;
  72. UNICODE_STRING CacheName;
  73. PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  74. PAGED_CODE();
  75. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  76. ("%ld: Entering MRxDAVQueryDirectory.\n", PsGetCurrentThreadId()));
  77. DavDbgTrace(DAV_TRACE_CONTEXT,
  78. ("%ld: MRxDAVQueryDirectory: RxContext: %08lx\n",
  79. PsGetCurrentThreadId(), RxContext));
  80. CacheName.Buffer = RxAllocatePoolWithTag(PagedPool,
  81. MAX_PATH * sizeof(WCHAR),
  82. DAV_QUERYDIR_POOLTAG);
  83. if (CacheName.Buffer == NULL) {
  84. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  85. goto EXIT_THE_FUNCTION;
  86. }
  87. RtlZeroMemory(CacheName.Buffer, MAX_PATH * sizeof(WCHAR));
  88. RtlCopyMemory(CacheName.Buffer,DirectoryName->Buffer,DirectoryName->Length);
  89. CacheName.Buffer[DirectoryName->Length/2] = L'\\';
  90. RtlCopyMemory(&CacheName.Buffer[DirectoryName->Length/2 + 1],
  91. capFobx->UnicodeQueryTemplate.Buffer,
  92. capFobx->UnicodeQueryTemplate.Length);
  93. CacheName.Length = ( DirectoryName->Length + capFobx->UnicodeQueryTemplate.Length + sizeof(WCHAR) );
  94. CacheName.MaximumLength = ( DirectoryName->Length + capFobx->UnicodeQueryTemplate.Length + sizeof(WCHAR) );
  95. if (!FsRtlDoesNameContainWildCards(&capFobx->UnicodeQueryTemplate)) {
  96. DAV_USERMODE_CREATE_RETURNED_FILEINFO FileInfo;
  97. PWEBDAV_FOBX DavFobx = MRxDAVGetFobxExtension(capFobx);
  98. if (DavFobx->CurrentFileIndex > 0) {
  99. DavFobx->NumOfFileEntries = 0;
  100. DavFobx->CurrentFileIndex = 0;
  101. NtStatus = STATUS_NO_MORE_FILES;
  102. goto EXIT_THE_FUNCTION;
  103. }
  104. if (MRxDAVIsFileNotFoundCachedWithName(&CacheName,capFcb->pNetRoot)) {
  105. DavDbgTrace(DAV_TRACE_DETAIL,
  106. ("MRxDAVCreateContinuation file not found %wZ\n",&CacheName));
  107. NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  108. goto EXIT_THE_FUNCTION;
  109. }
  110. if (MRxDAVIsFileInfoCacheFound(RxContext, &FileInfo, &NtStatus, &CacheName)) {
  111. PBYTE Buffer = RxContext->Info.Buffer;
  112. ULONG BufferLength = RxContext->Info.LengthRemaining;
  113. //
  114. // Zero the buffer supplied.
  115. //
  116. RtlZeroMemory(Buffer, BufferLength);
  117. NtStatus = MRxDAVQueryDirectoryFromCache(RxContext,
  118. Buffer,
  119. &FileInfo.BasicInformation,
  120. &FileInfo.StandardInformation,
  121. 1);
  122. DavFobx->NumOfFileEntries = 1;
  123. DavFobx->CurrentFileIndex = 1;
  124. goto EXIT_THE_FUNCTION;
  125. }
  126. }
  127. NtStatus = UMRxAsyncEngOuterWrapper(RxContext,
  128. SIZEOF_DAV_SPECIFIC_CONTEXT,
  129. MRxDAVFormatTheDAVContext,
  130. DAV_MINIRDR_ENTRY_FROM_QUERYDIR,
  131. MRxDAVQueryDirectoryContinuation,
  132. "MRxDAVQueryDirectory");
  133. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  134. ("%ld: Leaving MRxDAVQueryDirectory with NtStatus = %08lx\n",
  135. PsGetCurrentThreadId(), NtStatus));
  136. if (NtStatus == STATUS_NO_SUCH_FILE ||
  137. NtStatus == STATUS_OBJECT_PATH_NOT_FOUND ||
  138. NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  139. MRxDAVCacheFileNotFoundWithName(&CacheName,RxContext->pFcb->pNetRoot);
  140. MRxDAVInvalidateFileInfoCacheWithName(&CacheName,RxContext->pFcb->pNetRoot);
  141. }
  142. EXIT_THE_FUNCTION:
  143. if (CacheName.Buffer != NULL) {
  144. RxFreePool(CacheName.Buffer);
  145. }
  146. return(NtStatus);
  147. }
  148. NTSTATUS
  149. MRxDAVQueryDirectoryContinuation(
  150. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  151. )
  152. /*++
  153. Routine Description:
  154. This is the continuation routine for query directory operation.
  155. Arguments:
  156. AsyncEngineContext - The Reflectors context.
  157. RxContext - The RDBSS context.
  158. Return Value:
  159. RXSTATUS - The return status for the operation.
  160. --*/
  161. {
  162. NTSTATUS NtStatus;
  163. BOOL SynchronousIo;
  164. PAGED_CODE();
  165. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  166. ("%ld: Entering MRxDAVQueryDirectoryContinuation!!!!\n",
  167. PsGetCurrentThreadId()));
  168. DavDbgTrace(DAV_TRACE_CONTEXT,
  169. ("%ld: MRxDAVQueryDirectoryContinuation: "
  170. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  171. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  172. SynchronousIo = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
  173. if (!SynchronousIo) {
  174. //
  175. // Set the asynchronous flag. This is done since we do not want this
  176. // thread to block in the UMRxSubmitAsyncEngUserModeRequest function.
  177. // Also, since we need to call RxLowIoCompletion once we are done, set
  178. // ShouldCallLowIoCompletion in the context to TRUE.
  179. //
  180. SetFlag(AsyncEngineContext->Flags, UMRX_ASYNCENG_CTX_FLAG_ASYNC_OPERATION);
  181. AsyncEngineContext->ShouldCallLowIoCompletion = TRUE;
  182. //
  183. // Set the CancelRoutine on the RxContext. Since this is an Async
  184. // operation, it can be cancelled.
  185. //
  186. NtStatus = RxSetMinirdrCancelRoutine(RxContext, MRxDAVCancelRoutine);
  187. if (NtStatus != STATUS_SUCCESS) {
  188. ASSERT(NtStatus == STATUS_CANCELLED);
  189. DavDbgTrace(DAV_TRACE_ERROR,
  190. ("%ld: MRxDAVQueryDirectoryContinuation: "
  191. "AsyncEngineContext: %08lx. STATUS_CANCELLED\n",
  192. PsGetCurrentThreadId(), AsyncEngineContext));
  193. goto EXIT_THE_FUNCTION;
  194. }
  195. //
  196. // Since this is an Asyncchronous operation, mark the IRP as pending.
  197. // Its OK if you mark an IRP pending and complete it on the same thread
  198. // without returning STATUS_PENDING.
  199. //
  200. IoMarkIrpPending(RxContext->CurrentIrp);
  201. }
  202. //
  203. // Try usermode.
  204. //
  205. NtStatus = UMRxSubmitAsyncEngUserModeRequest(
  206. UMRX_ASYNCENGINE_ARGUMENTS,
  207. MRxDAVFormatUserModeQueryDirectoryRequest,
  208. MRxDAVPrecompleteUserModeQueryDirectoryRequest
  209. );
  210. EXIT_THE_FUNCTION:
  211. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  212. ("%ld: Leaving MRxDAVQueryDirectoryContinuation with NtStatus "
  213. "= %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  214. return NtStatus;
  215. }
  216. NTSTATUS
  217. MRxDAVFormatUserModeQueryDirectoryRequest(
  218. IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  219. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  220. IN ULONG WorkItemLength,
  221. OUT PULONG_PTR ReturnedLength
  222. )
  223. /*++
  224. Routine Description:
  225. This routine formats the QueryDirectory request being sent to the user mode
  226. for processing.
  227. Arguments:
  228. RxContext - The RDBSS context.
  229. AsyncEngineContext - The reflctor's context.
  230. WorkItem - The work item buffer.
  231. WorkItemLength - The length of the work item buffer.
  232. ReturnedLength -
  233. Return Value:
  234. STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES.
  235. --*/
  236. {
  237. NTSTATUS NtStatus = STATUS_SUCCESS;
  238. PMRX_SRV_CALL SrvCall = NULL;
  239. PWEBDAV_SRV_CALL DavSrvCall = NULL;
  240. PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  241. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  242. PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
  243. PMRX_NET_ROOT NetRoot = NULL;
  244. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  245. PWCHAR ServerName = NULL, NetRootName = NULL, JustTheNetRootName = NULL;
  246. PBYTE PathName = NULL;
  247. ULONG ServerNameLengthInBytes, PathNameLengthInBytes, NetRootNameLengthInBytes;
  248. PDAV_USERMODE_QUERYDIR_REQUEST QueryDirRequest = NULL;
  249. PSECURITY_CLIENT_CONTEXT SecurityClientContext = NULL;
  250. PWEBDAV_FOBX DavFobx = NULL;
  251. BOOLEAN ReturnVal;
  252. PUNICODE_STRING Template;
  253. RxCaptureFobx;
  254. PAGED_CODE();
  255. DavDbgTrace(DAV_TRACE_DETAIL,
  256. ("%ld: Entering MRxDAVFormatUserModeQueryDirectoryRequest.\n",
  257. PsGetCurrentThreadId()));
  258. DavDbgTrace(DAV_TRACE_CONTEXT,
  259. ("%ld: MRxDAVFormatUserModeQueryDirectoryRequest: "
  260. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  261. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  262. IF_DEBUG {
  263. ASSERT (capFobx != NULL);
  264. ASSERT (capFobx->pSrvOpen == RxContext->pRelevantSrvOpen);
  265. }
  266. DavWorkItem->WorkItemType = UserModeQueryDirectory;
  267. QueryDirRequest = &(DavWorkItem->QueryDirRequest);
  268. DavFobx = MRxDAVGetFobxExtension(capFobx);
  269. ASSERT(DavFobx != NULL);
  270. NetRoot = SrvOpen->pFcb->pNetRoot;
  271. DavVNetRoot = (PWEBDAV_V_NET_ROOT)SrvOpen->pVNetRoot->Context;
  272. ASSERT(DavVNetRoot != NULL);
  273. DavDbgTrace(DAV_TRACE_DETAIL,
  274. ("%ld: MRxDAVFormatUserModeQueryDirectoryRequest: SrvCallName = %wZ, "
  275. "SrvCallNameLength = %d\n", PsGetCurrentThreadId(),
  276. NetRoot->pSrvCall->pSrvCallName, NetRoot->pSrvCall->pSrvCallName->Length));
  277. DavDbgTrace(DAV_TRACE_DETAIL,
  278. ("%ld: MRxDAVFormatUserModeQueryDirectoryRequest: NetRootName = %wZ, "
  279. "NetRootNameLength = %d\n", PsGetCurrentThreadId(),
  280. NetRoot->pNetRootName, NetRoot->pNetRootName->Length));
  281. DavDbgTrace(DAV_TRACE_DETAIL,
  282. ("%ld: MRxDAVFormatUserModeQueryDirectoryRequest: PathName = %wZ, "
  283. "PathNameLength = %d\n", PsGetCurrentThreadId(),
  284. SrvOpen->pAlreadyPrefixedName, SrvOpen->pAlreadyPrefixedName->Length));
  285. //
  286. // Have we already created the DavFileAttributes list. If we have, then we
  287. // tell the user mode process to do nothing and return. Here we do need to
  288. // impersonate becuase the usermode will fail otherwise. This is becuase
  289. // of the way the usermode code is structured.
  290. //
  291. if (DavFobx->DavFileAttributes) {
  292. QueryDirRequest->AlreadyDone = TRUE;
  293. goto IMPERSONATE_AND_EXIT;
  294. }
  295. QueryDirRequest->AlreadyDone = FALSE;
  296. SrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;
  297. DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall);
  298. //
  299. // Copy the ServerName.
  300. //
  301. ServerNameLengthInBytes = ( SrvCall->pSrvCallName->Length + sizeof(WCHAR) );
  302. ServerName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  303. ServerNameLengthInBytes);
  304. if (ServerName == NULL) {
  305. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  306. DavDbgTrace(DAV_TRACE_ERROR,
  307. ("%ld: ERROR: MRxDAVFormatUserModeQueryDirectoryRequest/"
  308. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  309. PsGetCurrentThreadId(), NtStatus));
  310. goto EXIT_THE_FUNCTION;
  311. }
  312. RtlCopyBytes(ServerName,
  313. SrvCall->pSrvCallName->Buffer,
  314. SrvCall->pSrvCallName->Length);
  315. ServerName[( ( (ServerNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0';
  316. QueryDirRequest->ServerName = ServerName;
  317. DavDbgTrace(DAV_TRACE_DETAIL,
  318. ("%ld: MRxDAVFormatUserModeQueryDirectoryRequest: ServerName: "
  319. "%ws\n", PsGetCurrentThreadId(), ServerName));
  320. //
  321. // Copy the ServerID.
  322. //
  323. QueryDirRequest->ServerID = DavSrvCall->ServerID;
  324. Template = &(capFobx->UnicodeQueryTemplate);
  325. //
  326. // The NetRootName (pNetRootName) includes the ServerName. Hence to get the
  327. // NetRootNameLengthInBytes, we do the following.
  328. //
  329. NetRootNameLengthInBytes = (NetRoot->pNetRootName->Length - NetRoot->pSrvCall->pSrvCallName->Length);
  330. NetRootName = &(NetRoot->pNetRootName->Buffer[1]);
  331. JustTheNetRootName = wcschr(NetRootName, L'\\');
  332. //
  333. // Copy the PathName of the Directory. If the template does not contain any
  334. // wild cards, then we just need to get the attributes of this file from
  335. // the server. We only get the attributes of all the files, if a wild card
  336. // is specified in the template.
  337. //
  338. ReturnVal = FsRtlDoesNameContainWildCards(Template);
  339. if (ReturnVal) {
  340. //
  341. // The sizeof(WCHAR) is for the final '\0' char.
  342. //
  343. PathNameLengthInBytes = ( NetRootNameLengthInBytes + sizeof(WCHAR) );
  344. //
  345. // We need to allocate memory for the backslash and the Remaining name
  346. // only if the remaining name exists.
  347. //
  348. if (SrvOpen->pAlreadyPrefixedName->Length) {
  349. //
  350. // The sizeof(WCHAR) is for the backslash after the NetRootName.
  351. //
  352. PathNameLengthInBytes += ( SrvOpen->pAlreadyPrefixedName->Length + sizeof(WCHAR) );
  353. }
  354. PathName = (PBYTE) UMRxAllocateSecondaryBuffer(AsyncEngineContext, PathNameLengthInBytes);
  355. if (PathName == NULL) {
  356. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  357. DavDbgTrace(DAV_TRACE_ERROR,
  358. ("%ld: ERROR: MRxDAVFormatUserModeQueryDirectoryRequest/"
  359. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  360. PsGetCurrentThreadId(), NtStatus));
  361. goto EXIT_THE_FUNCTION;
  362. }
  363. QueryDirRequest->PathName = (PWCHAR)PathName;
  364. RtlZeroMemory(QueryDirRequest->PathName, PathNameLengthInBytes);
  365. //
  366. // Copy the NetRootName.
  367. //
  368. RtlCopyMemory(PathName, JustTheNetRootName, NetRootNameLengthInBytes);
  369. //
  370. // We need to copy the backclash and the remaining path name only if
  371. // the remaining path name exists.
  372. //
  373. if (SrvOpen->pAlreadyPrefixedName->Length) {
  374. if (SrvOpen->pAlreadyPrefixedName->Buffer[0] != L'\\') {
  375. //
  376. // Copy the backslash.
  377. //
  378. RtlCopyMemory( (PathName + NetRootNameLengthInBytes), L"\\", sizeof(WCHAR) );
  379. //
  380. // Copy the remaining path name after the NetRootName.
  381. //
  382. RtlCopyMemory( ( PathName + NetRootNameLengthInBytes + sizeof(WCHAR) ),
  383. SrvOpen->pAlreadyPrefixedName->Buffer,
  384. SrvOpen->pAlreadyPrefixedName->Length);
  385. } else {
  386. //
  387. // Copy the remaining path name after the NetRootName which has the leading
  388. // backslash already.
  389. //
  390. RtlCopyMemory( ( PathName + NetRootNameLengthInBytes ),
  391. SrvOpen->pAlreadyPrefixedName->Buffer,
  392. SrvOpen->pAlreadyPrefixedName->Length);
  393. }
  394. }
  395. QueryDirRequest->NoWildCards = FALSE;
  396. } else {
  397. //
  398. // The Template is just a filename without any wild card chars. We copy
  399. // the filaname after the pathname and send it to the user mode. First,
  400. // we need to figure out if the path name has a trailing '\'.
  401. //
  402. BOOL trailingSlash = FALSE;
  403. PWCHAR PName = SrvOpen->pAlreadyPrefixedName->Buffer;
  404. ULONG PLen = SrvOpen->pAlreadyPrefixedName->Length;
  405. if (PLen) {
  406. if ( PName[ ( ( PLen / sizeof(WCHAR) ) - 1 ) ] == L'\\' ) {
  407. trailingSlash = TRUE;
  408. }
  409. } else {
  410. PName = NULL;
  411. }
  412. if (trailingSlash) {
  413. //
  414. // The first sizeof(WCHAR) is for the backslash after the NetRootName.
  415. // The second sizeof(WCHAR) for the final \0.
  416. //
  417. PathNameLengthInBytes = ( NetRootNameLengthInBytes +
  418. sizeof(WCHAR) +
  419. SrvOpen->pAlreadyPrefixedName->Length +
  420. Template->Length +
  421. sizeof(WCHAR) );
  422. } else {
  423. //
  424. // The first sizeof(WCHAR) is for the backslash after the NetRootName.
  425. // The second sizeof(WCHAR) is for the final '\0' char.
  426. //
  427. PathNameLengthInBytes = ( NetRootNameLengthInBytes +
  428. sizeof(WCHAR) +
  429. Template->Length +
  430. sizeof(WCHAR) );
  431. //
  432. // The sizeof(WCHAR) if for the '\\' between the pathname and the
  433. // template name. We need to add this only if the remaining path
  434. // name exists.
  435. //
  436. if (PName) {
  437. PathNameLengthInBytes += ( SrvOpen->pAlreadyPrefixedName->Length +
  438. sizeof(WCHAR) );
  439. }
  440. }
  441. PathName = (PBYTE)UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  442. PathNameLengthInBytes);
  443. if (PathName == NULL) {
  444. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  445. DavDbgTrace(DAV_TRACE_ERROR,
  446. ("%ld: ERROR: MRxDAVFormatUserModeQueryDirectoryRequest/"
  447. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  448. PsGetCurrentThreadId(), NtStatus));
  449. goto EXIT_THE_FUNCTION;
  450. }
  451. QueryDirRequest->PathName = (PWCHAR)PathName;
  452. RtlZeroMemory(QueryDirRequest->PathName, PathNameLengthInBytes);
  453. //
  454. // Copy the NetRootName.
  455. //
  456. RtlCopyMemory(PathName, JustTheNetRootName, NetRootNameLengthInBytes);
  457. //
  458. // Copy the backclash.
  459. //
  460. RtlCopyMemory( (PathName + NetRootNameLengthInBytes), L"\\", sizeof(WCHAR) );
  461. //
  462. // If PName is not NULL, we need to copy the remaining name and then
  463. // the template name.
  464. //
  465. if (PName) {
  466. RtlCopyMemory( ( PathName + NetRootNameLengthInBytes + sizeof(WCHAR) ),
  467. SrvOpen->pAlreadyPrefixedName->Buffer,
  468. SrvOpen->pAlreadyPrefixedName->Length);
  469. if (trailingSlash) {
  470. RtlCopyMemory( (PathName + NetRootNameLengthInBytes +
  471. sizeof(WCHAR) + SrvOpen->pAlreadyPrefixedName->Length),
  472. Template->Buffer,
  473. Template->Length );
  474. } else {
  475. RtlCopyMemory( (PathName + NetRootNameLengthInBytes + sizeof(WCHAR)
  476. + SrvOpen->pAlreadyPrefixedName->Length),
  477. L"\\",
  478. sizeof(WCHAR) );
  479. RtlCopyMemory( ( PathName + NetRootNameLengthInBytes + sizeof(WCHAR)
  480. + SrvOpen->pAlreadyPrefixedName->Length + sizeof(WCHAR) ),
  481. Template->Buffer,
  482. Template->Length );
  483. }
  484. } else {
  485. //
  486. // A backslash has already been copied after the NetRootName.
  487. //
  488. RtlCopyMemory( ( PathName + NetRootNameLengthInBytes + sizeof(WCHAR) ),
  489. Template->Buffer,
  490. Template->Length );
  491. }
  492. QueryDirRequest->NoWildCards = TRUE;
  493. }
  494. DavDbgTrace(DAV_TRACE_DETAIL,
  495. ("%ld: MRxDAVFormatUserModeQueryDirectoryRequest. PathName ="
  496. " %ws\n", PsGetCurrentThreadId(), PathName));
  497. //
  498. // Set the LogonID stored in the Dav V_NET_ROOT. This value is used in the
  499. // user mode.
  500. //
  501. QueryDirRequest->LogonID.LowPart = DavVNetRoot->LogonID.LowPart;
  502. QueryDirRequest->LogonID.HighPart = DavVNetRoot->LogonID.HighPart;
  503. DavDbgTrace(DAV_TRACE_DETAIL,
  504. ("%ld: MRxDAVFormatUserModeQueryDirectoryRequest. DavVNetRoot"
  505. " = %08lx\n", PsGetCurrentThreadId(), DavVNetRoot));
  506. DavDbgTrace(DAV_TRACE_DETAIL,
  507. ("%ld: MRxDAVFormatUserModeQueryDirectoryRequest. LogonID.LowPart"
  508. " = %08lx\n", PsGetCurrentThreadId(), DavVNetRoot->LogonID.LowPart));
  509. DavDbgTrace(DAV_TRACE_DETAIL,
  510. ("%ld: MRxDAVFormatUserModeQueryDirectoryRequest. LogonID.HighPart"
  511. " = %08lx\n", PsGetCurrentThreadId(), DavVNetRoot->LogonID.HighPart));
  512. IMPERSONATE_AND_EXIT:
  513. SecurityClientContext = &(DavVNetRoot->SecurityClientContext);
  514. //
  515. // Impersonate the client who initiated the request. If we fail to
  516. // impersonate, tough luck.
  517. //
  518. if (SecurityClientContext != NULL) {
  519. NtStatus = UMRxImpersonateClient(SecurityClientContext, WorkItemHeader);
  520. if (!NT_SUCCESS(NtStatus)) {
  521. DavDbgTrace(DAV_TRACE_ERROR,
  522. ("%ld: ERROR: MRxDAVFormatUserModeQueryDirectoryRequest/"
  523. "UMRxImpersonateClient. NtStatus = %08lx.\n",
  524. PsGetCurrentThreadId(), NtStatus));
  525. }
  526. } else {
  527. NtStatus = STATUS_INVALID_PARAMETER;
  528. DavDbgTrace(DAV_TRACE_ERROR,
  529. ("%ld: ERROR: MRxDAVFormatUserModeQueryDirectoryRequest: "
  530. "SecurityClientContext is NULL.\n",
  531. PsGetCurrentThreadId()));
  532. }
  533. EXIT_THE_FUNCTION:
  534. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  535. ("%ld: Leaving MRxDAVFormatUserModeQueryDirectoryRequest with "
  536. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  537. return(NtStatus);
  538. }
  539. BOOL
  540. MRxDAVPrecompleteUserModeQueryDirectoryRequest(
  541. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  542. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  543. ULONG WorkItemLength,
  544. BOOL OperationCancelled
  545. )
  546. /*++
  547. Routine Description:
  548. The precompletion routine for the create SrvCall request.
  549. Arguments:
  550. RxContext - The RDBSS context.
  551. AsyncEngineContext - The reflctor's context.
  552. WorkItem - The work item buffer.
  553. WorkItemLength - The length of the work item buffer.
  554. OperationCancelled - TRUE if this operation was cancelled by the user.
  555. Return Value:
  556. TRUE - UMRxAsyncEngineCalldownIrpCompletion is called by the function
  557. UMRxCompleteUserModeRequest after we return.
  558. --*/
  559. {
  560. NTSTATUS NtStatus = STATUS_SUCCESS;
  561. PDAV_USERMODE_QUERYDIR_REQUEST QueryDirRequest = NULL;
  562. PDAV_USERMODE_QUERYDIR_RESPONSE QueryDirResponse = NULL;
  563. PDAV_USERMODE_WORKITEM DavWorkItem = NULL;
  564. PFILE_NAMES_INFORMATION FileNamesInfo = NULL;
  565. PFILE_DIRECTORY_INFORMATION FileDirInfo = NULL;
  566. PFILE_FULL_DIR_INFORMATION FileFullDirInfo = NULL;
  567. PFILE_BOTH_DIR_INFORMATION FileBothDirInfo = NULL;
  568. FILE_INFORMATION_CLASS FileInformationClass;
  569. PBYTE Buffer = NULL;
  570. BOOL SingleEntry, InitialQuery, IndexSpecified, EndOfBuffer = FALSE;
  571. BOOLEAN ReturnVal, RestartScan, NoWildCards = FALSE, AsyncOperation = FALSE;
  572. ULONG FileIndex, BufferLength, BufferLengthUsed = 0, NextEntryOffset = 0;
  573. PUNICODE_STRING Template = NULL;
  574. UNICODE_STRING UnicodeFileName;
  575. PDAV_FILE_ATTRIBUTES DavFileAttributes = NULL, TempDFA = NULL;
  576. PLIST_ENTRY listEntry = NULL;
  577. PWEBDAV_FOBX DavFobx = NULL;
  578. PVOID PreviousBlock = NULL;
  579. FILE_BASIC_INFORMATION BasicInfo;
  580. FILE_STANDARD_INFORMATION StandardInfo;
  581. UNICODE_STRING CacheName;
  582. PUNICODE_STRING DirectoryName = NULL;
  583. RxCaptureFobx;
  584. PAGED_CODE();
  585. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  586. ("%ld: Entering MRxDAVPrecompleteUserModeQueryDirectoryRequest.\n",
  587. PsGetCurrentThreadId()));
  588. DavDbgTrace(DAV_TRACE_CONTEXT,
  589. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  590. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  591. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  592. DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  593. QueryDirRequest = &(DavWorkItem->QueryDirRequest);
  594. QueryDirResponse = &(DavWorkItem->QueryDirResponse);
  595. CacheName.Buffer = NULL;
  596. CacheName.Length = 0;
  597. CacheName.MaximumLength = 0;
  598. //
  599. // If the operation is cancelled, then there is no guarantee that the FCB,
  600. // FOBX etc are still valid. All that we need to do is cleanup and bail.
  601. //
  602. if (!OperationCancelled) {
  603. //
  604. // We store the DavFileAttributes in the DAV FOBX extension. These will
  605. // be used on subsequent calls to the Enumerate directory call.
  606. //
  607. DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  608. DavFobx = MRxDAVGetFobxExtension(capFobx);
  609. ASSERT(DavFobx != NULL);
  610. }
  611. if ( QueryDirRequest->AlreadyDone == FALSE ) {
  612. //
  613. // If the operation is cancelled, then there is no guarantee that the FCB,
  614. // FOBX etc are still valid. All that we need to do is cleanup and bail.
  615. //
  616. if (!OperationCancelled) {
  617. //
  618. // Get the response items only if we succeeded in the user mode and if
  619. // we got the properties of all the files in the directory.
  620. //
  621. if ( AsyncEngineContext->Status == STATUS_SUCCESS &&
  622. QueryDirResponse->DavFileAttributes != NULL ) {
  623. DavFobx->DavFileAttributes = QueryDirResponse->DavFileAttributes;
  624. DavFobx->NumOfFileEntries = QueryDirResponse->NumOfFileEntries;
  625. DavFobx->CurrentFileIndex = 0;
  626. DavFobx->listEntry = &(DavFobx->DavFileAttributes->NextEntry);
  627. DavDbgTrace(( DAV_TRACE_DETAIL | DAV_TRACE_QUERYDIR ),
  628. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  629. "DavFileAttributes = %08lx, NumOfFileEntries = %d.\n",
  630. PsGetCurrentThreadId(), DavFobx->DavFileAttributes,
  631. DavFobx->NumOfFileEntries));
  632. }
  633. } else {
  634. //
  635. // If the operation was cancelled and we allocated the
  636. // DavFileAttributeList in the usermode, we need to set
  637. // callWorkItemCleanup to TRUE, so that it gets cleaned up.
  638. //
  639. if ( AsyncEngineContext->Status == STATUS_SUCCESS &&
  640. QueryDirResponse->DavFileAttributes != NULL ) {
  641. DavDbgTrace(DAV_TRACE_DETAIL,
  642. ("%ld: ERROR: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  643. "callWorkItemCleanup\n", PsGetCurrentThreadId()));
  644. DavWorkItem->callWorkItemCleanup = TRUE;
  645. }
  646. }
  647. //
  648. // We need to free up the heaps, we allocated in the format routine.
  649. //
  650. if (QueryDirRequest->ServerName != NULL) {
  651. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  652. (PBYTE)QueryDirRequest->ServerName);
  653. if (NtStatus != STATUS_SUCCESS) {
  654. DavDbgTrace(DAV_TRACE_ERROR,
  655. ("%ld: ERROR: MRxDAVPrecompleteUserModeQueryDirectoryRequest/"
  656. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  657. PsGetCurrentThreadId(), NtStatus));
  658. goto EXIT_THE_FUNCTION;
  659. }
  660. }
  661. if (QueryDirRequest->PathName != NULL) {
  662. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  663. (PBYTE)QueryDirRequest->PathName);
  664. if (NtStatus != STATUS_SUCCESS) {
  665. DavDbgTrace(DAV_TRACE_ERROR,
  666. ("%ld: ERROR: MRxDAVPrecompleteUserModeQueryDirectoryRequest/"
  667. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  668. PsGetCurrentThreadId(), NtStatus));
  669. goto EXIT_THE_FUNCTION;
  670. }
  671. }
  672. }
  673. //
  674. // Before proceeding further, we need to check the following. Its very
  675. // important that these checks (Async and Cancel) are done before anything
  676. // else is done.
  677. //
  678. AsyncOperation = FlagOn(AsyncEngineContext->Flags, UMRX_ASYNCENG_CTX_FLAG_ASYNC_OPERATION);
  679. if (AsyncOperation) {
  680. //
  681. // If this was an Async operation then we need to remove a reference on
  682. // the AsyncEngineContext which was taken before it was placed on the
  683. // KQueue to go to the usermode. Also, the context should have one more
  684. // reference.
  685. //
  686. ReturnVal = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  687. ASSERT(!ReturnVal);
  688. }
  689. //
  690. // If this operation was cancelled, then all that we need to do is finalize
  691. // the AsyncEngineContext, if the call was Async and return FALSE. If the
  692. // call was sync then we don't need to finalize.
  693. //
  694. if (OperationCancelled) {
  695. DavDbgTrace(DAV_TRACE_ERROR,
  696. ("%ld: ERROR: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  697. "Operation Cancelled.\n", PsGetCurrentThreadId()));
  698. if (AsyncOperation) {
  699. ReturnVal = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  700. ASSERT(!ReturnVal);
  701. }
  702. return FALSE;
  703. }
  704. CacheName.Buffer = RxAllocatePoolWithTag(PagedPool,
  705. MAX_PATH * sizeof(WCHAR),
  706. DAV_QUERYDIR_POOLTAG);
  707. if (CacheName.Buffer == NULL) {
  708. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  709. goto EXIT_THE_FUNCTION;
  710. }
  711. RtlZeroMemory(CacheName.Buffer,MAX_PATH * sizeof(WCHAR));
  712. RtlCopyMemory(CacheName.Buffer,DirectoryName->Buffer,DirectoryName->Length);
  713. CacheName.Buffer[DirectoryName->Length/2] = L'\\';
  714. RtlCopyMemory(&CacheName.Buffer[DirectoryName->Length/2 + 1],
  715. capFobx->UnicodeQueryTemplate.Buffer,
  716. capFobx->UnicodeQueryTemplate.Length);
  717. CacheName.Length =
  718. CacheName.MaximumLength = DirectoryName->Length + capFobx->UnicodeQueryTemplate.Length + sizeof(WCHAR);
  719. NtStatus = AsyncEngineContext->Status;
  720. if (NtStatus != STATUS_SUCCESS) {
  721. //
  722. // We failed in the user mode.
  723. //
  724. DavDbgTrace(DAV_TRACE_ERROR,
  725. ("%ld: ERROR: MRxDAVPrecompleteUserModeQueryDirectoryRequest:"
  726. "QueryDirectory failed with NtStatus = %08lx.\n",
  727. PsGetCurrentThreadId(), NtStatus));
  728. goto EXIT_THE_FUNCTION;
  729. }
  730. ASSERT(DavFobx->DavFileAttributes != NULL);
  731. SingleEntry = RxContext->QueryDirectory.ReturnSingleEntry;
  732. InitialQuery = RxContext->QueryDirectory.InitialQuery;
  733. RestartScan = RxContext->QueryDirectory.RestartScan;
  734. IndexSpecified = RxContext->QueryDirectory.IndexSpecified;
  735. FileIndex = RxContext->QueryDirectory.FileIndex;
  736. Buffer = RxContext->Info.Buffer;
  737. BufferLength = RxContext->Info.LengthRemaining;
  738. Template = &(capFobx->UnicodeQueryTemplate);
  739. FileInformationClass = RxContext->Info.FileInformationClass;
  740. DavDbgTrace(DAV_TRACE_DETAIL,
  741. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  742. "FileInformationClass = %d.\n",
  743. PsGetCurrentThreadId(), FileInformationClass));
  744. //
  745. // Zero the buffer supplied.
  746. //
  747. RtlZeroMemory(Buffer, BufferLength);
  748. //
  749. // See, if we need to restart from the beginning.
  750. //
  751. if (RestartScan) {
  752. DavFobx->CurrentFileIndex = 0;
  753. DavFobx->listEntry = &(DavFobx->DavFileAttributes->NextEntry);
  754. }
  755. //
  756. // Response has a pointer to the list of DavFileAttributes.
  757. //
  758. DavFileAttributes = DavFobx->DavFileAttributes;
  759. listEntry = DavFobx->listEntry;
  760. //
  761. // If we have returned all the entries, inform the user that they are no
  762. // more entries to return.
  763. //
  764. if ( DavFobx->CurrentFileIndex == DavFobx->NumOfFileEntries ) {
  765. DavDbgTrace(( DAV_TRACE_DETAIL | DAV_TRACE_QUERYDIR ),
  766. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  767. "No more entries to return.\n", PsGetCurrentThreadId()));
  768. NtStatus = STATUS_NO_MORE_FILES;
  769. //
  770. // Reset the index for the next call.
  771. //
  772. DavFobx->CurrentFileIndex = 0;
  773. DavFobx->listEntry = &(DavFobx->DavFileAttributes->NextEntry);
  774. goto EXIT_THE_FUNCTION;
  775. }
  776. DavDbgTrace(( DAV_TRACE_DETAIL | DAV_TRACE_QUERYDIR ),
  777. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  778. "TLength = %d, TMaxLength = %d, Template = %wZ.\n",
  779. PsGetCurrentThreadId(),
  780. Template->Length, Template->MaximumLength, Template));
  781. do {
  782. TempDFA = CONTAINING_RECORD(listEntry, DAV_FILE_ATTRIBUTES, NextEntry);
  783. //
  784. // If this file did not come back with a 200 OK in the PROPFIND response
  785. // then we need to skip it. The response of a PROPFIND is a multi-status
  786. // with each file/directory having its own status.
  787. //
  788. if (TempDFA->InvalidNode) {
  789. listEntry = listEntry->Flink;
  790. DavFobx->listEntry = listEntry;
  791. DavFobx->CurrentFileIndex++;
  792. continue;
  793. }
  794. //
  795. // Check to see if the name of this entry matches the pattern supplied
  796. // by the user. If it does not, then we don't need to return it.
  797. //
  798. RtlInitUnicodeString(&(UnicodeFileName), TempDFA->FileName);
  799. DavDbgTrace(DAV_TRACE_DETAIL,
  800. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  801. "FileName = %ws\n", PsGetCurrentThreadId(), TempDFA->FileName));
  802. //
  803. // If the template does not contain any wild cards then we need to just
  804. // check if the unicode strings are equal. If it does contain wild cards,
  805. // then upcase the characters of the template and call
  806. // FsRtlIsNameInExpression.
  807. //
  808. ReturnVal = FsRtlDoesNameContainWildCards(Template);
  809. if (ReturnVal) {
  810. UNICODE_STRING UpperCaseString;
  811. UpperCaseString.Buffer = NULL;
  812. UpperCaseString.Length = UpperCaseString.MaximumLength = 0;
  813. NtStatus = RtlUpcaseUnicodeString(&(UpperCaseString), Template, TRUE);
  814. if (NtStatus != STATUS_SUCCESS) {
  815. DavDbgTrace(DAV_TRACE_ERROR,
  816. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest:"
  817. "/RtlUpcaseUnicodeString. NtStatus = %08lx.\n",
  818. PsGetCurrentThreadId(), NtStatus));
  819. goto EXIT_THE_FUNCTION;
  820. }
  821. ReturnVal = FsRtlIsNameInExpression(&(UpperCaseString),
  822. &(UnicodeFileName),
  823. TRUE,
  824. FALSE);
  825. //
  826. // RtlUpcaseUnicodeString allocates memory for the buffer field of
  827. // the UpperCaseString. We need to free it now.
  828. //
  829. RtlFreeUnicodeString( &(UpperCaseString) );
  830. } else {
  831. NoWildCards = TRUE;
  832. ReturnVal = RtlEqualUnicodeString(Template,
  833. &(UnicodeFileName),
  834. TRUE);
  835. }
  836. if (!ReturnVal) {
  837. //
  838. // This name does not match the pattern, so ignore it. Get the
  839. // next listEntry.
  840. //
  841. listEntry = listEntry->Flink;
  842. DavDbgTrace(( DAV_TRACE_DETAIL | DAV_TRACE_QUERYDIR ),
  843. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  844. "FileName %ws does not belong to pattern.\n",
  845. PsGetCurrentThreadId(), TempDFA->FileName));
  846. DavFobx->listEntry = listEntry;
  847. DavFobx->CurrentFileIndex++;
  848. continue;
  849. }
  850. //
  851. // The first entry in the DavFileAttributes list is the directory being
  852. // enumerated. In this case NoWildCards == FALSE. We shouldn't be
  853. // including this in the list of files returned. If we did a FindFirst
  854. // on a particular file, then the only entry is for the file itself. In
  855. // this case NoWildCards == TRUE.
  856. //
  857. if ( DavFobx->CurrentFileIndex == 0 && !NoWildCards ) {
  858. listEntry = listEntry->Flink;
  859. DavFobx->listEntry = listEntry;
  860. DavFobx->CurrentFileIndex++;
  861. continue;
  862. }
  863. //
  864. // If we did not get any FileAttributes for this file from the server,
  865. // set the attribute value to FILE_ATTRIBUTE_ARCHIVE since the apps
  866. // expect this.
  867. //
  868. if (TempDFA->dwFileAttributes == 0) {
  869. TempDFA->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
  870. }
  871. RtlCopyMemory(&CacheName.Buffer[DirectoryName->Length/2+1],
  872. UnicodeFileName.Buffer,
  873. UnicodeFileName.Length);
  874. CacheName.Length =
  875. CacheName.MaximumLength = DirectoryName->Length + UnicodeFileName.Length + sizeof(WCHAR);
  876. switch (FileInformationClass) {
  877. case FileNamesInformation:
  878. DavDbgTrace(DAV_TRACE_DETAIL,
  879. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  880. "FileInformationClass = FileNamesInformation.\n",
  881. PsGetCurrentThreadId()));
  882. //
  883. // Set the offset field of the previous block.
  884. //
  885. if (PreviousBlock) {
  886. FileNamesInfo = (PFILE_NAMES_INFORMATION)PreviousBlock;
  887. FileNamesInfo->NextEntryOffset = NextEntryOffset;
  888. }
  889. NextEntryOffset = sizeof(FILE_NAMES_INFORMATION);
  890. NextEntryOffset += ( (TempDFA->FileNameLength + 1) * sizeof(WCHAR) );
  891. //
  892. // We need to round up NextEntryOffset to the next multiple of 8.
  893. // We do this to maintain pointer alignment.
  894. //
  895. NextEntryOffset = ( ( ( NextEntryOffset + 7 ) / 8 ) * 8 );
  896. //
  897. // Is there enough space in the user supplied buffer to store the
  898. // next entry ? If not, we need to return now since we cannot store
  899. // any more entries.
  900. //
  901. if (NextEntryOffset > BufferLength) {
  902. DavDbgTrace(DAV_TRACE_ERROR,
  903. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  904. "Insufficient buffer length.\n",
  905. PsGetCurrentThreadId()));
  906. if (PreviousBlock) {
  907. FileNamesInfo = (PFILE_NAMES_INFORMATION)PreviousBlock;
  908. FileNamesInfo->NextEntryOffset = 0;
  909. }
  910. EndOfBuffer = TRUE;
  911. break;
  912. }
  913. FileNamesInfo = (PFILE_NAMES_INFORMATION)Buffer;
  914. //
  915. // The NextEntryOffset gets set on the next cycle. This way, for
  916. // the last entry it will be zero.
  917. //
  918. FileNamesInfo->NextEntryOffset = 0;
  919. FileNamesInfo->FileIndex = TempDFA->FileIndex;
  920. FileNamesInfo->FileNameLength = ( (TempDFA->FileNameLength + 1) * sizeof(WCHAR) );
  921. wcscpy(FileNamesInfo->FileName, TempDFA->FileName);
  922. PreviousBlock = (PVOID)FileNamesInfo;
  923. //
  924. // Increment the pointer to point at the next byte.
  925. //
  926. Buffer += NextEntryOffset;
  927. //
  928. // We have written "NextEntryOffset" bytes, so decrement the number
  929. // of bytes available pointer.
  930. //
  931. BufferLength -= NextEntryOffset;
  932. //
  933. // Increment the total number of bytes written.
  934. //
  935. BufferLengthUsed += NextEntryOffset;
  936. break;
  937. case FileDirectoryInformation:
  938. DavDbgTrace(DAV_TRACE_DETAIL,
  939. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  940. "FileInformationClass = FileDirectoryInformation.\n",
  941. PsGetCurrentThreadId()));
  942. //
  943. // Set the offset field of the previous block.
  944. //
  945. if (PreviousBlock) {
  946. FileDirInfo = (PFILE_DIRECTORY_INFORMATION)PreviousBlock;
  947. FileDirInfo->NextEntryOffset = NextEntryOffset;
  948. }
  949. NextEntryOffset = sizeof(FILE_DIRECTORY_INFORMATION);
  950. NextEntryOffset += ( (TempDFA->FileNameLength + 1) * sizeof(WCHAR) );
  951. //
  952. // We need to round up NextEntryOffset to the next multiple of 8.
  953. // We do this to maintain pointer alignment.
  954. //
  955. NextEntryOffset = ( ( ( NextEntryOffset + 7 ) / 8 ) * 8 );
  956. if (NextEntryOffset > BufferLength) {
  957. DavDbgTrace(DAV_TRACE_ERROR,
  958. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  959. "Insufficient buffer length.\n",
  960. PsGetCurrentThreadId()));
  961. if (PreviousBlock) {
  962. FileDirInfo = (PFILE_DIRECTORY_INFORMATION)PreviousBlock;
  963. FileDirInfo->NextEntryOffset = 0;
  964. }
  965. EndOfBuffer = TRUE;
  966. break;
  967. }
  968. FileDirInfo = (PFILE_DIRECTORY_INFORMATION)Buffer;
  969. FileDirInfo->NextEntryOffset = 0;
  970. FileDirInfo->FileIndex = TempDFA->FileIndex;
  971. FileDirInfo->CreationTime.LowPart = TempDFA->CreationTime.LowPart;
  972. FileDirInfo->CreationTime.HighPart = TempDFA->CreationTime.HighPart;
  973. FileDirInfo->LastAccessTime.LowPart = TempDFA->LastModifiedTime.LowPart;
  974. FileDirInfo->LastAccessTime.HighPart = TempDFA->LastModifiedTime.HighPart;
  975. FileDirInfo->LastWriteTime.LowPart = TempDFA->LastModifiedTime.LowPart;
  976. FileDirInfo->LastWriteTime.HighPart = TempDFA->LastModifiedTime.HighPart;
  977. FileDirInfo->ChangeTime.LowPart = TempDFA->LastModifiedTime.LowPart;
  978. FileDirInfo->ChangeTime.HighPart = TempDFA->LastModifiedTime.HighPart;
  979. FileDirInfo->EndOfFile.LowPart = TempDFA->FileSize.LowPart;
  980. FileDirInfo->EndOfFile.HighPart = TempDFA->FileSize.HighPart;
  981. FileDirInfo->AllocationSize.LowPart = TempDFA->FileSize.LowPart;
  982. FileDirInfo->AllocationSize.HighPart = TempDFA->FileSize.HighPart;
  983. FileDirInfo->FileAttributes = TempDFA->dwFileAttributes;
  984. if (TempDFA->isCollection) {
  985. FileDirInfo->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  986. }
  987. if (TempDFA->isHidden) {
  988. FileDirInfo->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
  989. }
  990. FileDirInfo->FileNameLength = ( (TempDFA->FileNameLength + 1) * sizeof(WCHAR) );
  991. wcscpy(FileDirInfo->FileName, TempDFA->FileName);
  992. PreviousBlock = (PVOID)FileDirInfo;
  993. Buffer += NextEntryOffset;
  994. BufferLength -= NextEntryOffset;
  995. BufferLengthUsed += NextEntryOffset;
  996. if (!MRxDAVIsBasicFileInfoCacheFound(RxContext,&BasicInfo,&NtStatus,&CacheName)) {
  997. if (TempDFA->isCollection) {
  998. UNICODE_STRING DirName;
  999. NtStatus = MRxDAVGetFullDirectoryPath(RxContext,&CacheName,&DirName);
  1000. if (DirName.Buffer != NULL) {
  1001. if (FileDirInfo->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  1002. NtStatus = MRxDAVCreateEncryptedDirectoryKey(&DirName);
  1003. } else {
  1004. NtStatus = MRxDAVQueryEncryptedDirectoryKey(&DirName);
  1005. if (NtStatus == STATUS_SUCCESS) {
  1006. FileDirInfo->FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1007. } else if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  1008. NtStatus = STATUS_SUCCESS;
  1009. }
  1010. }
  1011. // The buffer was allocated in MRxDAVGetFullDirectoryPath
  1012. RxFreePool(DirName.Buffer);
  1013. }
  1014. if (NtStatus != STATUS_SUCCESS) {
  1015. goto EXIT_THE_FUNCTION;
  1016. }
  1017. }
  1018. BasicInfo.CreationTime = FileDirInfo->CreationTime;
  1019. BasicInfo.LastAccessTime = FileDirInfo->LastAccessTime;
  1020. BasicInfo.LastWriteTime = FileDirInfo->LastWriteTime;
  1021. BasicInfo.ChangeTime = FileDirInfo->ChangeTime;
  1022. BasicInfo.FileAttributes = FileDirInfo->FileAttributes;
  1023. StandardInfo.AllocationSize = FileDirInfo->AllocationSize;
  1024. StandardInfo.EndOfFile = FileDirInfo->EndOfFile;
  1025. StandardInfo.NumberOfLinks = 1;
  1026. StandardInfo.DeletePending = FALSE;
  1027. StandardInfo.Directory = TempDFA->isCollection;
  1028. MRxDAVCreateFileInfoCacheWithName(&CacheName,
  1029. RxContext->pFcb->pNetRoot,
  1030. &BasicInfo,
  1031. &StandardInfo,
  1032. STATUS_SUCCESS);
  1033. } else {
  1034. if (TempDFA->isCollection && (BasicInfo.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  1035. FileDirInfo->FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1036. }
  1037. }
  1038. //
  1039. // We filter the FILE_ATTRIBUTE_TEMPORARY flag since on FAT (which
  1040. // we emulate), FindFirstFile and FindNextFile don�t return
  1041. // FILE_ATTRIBUTE_TEMPORARY flag even though GetFileAttributes
  1042. // returns it. Hence we only filter this in the attributes that
  1043. // are being returned in this call and not in the attributes that
  1044. // have been saved.
  1045. //
  1046. FileDirInfo->FileAttributes &= ~FILE_ATTRIBUTE_TEMPORARY;
  1047. break;
  1048. case FileFullDirectoryInformation:
  1049. DavDbgTrace(DAV_TRACE_DETAIL,
  1050. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  1051. "FileInformationClass = FileFullDirectoryInformation.\n",
  1052. PsGetCurrentThreadId()));
  1053. //
  1054. // Set the offset field of the previous block.
  1055. //
  1056. if (PreviousBlock) {
  1057. FileFullDirInfo = (PFILE_FULL_DIR_INFORMATION)PreviousBlock;
  1058. FileFullDirInfo->NextEntryOffset = NextEntryOffset;
  1059. }
  1060. NextEntryOffset = sizeof(FILE_FULL_DIR_INFORMATION);
  1061. NextEntryOffset += ( (TempDFA->FileNameLength + 1) * sizeof(WCHAR) );
  1062. //
  1063. // We need to round up NextEntryOffset to the next multiple of 8.
  1064. // We do this to maintain pointer alignment.
  1065. //
  1066. NextEntryOffset = ( ( ( NextEntryOffset + 7 ) / 8 ) * 8 );
  1067. if (NextEntryOffset > BufferLength) {
  1068. DavDbgTrace(DAV_TRACE_ERROR,
  1069. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  1070. "Insufficient buffer length.\n",
  1071. PsGetCurrentThreadId()));
  1072. if (PreviousBlock) {
  1073. FileFullDirInfo = (PFILE_FULL_DIR_INFORMATION)PreviousBlock;
  1074. FileFullDirInfo->NextEntryOffset = 0;
  1075. }
  1076. EndOfBuffer = TRUE;
  1077. break;
  1078. }
  1079. FileFullDirInfo = (PFILE_FULL_DIR_INFORMATION)Buffer;
  1080. FileFullDirInfo->NextEntryOffset = 0;
  1081. FileFullDirInfo->FileIndex = TempDFA->FileIndex;
  1082. FileFullDirInfo->CreationTime.LowPart = TempDFA->CreationTime.LowPart;
  1083. FileFullDirInfo->CreationTime.HighPart = TempDFA->CreationTime.HighPart;
  1084. FileFullDirInfo->LastAccessTime.LowPart = TempDFA->LastModifiedTime.LowPart;
  1085. FileFullDirInfo->LastAccessTime.HighPart = TempDFA->LastModifiedTime.HighPart;
  1086. FileFullDirInfo->LastWriteTime.LowPart = TempDFA->LastModifiedTime.LowPart;
  1087. FileFullDirInfo->LastWriteTime.HighPart = TempDFA->LastModifiedTime.HighPart;
  1088. FileFullDirInfo->ChangeTime.LowPart = TempDFA->LastModifiedTime.LowPart;
  1089. FileFullDirInfo->ChangeTime.HighPart = TempDFA->LastModifiedTime.HighPart;
  1090. FileFullDirInfo->EndOfFile.LowPart = TempDFA->FileSize.LowPart;
  1091. FileFullDirInfo->EndOfFile.HighPart = TempDFA->FileSize.HighPart;
  1092. FileFullDirInfo->AllocationSize.LowPart = TempDFA->FileSize.LowPart;
  1093. FileFullDirInfo->AllocationSize.HighPart = TempDFA->FileSize.HighPart;
  1094. FileFullDirInfo->FileAttributes = TempDFA->dwFileAttributes;
  1095. if (TempDFA->isCollection) {
  1096. FileFullDirInfo->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  1097. }
  1098. if (TempDFA->isHidden) {
  1099. FileFullDirInfo->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
  1100. }
  1101. FileFullDirInfo->EaSize = 0;
  1102. FileFullDirInfo->FileNameLength = ( (TempDFA->FileNameLength + 1) * sizeof(WCHAR) );
  1103. wcscpy(FileFullDirInfo->FileName, TempDFA->FileName);
  1104. PreviousBlock = (PVOID)FileFullDirInfo;
  1105. Buffer += NextEntryOffset;
  1106. BufferLength -= NextEntryOffset;
  1107. BufferLengthUsed += NextEntryOffset;
  1108. if (!MRxDAVIsBasicFileInfoCacheFound(RxContext,&BasicInfo,&NtStatus,&CacheName)) {
  1109. if (TempDFA->isCollection) {
  1110. UNICODE_STRING DirName;
  1111. NtStatus = MRxDAVGetFullDirectoryPath(RxContext,&CacheName,&DirName);
  1112. if (DirName.Buffer != NULL) {
  1113. if (FileFullDirInfo->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  1114. NtStatus = MRxDAVCreateEncryptedDirectoryKey(&DirName);
  1115. } else {
  1116. NtStatus = MRxDAVQueryEncryptedDirectoryKey(&DirName);
  1117. if (NtStatus == STATUS_SUCCESS) {
  1118. FileFullDirInfo->FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1119. } else if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  1120. NtStatus = STATUS_SUCCESS;
  1121. }
  1122. }
  1123. // The buffer was allocated in MRxDAVGetFullDirectoryPath
  1124. RxFreePool(DirName.Buffer);
  1125. }
  1126. if (NtStatus != STATUS_SUCCESS) {
  1127. goto EXIT_THE_FUNCTION;
  1128. }
  1129. }
  1130. BasicInfo.CreationTime = FileFullDirInfo->CreationTime;
  1131. BasicInfo.LastAccessTime = FileFullDirInfo->LastAccessTime;
  1132. BasicInfo.LastWriteTime = FileFullDirInfo->LastWriteTime;
  1133. BasicInfo.ChangeTime = FileFullDirInfo->ChangeTime;
  1134. BasicInfo.FileAttributes = FileFullDirInfo->FileAttributes;
  1135. StandardInfo.AllocationSize = FileFullDirInfo->AllocationSize;
  1136. StandardInfo.EndOfFile = FileFullDirInfo->EndOfFile;
  1137. StandardInfo.NumberOfLinks = 1;
  1138. StandardInfo.DeletePending = FALSE;
  1139. StandardInfo.Directory = TempDFA->isCollection;
  1140. MRxDAVCreateFileInfoCacheWithName(&CacheName,
  1141. RxContext->pFcb->pNetRoot,
  1142. &BasicInfo,
  1143. &StandardInfo,
  1144. STATUS_SUCCESS);
  1145. } else {
  1146. if (TempDFA->isCollection && (BasicInfo.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  1147. FileFullDirInfo->FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1148. }
  1149. }
  1150. //
  1151. // We filter the FILE_ATTRIBUTE_TEMPORARY flag since on FAT (which
  1152. // we emulate), FindFirstFile and FindNextFile don�t return
  1153. // FILE_ATTRIBUTE_TEMPORARY flag even though GetFileAttributes
  1154. // returns it. Hence we only filter this in the attributes that
  1155. // are being returned in this call and not in the attributes that
  1156. // have been saved.
  1157. //
  1158. FileFullDirInfo->FileAttributes &= ~FILE_ATTRIBUTE_TEMPORARY;
  1159. break;
  1160. case FileBothDirectoryInformation:
  1161. DavDbgTrace(DAV_TRACE_DETAIL,
  1162. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  1163. "FileInformationClass = FileBothDirectoryInformation.\n",
  1164. PsGetCurrentThreadId()));
  1165. //
  1166. // Set the offset field of the previous block.
  1167. //
  1168. if (PreviousBlock) {
  1169. FileBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)PreviousBlock;
  1170. FileBothDirInfo->NextEntryOffset = NextEntryOffset;
  1171. }
  1172. NextEntryOffset = sizeof(FILE_BOTH_DIR_INFORMATION);
  1173. NextEntryOffset += ( (TempDFA->FileNameLength + 1) * sizeof(WCHAR) );
  1174. //
  1175. // We need to round up NextEntryOffset to the next multiple of 8.
  1176. // We do this to maintain pointer alignment.
  1177. //
  1178. NextEntryOffset = ( ( ( NextEntryOffset + 7 ) / 8 ) * 8 );
  1179. if (NextEntryOffset > BufferLength) {
  1180. DavDbgTrace(DAV_TRACE_ERROR,
  1181. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest:"
  1182. " Insufficient buffer length.\n",
  1183. PsGetCurrentThreadId()));
  1184. if (PreviousBlock) {
  1185. FileBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)PreviousBlock;
  1186. FileBothDirInfo->NextEntryOffset = 0;
  1187. }
  1188. EndOfBuffer = TRUE;
  1189. break;
  1190. }
  1191. FileBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)Buffer;
  1192. FileBothDirInfo->NextEntryOffset = 0;
  1193. FileBothDirInfo->FileIndex = TempDFA->FileIndex;
  1194. FileBothDirInfo->CreationTime.LowPart = TempDFA->CreationTime.LowPart;
  1195. FileBothDirInfo->CreationTime.HighPart = TempDFA->CreationTime.HighPart;
  1196. FileBothDirInfo->LastAccessTime.LowPart = TempDFA->LastModifiedTime.LowPart;
  1197. FileBothDirInfo->LastAccessTime.HighPart = TempDFA->LastModifiedTime.HighPart;
  1198. FileBothDirInfo->LastWriteTime.LowPart = TempDFA->LastModifiedTime.LowPart;
  1199. FileBothDirInfo->LastWriteTime.HighPart = TempDFA->LastModifiedTime.HighPart;
  1200. FileBothDirInfo->ChangeTime.LowPart = TempDFA->LastModifiedTime.LowPart;
  1201. FileBothDirInfo->ChangeTime.HighPart = TempDFA->LastModifiedTime.HighPart;
  1202. FileBothDirInfo->EndOfFile.LowPart = TempDFA->FileSize.LowPart;
  1203. FileBothDirInfo->EndOfFile.HighPart = TempDFA->FileSize.HighPart;
  1204. FileBothDirInfo->AllocationSize.LowPart = TempDFA->FileSize.LowPart;
  1205. FileBothDirInfo->AllocationSize.HighPart = TempDFA->FileSize.HighPart;
  1206. FileBothDirInfo->FileAttributes = TempDFA->dwFileAttributes;
  1207. if (TempDFA->isCollection) {
  1208. FileBothDirInfo->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  1209. }
  1210. if (TempDFA->isHidden) {
  1211. FileBothDirInfo->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
  1212. }
  1213. FileBothDirInfo->EaSize = 0;
  1214. //
  1215. // We don't support short file names. We add L'\0' as the first
  1216. // character in the ShortName string to make it a zero length name.
  1217. //
  1218. FileBothDirInfo->ShortNameLength = 0;
  1219. FileBothDirInfo->ShortName[0] = L'\0';
  1220. FileBothDirInfo->FileNameLength = ( (TempDFA->FileNameLength + 1) * sizeof(WCHAR) );
  1221. wcscpy(FileBothDirInfo->FileName, TempDFA->FileName);
  1222. PreviousBlock = (PVOID)FileBothDirInfo;
  1223. Buffer += NextEntryOffset;
  1224. BufferLength -= NextEntryOffset;
  1225. BufferLengthUsed += NextEntryOffset;
  1226. if (!MRxDAVIsBasicFileInfoCacheFound(RxContext,&BasicInfo,&NtStatus,&CacheName)) {
  1227. if (TempDFA->isCollection) {
  1228. UNICODE_STRING DirName;
  1229. NtStatus = MRxDAVGetFullDirectoryPath(RxContext,&CacheName,&DirName);
  1230. if (DirName.Buffer != NULL) {
  1231. if (FileBothDirInfo->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  1232. NtStatus = MRxDAVCreateEncryptedDirectoryKey(&DirName);
  1233. } else {
  1234. NtStatus = MRxDAVQueryEncryptedDirectoryKey(&DirName);
  1235. if (NtStatus == STATUS_SUCCESS) {
  1236. FileBothDirInfo->FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1237. } else if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  1238. NtStatus = STATUS_SUCCESS;
  1239. }
  1240. }
  1241. // The buffer was allocated in MRxDAVGetFullDirectoryPath
  1242. RxFreePool(DirName.Buffer);
  1243. }
  1244. if (NtStatus != STATUS_SUCCESS) {
  1245. goto EXIT_THE_FUNCTION;
  1246. }
  1247. }
  1248. BasicInfo.CreationTime = FileBothDirInfo->CreationTime;
  1249. BasicInfo.LastAccessTime = FileBothDirInfo->LastAccessTime;
  1250. BasicInfo.LastWriteTime = FileBothDirInfo->LastWriteTime;
  1251. BasicInfo.ChangeTime = FileBothDirInfo->ChangeTime;
  1252. BasicInfo.FileAttributes = FileBothDirInfo->FileAttributes;
  1253. StandardInfo.AllocationSize = FileBothDirInfo->AllocationSize;
  1254. StandardInfo.EndOfFile = FileBothDirInfo->EndOfFile;
  1255. StandardInfo.NumberOfLinks = 1;
  1256. StandardInfo.DeletePending = FALSE;
  1257. StandardInfo.Directory = TempDFA->isCollection;
  1258. MRxDAVCreateFileInfoCacheWithName(&CacheName,
  1259. RxContext->pFcb->pNetRoot,
  1260. &BasicInfo,
  1261. &StandardInfo,
  1262. STATUS_SUCCESS);
  1263. } else {
  1264. if (TempDFA->isCollection && (BasicInfo.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  1265. FileBothDirInfo->FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1266. }
  1267. }
  1268. //
  1269. // We filter the FILE_ATTRIBUTE_TEMPORARY flag since on FAT (which
  1270. // we emulate), FindFirstFile and FindNextFile don�t return
  1271. // FILE_ATTRIBUTE_TEMPORARY flag even though GetFileAttributes
  1272. // returns it. Hence we only filter this in the attributes that
  1273. // are being returned in this call and not in the attributes that
  1274. // have been saved.
  1275. //
  1276. FileBothDirInfo->FileAttributes &= ~FILE_ATTRIBUTE_TEMPORARY;
  1277. break;
  1278. default:
  1279. DavDbgTrace(DAV_TRACE_ERROR,
  1280. ("%ld: MRxDAVPrecompleteUserModeQueryDirectoryRequest: "
  1281. "FileInformationClass = UnKnown(%d).\n",
  1282. PsGetCurrentThreadId(), FileInformationClass));
  1283. NtStatus = STATUS_NOT_SUPPORTED;
  1284. goto EXIT_THE_FUNCTION;
  1285. break;
  1286. } // end of switch(FileInformationClass)
  1287. //
  1288. // If the user supplied buffer is not enough to store any more
  1289. // information, we are done. This check should be done before
  1290. // changing the values below.
  1291. //
  1292. if (EndOfBuffer) {
  1293. NtStatus = STATUS_SUCCESS;
  1294. break;
  1295. }
  1296. //
  1297. // These values should be changed after the "EndOfBuffer" check and
  1298. // before the "SingleEntry" check.
  1299. //
  1300. listEntry = listEntry->Flink;
  1301. DavFobx->listEntry = listEntry;
  1302. DavFobx->CurrentFileIndex++;
  1303. //
  1304. // If the user only asked for a single entry, we are done. This check
  1305. // should be done, after changing the values above.
  1306. //
  1307. if (SingleEntry) {
  1308. break;
  1309. }
  1310. } while ( listEntry != &(DavFileAttributes->NextEntry) );
  1311. //
  1312. // If we have gone through all the entries and the BufferLengthUsed is 0,
  1313. // then we need to return
  1314. //
  1315. if ( BufferLengthUsed == 0 && listEntry == &(DavFileAttributes->NextEntry) ) {
  1316. NtStatus = STATUS_NO_MORE_FILES;
  1317. //
  1318. // Reset the index for the next call.
  1319. //
  1320. DavFobx->CurrentFileIndex = 0;
  1321. DavFobx->listEntry = &(DavFobx->DavFileAttributes->NextEntry);
  1322. goto EXIT_THE_FUNCTION;
  1323. }
  1324. RxContext->Info.LengthRemaining -= BufferLengthUsed;
  1325. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  1326. ("%ld: Leaving MRxDAVPrecompleteUserModeQueryDirectoryRequest.\n",
  1327. PsGetCurrentThreadId()));
  1328. EXIT_THE_FUNCTION:
  1329. AsyncEngineContext->Status = NtStatus;
  1330. if (CacheName.Buffer != NULL) {
  1331. RxFreePool(CacheName.Buffer);
  1332. }
  1333. return(TRUE);
  1334. }
  1335. NTSTATUS
  1336. MRxDAVQueryDirectoryFromCache(
  1337. IN PRX_CONTEXT RxContext,
  1338. IN PBYTE Buffer,
  1339. IN PFILE_BASIC_INFORMATION BasicInfo,
  1340. IN PFILE_STANDARD_INFORMATION StandardInfo,
  1341. IN ULONG FileIndex
  1342. )
  1343. /*++
  1344. Routine Description:
  1345. The precompletion routine for the create SrvCall request.
  1346. Arguments:
  1347. RxContext - The RDBSS context.
  1348. AsyncEngineContext - The reflctor's context.
  1349. WorkItem - The work item buffer.
  1350. WorkItemLength - The length of the work item buffer.
  1351. Return Value:
  1352. TRUE or FALSE.
  1353. --*/
  1354. {
  1355. RxCaptureFobx;
  1356. NTSTATUS NtStatus = STATUS_SUCCESS;
  1357. PFILE_NAMES_INFORMATION FileNamesInfo = NULL;
  1358. PFILE_DIRECTORY_INFORMATION FileDirInfo = NULL;
  1359. PFILE_FULL_DIR_INFORMATION FileFullDirInfo = NULL;
  1360. PFILE_BOTH_DIR_INFORMATION FileBothDirInfo = NULL;
  1361. ULONG BufferLength;
  1362. PUNICODE_STRING FileName = &capFobx->UnicodeQueryTemplate;
  1363. ULONG SpaceNeeded = 0;
  1364. PAGED_CODE();
  1365. BufferLength = RxContext->Info.LengthRemaining;
  1366. SpaceNeeded = FileName->Length;
  1367. switch (RxContext->Info.FileInformationClass) {
  1368. case FileNamesInformation:
  1369. DavDbgTrace(DAV_TRACE_DETAIL,
  1370. ("%ld: MRxDAVQueryDirectoryFromCache: "
  1371. "FileInformationClass = FileNamesInformation.\n",
  1372. PsGetCurrentThreadId()));
  1373. SpaceNeeded += sizeof(FILE_NAMES_INFORMATION);
  1374. //
  1375. // Is there enough space in the user supplied buffer to store the
  1376. // next entry ? If not, we need to return now since we cannot store
  1377. // any more entries.
  1378. //
  1379. if (SpaceNeeded > BufferLength) {
  1380. NtStatus = STATUS_BUFFER_OVERFLOW;
  1381. goto EXIT_THE_FUNCTION;
  1382. }
  1383. FileNamesInfo = (PFILE_NAMES_INFORMATION)Buffer;
  1384. FileNamesInfo->NextEntryOffset = 0;
  1385. FileNamesInfo->FileIndex = FileIndex;
  1386. FileNamesInfo->FileNameLength = FileName->Length;
  1387. RtlCopyMemory(FileNamesInfo->FileName,FileName->Buffer,FileName->Length);
  1388. break;
  1389. case FileDirectoryInformation:
  1390. DavDbgTrace(DAV_TRACE_DETAIL,
  1391. ("%ld: MRxDAVQueryDirectoryFromCache: "
  1392. "FileInformationClass = FileDirectoryInformation.\n",
  1393. PsGetCurrentThreadId()));
  1394. SpaceNeeded += sizeof(FILE_DIRECTORY_INFORMATION);
  1395. if (SpaceNeeded > BufferLength) {
  1396. DavDbgTrace(DAV_TRACE_ERROR,
  1397. ("%ld: MRxDAVQueryDirectoryFromCache: "
  1398. "Insufficient buffer length.\n",
  1399. PsGetCurrentThreadId()));
  1400. NtStatus = STATUS_BUFFER_OVERFLOW;
  1401. goto EXIT_THE_FUNCTION;
  1402. }
  1403. FileDirInfo = (PFILE_DIRECTORY_INFORMATION)Buffer;
  1404. FileDirInfo->NextEntryOffset = 0;
  1405. FileDirInfo->FileIndex = FileIndex;
  1406. FileDirInfo->CreationTime.QuadPart = BasicInfo->CreationTime.QuadPart;
  1407. FileDirInfo->LastAccessTime.QuadPart = BasicInfo->LastAccessTime.QuadPart;
  1408. FileDirInfo->LastWriteTime.QuadPart = BasicInfo->LastWriteTime.QuadPart;
  1409. FileDirInfo->ChangeTime.QuadPart = BasicInfo->ChangeTime.QuadPart;
  1410. FileDirInfo->FileAttributes = BasicInfo->FileAttributes;
  1411. //
  1412. // We filter the FILE_ATTRIBUTE_TEMPORARY flag since on FAT (which
  1413. // we emulate), FindFirstFile and FindNextFile don�t return
  1414. // FILE_ATTRIBUTE_TEMPORARY flag even though GetFileAttributes
  1415. // returns it. Hence we only filter this in the attributes that
  1416. // are being returned in this call and not in the attributes that
  1417. // have been saved.
  1418. //
  1419. FileDirInfo->FileAttributes &= ~FILE_ATTRIBUTE_TEMPORARY;
  1420. FileDirInfo->EndOfFile.QuadPart = StandardInfo->EndOfFile.QuadPart;
  1421. FileDirInfo->AllocationSize.QuadPart = StandardInfo->AllocationSize.QuadPart;
  1422. FileDirInfo->FileNameLength = FileName->Length;
  1423. RtlCopyMemory(FileDirInfo->FileName,FileName->Buffer,FileName->Length);
  1424. break;
  1425. case FileFullDirectoryInformation:
  1426. DavDbgTrace(DAV_TRACE_DETAIL,
  1427. ("%ld: MRxDAVQueryDirectoryFromCache: "
  1428. "FileInformationClass = FileFullDirectoryInformation.\n",
  1429. PsGetCurrentThreadId()));
  1430. SpaceNeeded += sizeof(FILE_FULL_DIR_INFORMATION);
  1431. if (SpaceNeeded > BufferLength) {
  1432. DavDbgTrace(DAV_TRACE_ERROR,
  1433. ("%ld: MRxDAVQueryDirectoryFromCache: "
  1434. "Insufficient buffer length.\n",
  1435. PsGetCurrentThreadId()));
  1436. NtStatus = STATUS_BUFFER_OVERFLOW;
  1437. goto EXIT_THE_FUNCTION;
  1438. }
  1439. FileFullDirInfo = (PFILE_FULL_DIR_INFORMATION)Buffer;
  1440. FileFullDirInfo->NextEntryOffset = 0;
  1441. FileFullDirInfo->FileIndex = FileIndex;
  1442. FileFullDirInfo->CreationTime.QuadPart = BasicInfo->CreationTime.QuadPart;
  1443. FileFullDirInfo->LastAccessTime.QuadPart = BasicInfo->LastAccessTime.QuadPart;
  1444. FileFullDirInfo->LastWriteTime.QuadPart = BasicInfo->LastWriteTime.QuadPart;
  1445. FileFullDirInfo->ChangeTime.QuadPart = BasicInfo->ChangeTime.QuadPart;
  1446. FileFullDirInfo->FileAttributes = BasicInfo->FileAttributes;
  1447. //
  1448. // We filter the FILE_ATTRIBUTE_TEMPORARY flag since on FAT (which
  1449. // we emulate), FindFirstFile and FindNextFile don�t return
  1450. // FILE_ATTRIBUTE_TEMPORARY flag even though GetFileAttributes
  1451. // returns it. Hence we only filter this in the attributes that
  1452. // are being returned in this call and not in the attributes that
  1453. // have been saved.
  1454. //
  1455. FileFullDirInfo->FileAttributes &= ~FILE_ATTRIBUTE_TEMPORARY;
  1456. FileFullDirInfo->EndOfFile.QuadPart = StandardInfo->EndOfFile.QuadPart;
  1457. FileFullDirInfo->AllocationSize.QuadPart = StandardInfo->AllocationSize.QuadPart;
  1458. FileFullDirInfo->EaSize = 0;
  1459. FileFullDirInfo->FileNameLength = FileName->Length;
  1460. RtlCopyMemory(FileFullDirInfo->FileName,FileName->Buffer,FileName->Length);
  1461. break;
  1462. case FileBothDirectoryInformation:
  1463. DavDbgTrace(DAV_TRACE_DETAIL,
  1464. ("%ld: MRxDAVQueryDirectoryFromCache: "
  1465. "FileInformationClass = FileBothDirectoryInformation.\n",
  1466. PsGetCurrentThreadId()));
  1467. SpaceNeeded += sizeof(FILE_BOTH_DIR_INFORMATION);
  1468. if (SpaceNeeded > BufferLength) {
  1469. DavDbgTrace(DAV_TRACE_ERROR,
  1470. ("%ld: MRxDAVQueryDirectoryFromCache: "
  1471. "Insufficient buffer length.\n",
  1472. PsGetCurrentThreadId()));
  1473. NtStatus = STATUS_BUFFER_OVERFLOW;
  1474. goto EXIT_THE_FUNCTION;
  1475. }
  1476. FileBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)Buffer;
  1477. FileBothDirInfo->NextEntryOffset = 0;
  1478. FileBothDirInfo->FileIndex = FileIndex;
  1479. FileBothDirInfo->CreationTime.QuadPart = BasicInfo->CreationTime.QuadPart;
  1480. FileBothDirInfo->LastAccessTime.QuadPart = BasicInfo->LastAccessTime.QuadPart;
  1481. FileBothDirInfo->LastWriteTime.QuadPart = BasicInfo->LastWriteTime.QuadPart;
  1482. FileBothDirInfo->ChangeTime.QuadPart = BasicInfo->ChangeTime.QuadPart;
  1483. FileBothDirInfo->FileAttributes = BasicInfo->FileAttributes;
  1484. //
  1485. // We filter the FILE_ATTRIBUTE_TEMPORARY flag since on FAT (which
  1486. // we emulate), FindFirstFile and FindNextFile don�t return
  1487. // FILE_ATTRIBUTE_TEMPORARY flag even though GetFileAttributes
  1488. // returns it. Hence we only filter this in the attributes that
  1489. // are being returned in this call and not in the attributes that
  1490. // have been saved.
  1491. //
  1492. FileBothDirInfo->FileAttributes &= ~FILE_ATTRIBUTE_TEMPORARY;
  1493. FileBothDirInfo->EndOfFile.QuadPart = StandardInfo->EndOfFile.QuadPart;
  1494. FileBothDirInfo->AllocationSize.QuadPart = StandardInfo->AllocationSize.QuadPart;
  1495. FileBothDirInfo->EaSize = 0;
  1496. //
  1497. // We don't support short file names. We add L'\0' as the first
  1498. // character in the ShortName string to make it a zero length name.
  1499. //
  1500. FileBothDirInfo->ShortNameLength = 0;
  1501. FileBothDirInfo->ShortName[0] = L'\0';
  1502. FileBothDirInfo->FileNameLength = FileName->Length;
  1503. RtlCopyMemory(FileBothDirInfo->FileName,FileName->Buffer,FileName->Length);
  1504. break;
  1505. default:
  1506. DavDbgTrace(DAV_TRACE_ERROR,
  1507. ("%ld: MRxDAVQueryDirectoryFromCache: "
  1508. "FileInformationClass = UnKnown(%d).\n",
  1509. PsGetCurrentThreadId(), RxContext->Info.FileInformationClass));
  1510. NtStatus = STATUS_NOT_SUPPORTED;
  1511. goto EXIT_THE_FUNCTION;
  1512. break;
  1513. } // end of switch(FileInformationClass)
  1514. RxContext->Info.LengthRemaining -= SpaceNeeded;
  1515. EXIT_THE_FUNCTION:
  1516. return NtStatus;
  1517. }