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.

638 lines
19 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. fcbfobx.c
  5. Abstract:
  6. This code manages the finalizing of the FCB and FOBX strucutres of the
  7. DAV Mini-Redir.
  8. Author:
  9. Rohan Kumar [RohanK] 26-Sept-1999
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include "webdav.h"
  14. //
  15. // Mentioned below are the prototypes of functions tht are used only within
  16. // this module (file). These functions should not be exposed outside.
  17. //
  18. NTSTATUS
  19. MRxDAVDeallocateForFobxContinuation(
  20. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  21. );
  22. NTSTATUS
  23. MRxDAVFormatUserModeFobxFinalizeRequest(
  24. IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  25. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  26. IN ULONG WorkItemLength,
  27. OUT PULONG_PTR ReturnedLength
  28. );
  29. BOOL
  30. MRxDAVPrecompleteUserModeFobxFinalizeRequest(
  31. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  32. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  33. ULONG WorkItemLength,
  34. BOOL OperationCancelled
  35. );
  36. VOID
  37. DavLogDelayedWriteError(
  38. PUNICODE_STRING PathName
  39. );
  40. #ifdef ALLOC_PRAGMA
  41. #pragma alloc_text(PAGE, MRxDAVDeallocateForFobx)
  42. #pragma alloc_text(PAGE, MRxDAVDeallocateForFobxContinuation)
  43. #pragma alloc_text(PAGE, MRxDAVFormatUserModeFobxFinalizeRequest)
  44. #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeFobxFinalizeRequest)
  45. #pragma alloc_text(PAGE, MRxDAVCleanupFobx)
  46. #pragma alloc_text(PAGE, MRxDAVDeallocateForFcb)
  47. #pragma alloc_text(PAGE, DavLogDelayedWriteError)
  48. #endif
  49. //
  50. // Implementation of functions begins here.
  51. //
  52. NTSTATUS
  53. MRxDAVDeallocateForFobx(
  54. IN OUT PMRX_FOBX pFobx
  55. )
  56. /*++
  57. Routine Description:
  58. This routine is called when the wrapper is about to deallocate a FOBX.
  59. Arguments:
  60. pFobx - the Fobx being deallocated.
  61. Return Value:
  62. RXSTATUS - STATUS_SUCCESS
  63. --*/
  64. {
  65. NTSTATUS NtStatus = STATUS_SUCCESS;
  66. PWEBDAV_FOBX DavFobx = NULL;
  67. PRX_CONTEXT RxContext = NULL;
  68. PMRX_SRV_CALL SrvCall;
  69. PRDBSS_DEVICE_OBJECT RxDeviceObject;
  70. PUNICODE_STRING RemainingName = NULL;
  71. PAGED_CODE();
  72. SrvCall = (PMRX_SRV_CALL)pFobx->pSrvOpen->pFcb->pNetRoot->pSrvCall;
  73. ASSERT(SrvCall);
  74. RxDeviceObject = SrvCall->RxDeviceObject;
  75. DavFobx = MRxDAVGetFobxExtension(pFobx);
  76. ASSERT(DavFobx != NULL);
  77. RemainingName = pFobx->pSrvOpen->pAlreadyPrefixedName;
  78. DavDbgTrace(DAV_TRACE_DETAIL,
  79. ("%ld: Entering MRxDAVDeallocateForFobx. RemainingName = %wZ.\n",
  80. PsGetCurrentThreadId(), RemainingName));
  81. //
  82. // If this FOBX does not have a list of DavFileAttributes, we are done.
  83. //
  84. if (DavFobx->DavFileAttributes == NULL) {
  85. return NtStatus;
  86. }
  87. DavDbgTrace(DAV_TRACE_DETAIL,
  88. ("%ld: MRxDAVDeallocateForFobx. DavFileAttributes = %08lx.\n",
  89. PsGetCurrentThreadId(), DavFobx->DavFileAttributes));
  90. //
  91. // We need to finalize the list of DavFileAttributes.
  92. //
  93. //
  94. // Unfortunately, we do not have an RxContext here and hence have to create
  95. // one. An RxContext is required for a request to be reflected up.
  96. //
  97. RxContext = RxCreateRxContext(NULL, RxDeviceObject, 0);
  98. if (RxContext == NULL) {
  99. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  100. DavDbgTrace(DAV_TRACE_ERROR,
  101. ("%ld: MRxDAVDeallocateForFobx/RxCreateRxContext: "
  102. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  103. goto EXIT_THE_FUNCTION;
  104. }
  105. //
  106. // We need to send the Fobx to the format routine and use the
  107. // MRxContext[1] pointer of the RxContext structure to store it.
  108. //
  109. RxContext->MRxContext[1] = (PVOID)pFobx;
  110. NtStatus = UMRxAsyncEngOuterWrapper(RxContext,
  111. SIZEOF_DAV_SPECIFIC_CONTEXT,
  112. MRxDAVFormatTheDAVContext,
  113. DAV_MINIRDR_ENTRY_FROM_CLEANUPFOBX,
  114. MRxDAVDeallocateForFobxContinuation,
  115. "MRxDAVDeallocateForFobx");
  116. if (NtStatus != ERROR_SUCCESS) {
  117. DavDbgTrace(DAV_TRACE_ERROR,
  118. ("%ld: MRxDAVDeallocateForFobx/UMRxAsyncEngOuterWrapper: "
  119. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  120. }
  121. EXIT_THE_FUNCTION:
  122. if (RxContext) {
  123. RxDereferenceAndDeleteRxContext(RxContext);
  124. }
  125. DavDbgTrace(DAV_TRACE_DETAIL,
  126. ("%ld: Leaving MRxDAVDeallocateForFobx with NtStatus = %08lx.\n",
  127. PsGetCurrentThreadId(), NtStatus));
  128. return(NtStatus);
  129. }
  130. NTSTATUS
  131. MRxDAVDeallocateForFobxContinuation(
  132. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  133. )
  134. /*++
  135. Routine Description:
  136. This is the continuation routine which finalizes an Fobx.
  137. Arguments:
  138. AsyncEngineContext - The Reflectors context.
  139. RxContext - The RDBSS context.
  140. Return Value:
  141. RXSTATUS - The return status for the operation
  142. --*/
  143. {
  144. NTSTATUS NtStatus;
  145. PAGED_CODE();
  146. DavDbgTrace(DAV_TRACE_DETAIL,
  147. ("%ld: Entering MRxDAVDeallocateForFobxContinuation.\n",
  148. PsGetCurrentThreadId()));
  149. DavDbgTrace(DAV_TRACE_CONTEXT,
  150. ("%ld: MRxDAVDeallocateForFobxContinuation: "
  151. "AsyncEngineContext: %08lx, RxContext: %08lx\n",
  152. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  153. //
  154. // Try usermode.
  155. //
  156. NtStatus = UMRxSubmitAsyncEngUserModeRequest(
  157. UMRX_ASYNCENGINE_ARGUMENTS,
  158. MRxDAVFormatUserModeFobxFinalizeRequest,
  159. MRxDAVPrecompleteUserModeFobxFinalizeRequest
  160. );
  161. DavDbgTrace(DAV_TRACE_DETAIL,
  162. ("%ld: Leaving MRxDAVFinalizeSrvCallContinuation with NtStatus"
  163. " = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  164. return NtStatus;
  165. }
  166. NTSTATUS
  167. MRxDAVFormatUserModeFobxFinalizeRequest(
  168. IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  169. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  170. IN ULONG WorkItemLength,
  171. OUT PULONG_PTR ReturnedLength
  172. )
  173. /*++
  174. Routine Description:
  175. This routine formats the Fobx finalize request being sent to the user
  176. mode for processing.
  177. Arguments:
  178. RxContext - The RDBSS context.
  179. AsyncEngineContext - The reflctor's context.
  180. WorkItem - The work item buffer.
  181. WorkItemLength - The length of the work item buffer.
  182. ReturnedLength -
  183. Return Value:
  184. STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES.
  185. --*/
  186. {
  187. NTSTATUS NtStatus = STATUS_SUCCESS;
  188. PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  189. PDAV_USERMODE_FINALIZE_FOBX_REQUEST FinFobxReq = NULL;
  190. PMRX_FOBX Fobx = NULL;
  191. PWEBDAV_FOBX DavFobx = NULL;
  192. PAGED_CODE();
  193. DavDbgTrace(DAV_TRACE_DETAIL,
  194. ("%ld: Entering MRxDAVFormatUserModeFobxFinalizeRequest.\n",
  195. PsGetCurrentThreadId()));
  196. DavDbgTrace(DAV_TRACE_CONTEXT,
  197. ("%ld: MRxDAVFormatUserModeFobxFinalizeRequest: "
  198. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  199. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  200. //
  201. // We dont impersonate the user before going up to the user mode since
  202. // all we do in the user mode is free memory and the users credentials are
  203. // not needed to do this.
  204. //
  205. //
  206. // Fobx was set to MRxContext[1] in MRxDAVDeallocateForFobx. We need it to
  207. // get the pointer to the DavFileAttributes list.
  208. //
  209. Fobx = (PMRX_FOBX)RxContext->MRxContext[1];
  210. DavFobx = MRxDAVGetFobxExtension(Fobx);
  211. ASSERT(DavFobx != NULL);
  212. ASSERT(DavFobx->DavFileAttributes != NULL);
  213. DavDbgTrace(DAV_TRACE_DETAIL,
  214. ("%ld: MRxDAVFormatUserModeFobxFinalizeRequest. DavFileAttributes = %08lx.\n",
  215. PsGetCurrentThreadId(), DavFobx->DavFileAttributes));
  216. DavWorkItem->WorkItemType = UserModeFinalizeFobx;
  217. FinFobxReq = &(DavWorkItem->FinalizeFobxRequest);
  218. FinFobxReq->DavFileAttributes = DavFobx->DavFileAttributes;
  219. DavDbgTrace(DAV_TRACE_DETAIL,
  220. ("%ld: Leaving MRxDAVFormatUserModeFobxFinalizeRequest "
  221. "with NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  222. return NtStatus;
  223. }
  224. BOOL
  225. MRxDAVPrecompleteUserModeFobxFinalizeRequest(
  226. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  227. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  228. ULONG WorkItemLength,
  229. BOOL OperationCancelled
  230. )
  231. /*++
  232. Routine Description:
  233. The precompletion routine for the finalize Fobx request.
  234. Arguments:
  235. RxContext - The RDBSS context.
  236. AsyncEngineContext - The reflctor's context.
  237. WorkItem - The work item buffer.
  238. OperationCancelled - TRUE if this operation was cancelled by the user.
  239. Return Value:
  240. TRUE - UMRxAsyncEngineCalldownIrpCompletion is called by the function
  241. UMRxCompleteUserModeRequest after we return.
  242. --*/
  243. {
  244. NTSTATUS NtStatus = STATUS_SUCCESS;
  245. PDAV_USERMODE_WORKITEM WorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  246. PAGED_CODE();
  247. DavDbgTrace(DAV_TRACE_DETAIL,
  248. ("%ld: Entering MRxDAVPrecompleteUserModeFobxFinalizeRequest.\n",
  249. PsGetCurrentThreadId()));
  250. DavDbgTrace(DAV_TRACE_CONTEXT,
  251. ("%ld: MRxDAVPrecompleteUserModeFobxFinalizeRequest: "
  252. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  253. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  254. //
  255. // A FinalizeFobx request can never by Async.
  256. //
  257. ASSERT(AsyncEngineContext->AsyncOperation == FALSE);
  258. //
  259. // If this operation was cancelled, then we don't need to do anything
  260. // special in the CloseSrvOpen case.
  261. //
  262. if (OperationCancelled) {
  263. DavDbgTrace(DAV_TRACE_ERROR,
  264. ("%ld: MRxDAVPrecompleteUserModeFobxFinalizeRequest: Operation Cancelled. "
  265. "AsyncEngineContext = %08lx, RxContext = %08lx.\n",
  266. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  267. }
  268. NtStatus = AsyncEngineContext->Status;
  269. if (NtStatus != STATUS_SUCCESS) {
  270. DavDbgTrace(DAV_TRACE_ERROR,
  271. ("%ld: MRxDAVPrecompleteUserModeFobxFinalizeRequest: "
  272. "Finalize Fobx failed in user mode.\n",
  273. PsGetCurrentThreadId()));
  274. }
  275. DavDbgTrace(DAV_TRACE_DETAIL,
  276. ("%ld: Leaving MRxDAVPrecompleteUserModeFobxFinalizeRequest.\n",
  277. PsGetCurrentThreadId()));
  278. return TRUE;
  279. }
  280. NTSTATUS
  281. MRxDAVCleanupFobx(
  282. IN PRX_CONTEXT RxContext
  283. )
  284. /*++
  285. Routine Description:
  286. This routine cleansup a file system object. Normally a no op.
  287. Arguments:
  288. pRxContext - the RDBSS context
  289. Return Value:
  290. RXSTATUS - The return status for the operation
  291. --*/
  292. {
  293. NTSTATUS Status = STATUS_SUCCESS;
  294. RxCaptureFcb;
  295. NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
  296. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  297. PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen, capFcb);
  298. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  299. PMRX_FCB Fcb = SrvOpen->pFcb;
  300. PWEBDAV_FCB DavFcb = MRxDAVGetFcbExtension(Fcb);
  301. PAGED_CODE();
  302. DavDbgTrace(DAV_TRACE_DETAIL,
  303. ("%ld: Entering MRxDAVCleanupFobx: RemainingName: %wZ\n",
  304. PsGetCurrentThreadId(), RemainingName));
  305. IF_DEBUG {
  306. RxCaptureFobx;
  307. ASSERT (capFobx != NULL);
  308. ASSERT (capFobx->pSrvOpen == RxContext->pRelevantSrvOpen);
  309. }
  310. ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
  311. ASSERT ( NodeTypeIsFcb(capFcb) );
  312. ASSERT (FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT));
  313. //
  314. // Because we only have one handle on the file, we do nothing for each
  315. // individual handle being closed. In this way we avoid doing paging ios.
  316. // We close the handle when the final close for the fcb comes down.
  317. //
  318. return(Status);
  319. }
  320. NTSTATUS
  321. MRxDAVDeallocateForFcb(
  322. IN OUT PMRX_FCB pFcb
  323. )
  324. /*++
  325. Routine Description:
  326. This routine is called when the wrapper is about to deallocate a FCB.
  327. Arguments:
  328. pFcb - the Fcb being deallocated.
  329. Return Value:
  330. RXSTATUS - STATUS_SUCCESS
  331. --*/
  332. {
  333. NTSTATUS NtStatus = STATUS_SUCCESS;
  334. PWEBDAV_FCB DavFcb = (PWEBDAV_FCB)(pFcb->Context);
  335. PWCHAR NtFileName = NULL;
  336. LONG FileWasModified = 0;
  337. PAGED_CODE();
  338. DavDbgTrace(DAV_TRACE_DETAIL,
  339. ("%ld: Entering MRxDAVDeallocateForFcb: FileName: %ws\n",
  340. PsGetCurrentThreadId(), DavFcb->FileName));
  341. //
  342. // If we allocated the FCB resource to synchronize the "read-modify-write"
  343. // sequence, we need to uninitialize and deallocate it now.
  344. //
  345. if (DavFcb->DavReadModifyWriteLock) {
  346. ExDeleteResourceLite(DavFcb->DavReadModifyWriteLock);
  347. RxFreePool(DavFcb->DavReadModifyWriteLock);
  348. DavFcb->DavReadModifyWriteLock = NULL;
  349. }
  350. //
  351. // If the value of DavFcb->FileWasModified is TRUE, it means that some write
  352. // never made it to the server. This is a delayed write failure in WebDav.
  353. // We need to notify this to the user. Hence we log an entry in the EventLog
  354. // and call IoRaiseInformationalHardError to inform the user.
  355. //
  356. FileWasModified = InterlockedCompareExchange(&(DavFcb->FileWasModified), 0, 0);
  357. if (FileWasModified != 0) {
  358. BOOLEAN RaiseHardError = FALSE;
  359. ASSERT(DavFcb->FileNameInfo.Buffer != NULL);
  360. //
  361. // Log that the write failed in the event log.
  362. //
  363. DavLogDelayedWriteError( &(DavFcb->FileNameInfo) );
  364. RaiseHardError = IoRaiseInformationalHardError(STATUS_LOST_WRITEBEHIND_DATA,
  365. &(DavFcb->FileNameInfo),
  366. NULL);
  367. if (!RaiseHardError) {
  368. DavDbgTrace(DAV_TRACE_ERROR,
  369. ("%ld: ERROR: MRxDAVDeallocateForFcb/IoRaiseInformationalHardError",
  370. PsGetCurrentThreadId()));
  371. }
  372. }
  373. //
  374. // If we allocated any memory for the FileNameInfo, we need to free it now.
  375. //
  376. if (DavFcb->FileNameInfo.Buffer) {
  377. ASSERT(DavFcb->FileNameInfoAllocated == TRUE);
  378. RxFreePool(DavFcb->FileNameInfo.Buffer);
  379. DavFcb->FileNameInfo.Buffer = NULL;
  380. DavFcb->FileNameInfo.Length = 0;
  381. DavFcb->FileNameInfo.MaximumLength = 0;
  382. DavFcb->FileNameInfoAllocated = FALSE;
  383. }
  384. //
  385. // Delete the EFS file cache at the end of the Fcb lifetime. If the file is
  386. // opened again, the EFS file cache will be restored from the WinInet cache
  387. // in backup formate. This way, WinInet does not involved in delete the EFS
  388. // file cache which will be denied in the context of LocalService.
  389. //
  390. if (DavFcb->LocalFileIsEncrypted) {
  391. NTSTATUS LocalNtStatus = STATUS_SUCCESS;
  392. OBJECT_ATTRIBUTES ObjectAttributes;
  393. UNICODE_STRING UnicodeFileName;
  394. ULONG SizeInBytes = 0;
  395. SizeInBytes = ( MAX_PATH + wcslen(L"\\??\\") + 1 ) * sizeof(WCHAR);
  396. NtFileName = RxAllocatePoolWithTag(PagedPool, SizeInBytes, DAV_FILENAME_POOLTAG);
  397. if (NtFileName == NULL) {
  398. //
  399. // cannot do much, bailout
  400. //
  401. DavDbgTrace(DAV_TRACE_ERROR,
  402. ("%ld: MRxDAVDeallocateForFcb/RxAllocatePoolWithTag failed", PsGetCurrentThreadId()));
  403. goto EXIT_THE_FUNCTION;
  404. }
  405. RtlZeroMemory(NtFileName, SizeInBytes);
  406. wcscpy( NtFileName, L"\\??\\" );
  407. wcscpy( &(NtFileName[4]), DavFcb->FileName );
  408. DavDbgTrace(DAV_TRACE_DETAIL,
  409. ("%ld: MRxDAVDeallocateForFcb: NtFileName = %ws\n",
  410. PsGetCurrentThreadId(), NtFileName));
  411. RtlInitUnicodeString( &(UnicodeFileName), NtFileName );
  412. InitializeObjectAttributes( &ObjectAttributes,
  413. &UnicodeFileName,
  414. OBJ_CASE_INSENSITIVE,
  415. NULL,
  416. NULL);
  417. LocalNtStatus = ZwDeleteFile( &(ObjectAttributes) );
  418. if (!NT_SUCCESS(LocalNtStatus)) {
  419. DavDbgTrace(DAV_TRACE_ERROR,
  420. ("%ld: ERROR: MRxDAVDeallocateForFcb/ZwDeleteFile"
  421. ". NtStatus = %08lx %ws \n", PsGetCurrentThreadId(), LocalNtStatus,DavFcb->FileName));
  422. }
  423. }
  424. EXIT_THE_FUNCTION:
  425. if (NtFileName) {
  426. RxFreePool(NtFileName);
  427. }
  428. RtlZeroMemory(DavFcb, sizeof(WEBDAV_FCB));
  429. return(NtStatus);
  430. }
  431. VOID
  432. DavLogDelayedWriteError(
  433. PUNICODE_STRING PathName
  434. )
  435. /*++
  436. Routine Description:
  437. This routine logs a delayed write error to the event log.
  438. Arguments:
  439. PathName - The PathName for which the delayed write failed.
  440. Return Value:
  441. RXSTATUS - The return status for the operation
  442. --*/
  443. {
  444. NTSTATUS Status = STATUS_SUCCESS;
  445. USHORT RemainingLength = 0;
  446. UNICODE_STRING ErrorLog[1];
  447. PAGED_CODE();
  448. RemainingLength = ERROR_LOG_MAXIMUM_SIZE;
  449. RemainingLength -= sizeof(IO_ERROR_LOG_PACKET);
  450. RemainingLength -= sizeof(UNICODE_NULL);
  451. //
  452. // If the length of the PathName is less than the RemainingLength, then we
  453. // print the entire path, otherwise we print the max amount allowed. This is
  454. // because the length of the error log message is limited by the
  455. // ERROR_LOG_MAXIMUM_SIZE.
  456. //
  457. if (PathName->Length > RemainingLength) {
  458. ErrorLog[0].Length = RemainingLength;
  459. } else {
  460. ErrorLog[0].Length = PathName->Length;
  461. }
  462. ErrorLog[0].MaximumLength = ErrorLog[0].Length;
  463. ErrorLog[0].Buffer = PathName->Buffer;
  464. RxLogEventWithAnnotation((PRDBSS_DEVICE_OBJECT)MRxDAVDeviceObject,
  465. EVENT_DAV_REDIR_DELAYED_WRITE_FAILED,
  466. STATUS_LOST_WRITEBEHIND_DATA,
  467. NULL,
  468. 0,
  469. ErrorLog,
  470. 1);
  471. return;
  472. }