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.

3595 lines
129 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. openclos.c
  5. Abstract:
  6. This module implements the DAV miniredir call down routines pertaining to
  7. opening/closing of file/directories.
  8. Author:
  9. Balan Sethu Raman [SethuR]
  10. Rohan Kumar [rohank] 15-March-1999
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "webdav.h"
  16. //
  17. // The global list of all the active LOCK tokens (one for every LOCK taken) and
  18. // the resource that is used to synchronize access to it.
  19. //
  20. LIST_ENTRY LockTokenEntryList;
  21. ERESOURCE LockTokenEntryListLock;
  22. //
  23. // The global list of all the LOCK conflict entries and the resource that is
  24. // used to synchronize access to it.
  25. //
  26. LIST_ENTRY LockConflictEntryList;
  27. ERESOURCE LockConflictEntryListLock;
  28. //
  29. // Mentioned below are the prototypes of functions tht are used only within
  30. // this module (file). These functions should not be exposed outside.
  31. //
  32. NTSTATUS
  33. MRxDAVSyncIrpCompletionRoutine(
  34. IN PDEVICE_OBJECT DeviceObject,
  35. IN PIRP CalldownIrp,
  36. IN PVOID Context
  37. );
  38. NTSTATUS
  39. MRxDAVCreateContinuation(
  40. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  41. );
  42. NTSTATUS
  43. MRxDAVCloseSrvOpenContinuation(
  44. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  45. );
  46. NTSTATUS
  47. MRxDAVFormatUserModeCloseRequest(
  48. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  49. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  50. ULONG WorkItemLength,
  51. PULONG_PTR ReturnedLength
  52. );
  53. NTSTATUS
  54. MRxDAVFormatUserModeCreateRequest(
  55. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  56. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  57. ULONG WorkItemLength,
  58. PULONG_PTR ReturnedLength
  59. );
  60. BOOL
  61. MRxDAVPrecompleteUserModeCloseRequest(
  62. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  63. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  64. ULONG WorkItemLength,
  65. BOOL OperationCancelled
  66. );
  67. BOOL
  68. MRxDAVPrecompleteUserModeCreateRequest(
  69. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  70. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  71. ULONG WorkItemLength,
  72. BOOL OperationCancelled
  73. );
  74. #ifdef ALLOC_PRAGMA
  75. #pragma alloc_text(PAGE, MRxDAVSyncXxxInformation)
  76. #pragma alloc_text(PAGE, MRxDAVShouldTryToCollapseThisOpen)
  77. #pragma alloc_text(PAGE, MRxDAVSetLoud)
  78. #pragma alloc_text(PAGE, MRxDAVCreate)
  79. #pragma alloc_text(PAGE, MRxDAVFormatUserModeCreateRequest)
  80. #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeCreateRequest)
  81. #pragma alloc_text(PAGE, MRxDAVCreateContinuation)
  82. #pragma alloc_text(PAGE, MRxDAVCollapseOpen)
  83. #pragma alloc_text(PAGE, MRxDAVComputeNewBufferingState)
  84. #pragma alloc_text(PAGE, MRxDAVTruncate)
  85. #pragma alloc_text(PAGE, MRxDAVForcedClose)
  86. #pragma alloc_text(PAGE, MRxDAVCloseSrvOpen)
  87. #pragma alloc_text(PAGE, MRxDAVFormatUserModeCloseRequest)
  88. #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeCloseRequest)
  89. #pragma alloc_text(PAGE, MRxDAVCloseSrvOpenContinuation)
  90. #endif
  91. //
  92. // The implementation of functions begins here.
  93. //
  94. #define MRXDAV_ENCRYPTED_DIRECTORY_KEY L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\MRxDAV\\EncryptedDirectories"
  95. NTSTATUS
  96. MRxDAVSyncIrpCompletionRoutine(
  97. IN PDEVICE_OBJECT DeviceObject,
  98. IN PIRP CalldownIrp,
  99. IN PVOID Context
  100. )
  101. /*++
  102. Routine Description:
  103. This routine is called when the calldownirp is completed.
  104. Arguments:
  105. DeviceObject
  106. CalldownIrp
  107. Context
  108. Return Value:
  109. RXSTATUS - STATUS_MORE_PROCESSING_REQUIRED
  110. --*/
  111. {
  112. PRX_CONTEXT RxContext = (PRX_CONTEXT)Context;
  113. //
  114. // Since this is an IRP completion rotuine, this cannot be paged code.
  115. //
  116. if (CalldownIrp->PendingReturned){
  117. RxSignalSynchronousWaiter(RxContext);
  118. }
  119. return(STATUS_MORE_PROCESSING_REQUIRED);
  120. }
  121. ULONG_PTR DummyReturnedLengthForXxxInfo;
  122. NTSTATUS
  123. MRxDAVSyncXxxInformation(
  124. IN OUT PRX_CONTEXT RxContext,
  125. IN UCHAR MajorFunction,
  126. IN PFILE_OBJECT FileObject,
  127. IN ULONG InformationClass,
  128. IN ULONG Length,
  129. OUT PVOID Information,
  130. OUT PULONG_PTR ReturnedLength OPTIONAL
  131. )
  132. /*++
  133. Routine Description:
  134. This routine returns the requested information about a specified file
  135. or volume. The information returned is determined by the class that
  136. is specified, and it is placed into the caller's output buffer.
  137. Arguments:
  138. FsInformationClass - Specifies the type of information which should be
  139. returned about the file/volume.
  140. Length - Supplies the length of the buffer in bytes.
  141. FsInformation - Supplies a buffer to receive the requested information
  142. returned about the file. This buffer must not be pageable
  143. and must reside in system space.
  144. ReturnedLength - Supplies a variable that is to receive the length of the
  145. information written to the buffer.
  146. FileInformation - Boolean that indicates whether the information requested
  147. is for a file or a volume.
  148. Return Value:
  149. The status returned is the final completion status of the operation.
  150. --*/
  151. {
  152. NTSTATUS Status;
  153. PIRP irp,TopIrp;
  154. PIO_STACK_LOCATION irpSp;
  155. PDEVICE_OBJECT DeviceObject;
  156. PAGED_CODE();
  157. if (ReturnedLength == NULL) {
  158. ReturnedLength = &(DummyReturnedLengthForXxxInfo);
  159. }
  160. ASSERT (FileObject);
  161. DeviceObject = IoGetRelatedDeviceObject(FileObject);
  162. ASSERT (DeviceObject);
  163. //
  164. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  165. // The allocation is performed with an exception handler in case the
  166. // caller does not have enough quota to allocate the packet.
  167. //
  168. irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
  169. if (!irp) {
  170. return STATUS_INSUFFICIENT_RESOURCES;
  171. }
  172. irp->Tail.Overlay.OriginalFileObject = FileObject;
  173. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  174. irp->RequestorMode = KernelMode;
  175. //
  176. // Get a pointer to the stack location for the first driver. This will be
  177. // used to pass the original function codes and parameters.
  178. //
  179. irpSp = IoGetNextIrpStackLocation(irp);
  180. irpSp->MajorFunction = MajorFunction;
  181. irpSp->FileObject = FileObject;
  182. IoSetCompletionRoutine(irp,
  183. MRxDAVSyncIrpCompletionRoutine,
  184. RxContext,
  185. TRUE,
  186. TRUE,
  187. TRUE);
  188. irp->AssociatedIrp.SystemBuffer = Information;
  189. //
  190. // Copy the caller's parameters to the service-specific portion of the
  191. // IRP.
  192. //
  193. IF_DEBUG {
  194. ASSERT((irpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION)
  195. || (irpSp->MajorFunction == IRP_MJ_SET_INFORMATION)
  196. || (irpSp->MajorFunction == IRP_MJ_QUERY_VOLUME_INFORMATION));
  197. if (irpSp->MajorFunction == IRP_MJ_SET_INFORMATION) {
  198. //IF_LOUD_DOWNCALLS(MiniFileObject) {
  199. // SetFileInfoInfo = ((PFILE_END_OF_FILE_INFORMATION)Information)->EndOfFile.LowPart;
  200. //}
  201. }
  202. ASSERT(&irpSp->Parameters.QueryFile.Length
  203. == &irpSp->Parameters.SetFile.Length);
  204. ASSERT(&irpSp->Parameters.QueryFile.Length
  205. == &irpSp->Parameters.QueryVolume.Length);
  206. ASSERT(&irpSp->Parameters.QueryFile.FileInformationClass
  207. == &irpSp->Parameters.SetFile.FileInformationClass);
  208. ASSERT(&irpSp->Parameters.QueryFile.FileInformationClass
  209. == &irpSp->Parameters.QueryVolume.FsInformationClass);
  210. }
  211. irpSp->Parameters.QueryFile.Length = Length;
  212. irpSp->Parameters.QueryFile.FileInformationClass = InformationClass;
  213. //
  214. // Now simply invoke the driver at its dispatch entry with the IRP.
  215. //
  216. KeInitializeEvent(&RxContext->SyncEvent,
  217. NotificationEvent,
  218. FALSE);
  219. try {
  220. TopIrp = IoGetTopLevelIrp();
  221. //
  222. // Tell the underlying guy he's all clear.
  223. //
  224. IoSetTopLevelIrp(NULL);
  225. Status = IoCallDriver(DeviceObject,irp);
  226. } finally {
  227. //
  228. // Restore my context for unwind.
  229. //
  230. IoSetTopLevelIrp(TopIrp);
  231. }
  232. if (Status == (STATUS_PENDING)) {
  233. RxWaitSync(RxContext);
  234. Status = irp->IoStatus.Status;
  235. }
  236. if (Status == STATUS_SUCCESS) {
  237. *ReturnedLength = irp->IoStatus.Information;
  238. }
  239. IoFreeIrp(irp);
  240. return(Status);
  241. }
  242. NTSTATUS
  243. MRxDAVShouldTryToCollapseThisOpen(
  244. IN PRX_CONTEXT RxContext
  245. )
  246. /*++
  247. Routine Description:
  248. This routine determines if the mini knows of a good reason not
  249. to try collapsing on this open. Presently, the only reason would
  250. be if this were a copychunk open.
  251. Arguments:
  252. RxContext - the RDBSS context
  253. Return Value:
  254. NTSTATUS - The return status for the operation
  255. SUCCESS --> okay to try collapse
  256. other (MORE_PROCESSING_REQUIRED) --> dont collapse
  257. --*/
  258. {
  259. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  260. PAGED_CODE();
  261. //
  262. // We do not collapse any SrvOpen. The idea is to have one SrvOpen per
  263. // create.
  264. //
  265. DavDbgTrace(DAV_TRACE_DETAIL,
  266. ("%ld: Entering MRxDAVShouldTryToCollapseThisOpen!!!!\n",
  267. PsGetCurrentThreadId()));
  268. return Status;
  269. }
  270. ULONG UMRxLoudStringTableSize = 0;
  271. UNICODE_STRING UMRxLoudStrings[50];
  272. VOID
  273. MRxDAVSetLoud(
  274. IN PBYTE Msg,
  275. IN PRX_CONTEXT RxContext,
  276. IN PUNICODE_STRING s
  277. )
  278. {
  279. ULONG i;
  280. UNICODE_STRING temp;
  281. PAGED_CODE();
  282. for (i=0; i < UMRxLoudStringTableSize; i++) {
  283. PUNICODE_STRING t = &(UMRxLoudStrings[i]);
  284. ((PBYTE)temp.Buffer) = ((PBYTE)s->Buffer) + s->Length - t->Length;
  285. temp.Length = t->Length;
  286. if (RtlEqualUnicodeString(&temp, t, TRUE)) {
  287. DavDbgTrace(DAV_TRACE_DETAIL,
  288. ("%ld: MRxDAVSetLoud: %s Found %wZ from %wZ.\n",
  289. PsGetCurrentThreadId(), Msg, t, s));
  290. RxContext->LoudCompletionString = t;
  291. break;
  292. }
  293. }
  294. }
  295. NTSTATUS
  296. MRxDAVCreate(
  297. IN PRX_CONTEXT RxContext
  298. )
  299. /*++
  300. Routine Description:
  301. This routine handles create request for the DAV mini-redir.
  302. Arguments:
  303. RxContext - The RDBSS context.
  304. Return Value:
  305. RXSTATUS - The return status for the operation.
  306. --*/
  307. {
  308. NTSTATUS NtStatus = STATUS_SUCCESS;
  309. PAGED_CODE();
  310. DavDbgTrace(DAV_TRACE_DETAIL,
  311. ("%ld: Entering MRxDAVCreate!!!!\n", PsGetCurrentThreadId()));
  312. DavDbgTrace(DAV_TRACE_CONTEXT,
  313. ("%ld: MRxDAVCreate: RxContext: %08lx\n",
  314. PsGetCurrentThreadId(), RxContext));
  315. NtStatus = UMRxAsyncEngOuterWrapper(RxContext,
  316. SIZEOF_DAV_SPECIFIC_CONTEXT,
  317. MRxDAVFormatTheDAVContext,
  318. DAV_MINIRDR_ENTRY_FROM_CREATE,
  319. MRxDAVCreateContinuation,
  320. "MRxDAVCreate");
  321. DavDbgTrace(DAV_TRACE_DETAIL,
  322. ("%ld: Leaving MRxDAVCreate with NtStatus = %08lx\n",
  323. PsGetCurrentThreadId(), NtStatus));
  324. return(NtStatus);
  325. }
  326. NTSTATUS
  327. MRxDAVFormatUserModeCreateRequest(
  328. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  329. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  330. ULONG WorkItemLength,
  331. PULONG_PTR ReturnedLength
  332. )
  333. /*++
  334. Routine Description:
  335. This routine formats the arguments of the create request which is being
  336. sent to the user mode for processing.
  337. Arguments:
  338. RxContext - The RDBSS context.
  339. AsyncEngineContext - The reflctor's context.
  340. WorkItem - The work item buffer.
  341. WorkItemLength - The length of the work item buffer.
  342. ReturnedLength -
  343. Return Value:
  344. STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES.
  345. --*/
  346. {
  347. NTSTATUS NtStatus = STATUS_SUCCESS;
  348. PDAV_USERMODE_WORKITEM WorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  349. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  350. PMRX_FCB Fcb = SrvOpen->pFcb;
  351. PWEBDAV_FCB DavFcb = MRxDAVGetFcbExtension(Fcb);
  352. PWEBDAV_CONTEXT DavContext = (PWEBDAV_CONTEXT)AsyncEngineContext;
  353. PNT_CREATE_PARAMETERS CreateParameters;
  354. PDAV_USERMODE_CREATE_REQUEST CreateRequest = &(WorkItem->CreateRequest);
  355. PDAV_USERMODE_CREATE_RESPONSE CreateResponse = &(WorkItem->CreateResponse);
  356. PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
  357. PWEBDAV_SRV_CALL DavSrvCall = NULL;
  358. PSECURITY_CLIENT_CONTEXT SecurityClientContext = NULL;
  359. PBYTE SecondaryBuff = NULL;
  360. PWCHAR NetRootName = NULL, AlreadyPrefixedName = NULL;
  361. DWORD PathLen = 0, PathLenInBytes = 0, SdLength = 0;
  362. BOOL didIAllocateFileNameInfo = FALSE;
  363. PAGED_CODE();
  364. DavDbgTrace(DAV_TRACE_DETAIL,
  365. ("%ld: Entering MRxDAVFormatUserModeCreateRequest!!!!\n",
  366. PsGetCurrentThreadId()));
  367. DavDbgTrace(DAV_TRACE_CONTEXT,
  368. ("%ld: MRxDAVFormatUserModeCreateRequest: AsyncEngineContext = "
  369. "%08lx, RxContext = %08lx.\n", PsGetCurrentThreadId(),
  370. AsyncEngineContext, RxContext));
  371. CreateParameters = &(RxContext->Create.NtCreateParameters);
  372. //
  373. // Set the SecurityClientContext which is used in impersonating.
  374. //
  375. MRxDAVGetSecurityClientContext();
  376. //
  377. // Copy the LogonID in the CreateRequest buffer. The LogonId is in the
  378. // MiniRedir's portion of the V_NET_ROOT.
  379. //
  380. CreateRequest->LogonID.LowPart = DavVNetRoot->LogonID.LowPart;
  381. CreateRequest->LogonID.HighPart = DavVNetRoot->LogonID.HighPart;
  382. DavDbgTrace(DAV_TRACE_DETAIL,
  383. ("%ld: MRxDAVFormatUserModeCreateRequest: LogonID.LowPart = %08lx\n",
  384. PsGetCurrentThreadId(), DavVNetRoot->LogonID.LowPart));
  385. DavDbgTrace(DAV_TRACE_DETAIL,
  386. ("%ld: MRxDAVFormatUserModeCreateRequest: LogonID.HighPart = %08lx\n",
  387. PsGetCurrentThreadId(), DavVNetRoot->LogonID.HighPart));
  388. //
  389. // Impersonate the client who initiated the request. If we fail to
  390. // impersonate, tough luck.
  391. //
  392. if (SecurityClientContext != NULL) {
  393. NtStatus = UMRxImpersonateClient(SecurityClientContext, WorkItemHeader);
  394. if (!NT_SUCCESS(NtStatus)) {
  395. DavDbgTrace(DAV_TRACE_ERROR,
  396. ("%ld: ERROR: MRxDAVFormatUserModeCreateRequest/"
  397. "UMRxImpersonateClient. NtStatus = %08lx.\n",
  398. PsGetCurrentThreadId(), NtStatus));
  399. goto EXIT_THE_FUNCTION;
  400. }
  401. } else {
  402. NtStatus = STATUS_INVALID_PARAMETER;
  403. DavDbgTrace(DAV_TRACE_ERROR,
  404. ("%ld: ERROR: MRxDAVFormatUserModeCreateRequest: "
  405. "SecurityClientContext is NULL.\n",
  406. PsGetCurrentThreadId()));
  407. goto EXIT_THE_FUNCTION;
  408. }
  409. NetRootName = SrvOpen->pVNetRoot->pNetRoot->pNetRootName->Buffer;
  410. AlreadyPrefixedName = SrvOpen->pAlreadyPrefixedName->Buffer;
  411. //
  412. // Allocate memory for the complete path name and copy it.
  413. // The CompletePathName = NetRootName + AlreadyPrefixedName. The extra two
  414. // bytes are for '\0' at the end.
  415. //
  416. PathLen = SrvOpen->pVNetRoot->pNetRoot->pNetRootName->Length;
  417. PathLen += SrvOpen->pAlreadyPrefixedName->Length;
  418. PathLen += sizeof(WCHAR);
  419. PathLenInBytes = PathLen;
  420. SecondaryBuff = UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  421. PathLenInBytes);
  422. if (SecondaryBuff == NULL) {
  423. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  424. DavDbgTrace(DAV_TRACE_ERROR,
  425. ("ld: MRxDAVFormatUserModeCreateRequest/"
  426. "UMRxAllocateSecondaryBuffer: ERROR: NtStatus = %08lx.\n",
  427. PsGetCurrentThreadId(), NtStatus));
  428. goto EXIT_THE_FUNCTION;
  429. }
  430. CreateRequest->CompletePathName = (PWCHAR)SecondaryBuff;
  431. RtlZeroMemory(CreateRequest->CompletePathName, PathLenInBytes);
  432. //
  433. // Copy the NetRootName.
  434. //
  435. RtlCopyMemory(SecondaryBuff,
  436. NetRootName,
  437. SrvOpen->pVNetRoot->pNetRoot->pNetRootName->Length);
  438. //
  439. // Copy the AlreadyPrefixedName after the NetRootName to make the complete
  440. // path name.
  441. //
  442. RtlCopyMemory(SecondaryBuff + SrvOpen->pVNetRoot->pNetRoot->pNetRootName->Length,
  443. AlreadyPrefixedName,
  444. SrvOpen->pAlreadyPrefixedName->Length);
  445. DavDbgTrace(DAV_TRACE_DETAIL,
  446. ("%ld: MRxDAVFormatUserModeCreateRequest: CPN = %ws.\n",
  447. PsGetCurrentThreadId(), CreateRequest->CompletePathName));
  448. //
  449. // If this is the first create, then we need to allocate the FileNameInfo
  450. // in the FCB. This is used in logging the delayed write failure.
  451. //
  452. if (DavFcb->FileNameInfoAllocated != TRUE) {
  453. DavFcb->FileNameInfo.Buffer = RxAllocatePoolWithTag(PagedPool,
  454. PathLenInBytes,
  455. DAV_FILEINFO_POOLTAG);
  456. if (DavFcb->FileNameInfo.Buffer == NULL) {
  457. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  458. DavDbgTrace(DAV_TRACE_ERROR,
  459. ("ld: ERROR: MRxDAVFormatUserModeCreateRequest/"
  460. "RxAllocatePoolWithTag: NtStatus = %08lx\n",
  461. PsGetCurrentThreadId(), NtStatus));
  462. goto EXIT_THE_FUNCTION;
  463. }
  464. RtlZeroMemory(DavFcb->FileNameInfo.Buffer, PathLenInBytes);
  465. RtlCopyMemory(DavFcb->FileNameInfo.Buffer,
  466. CreateRequest->CompletePathName,
  467. PathLenInBytes);
  468. DavFcb->FileNameInfo.Length = (USHORT)PathLenInBytes - sizeof(WCHAR);
  469. DavFcb->FileNameInfo.MaximumLength = (USHORT)PathLenInBytes;
  470. DavFcb->FileNameInfoAllocated = TRUE;
  471. didIAllocateFileNameInfo = TRUE;
  472. DavDbgTrace(DAV_TRACE_DETAIL,
  473. ("%ld: MRxDAVFormatUserModeCreateRequest: FileNameInfo = %wZ\n",
  474. PsGetCurrentThreadId(), &(DavFcb->FileNameInfo)));
  475. }
  476. WorkItem->WorkItemType = UserModeCreate;
  477. //
  478. // Set the ServerID that was got during the CreateSrvCall operation.
  479. //
  480. ASSERT(RxContext->pRelevantSrvOpen->pVNetRoot->pNetRoot->pSrvCall->Context);
  481. DavSrvCall = (PWEBDAV_SRV_CALL)RxContext->pRelevantSrvOpen->pVNetRoot->
  482. pNetRoot->pSrvCall->Context;
  483. CreateRequest->ServerID = DavSrvCall->ServerID;
  484. DavDbgTrace(DAV_TRACE_DETAIL,
  485. ("%ld: MRxDAVFormatUserModeCreateRequest: ServerID = %d.\n",
  486. PsGetCurrentThreadId(), CreateRequest->ServerID));
  487. CreateRequest->AllocationSize = CreateParameters->AllocationSize;
  488. CreateRequest->FileAttributes = CreateParameters->FileAttributes;
  489. CreateRequest->ShareAccess = CreateParameters->ShareAccess;
  490. CreateRequest->CreateDisposition = CreateParameters->Disposition;
  491. CreateRequest->EaBuffer = RxContext->Create.EaBuffer;
  492. CreateRequest->EaLength = RxContext->Create.EaLength;
  493. SdLength = CreateRequest->SdLength = RxContext->Create.SdLength;
  494. CreateRequest->ImpersonationLevel = CreateParameters->ImpersonationLevel;
  495. CreateRequest->SecurityFlags = 0;
  496. if (CreateParameters->SecurityContext != NULL) {
  497. if (CreateParameters->SecurityContext->SecurityQos != NULL) {
  498. if (CreateParameters->SecurityContext->
  499. SecurityQos->ContextTrackingMode == SECURITY_DYNAMIC_TRACKING) {
  500. CreateRequest->SecurityFlags |= DAV_SECURITY_DYNAMIC_TRACKING;
  501. }
  502. if (CreateParameters->SecurityContext->SecurityQos->EffectiveOnly) {
  503. CreateRequest->SecurityFlags |= DAV_SECURITY_EFFECTIVE_ONLY;
  504. }
  505. }
  506. }
  507. CreateRequest->DesiredAccess = CreateParameters->DesiredAccess;
  508. CreateRequest->CreateOptions = CreateParameters->CreateOptions;
  509. if (AsyncEngineContext->FileInformationCached) {
  510. CreateRequest->FileInformationCached = TRUE;
  511. CreateResponse->BasicInformation = DavContext->CreateReturnedFileInfo->BasicInformation;
  512. CreateResponse->StandardInformation = DavContext->CreateReturnedFileInfo->StandardInformation;
  513. DavDbgTrace(DAV_TRACE_DETAIL,
  514. ("MRxDAVFormatUserModeCreateRequest file info cached %x %x %x %x %ws\n",
  515. CreateResponse->BasicInformation.FileAttributes,
  516. CreateResponse->BasicInformation.CreationTime.HighPart,
  517. CreateResponse->BasicInformation.CreationTime.LowPart,
  518. CreateResponse->StandardInformation.EndOfFile.LowPart,
  519. CreateRequest->CompletePathName));
  520. }
  521. CreateRequest->ParentDirInfomationCached = AsyncEngineContext->ParentDirInfomationCached;
  522. CreateRequest->ParentDirIsEncrypted = AsyncEngineContext->ParentDirIsEncrypted;
  523. if (AsyncEngineContext->FileNotExists) {
  524. CreateRequest->FileNotExists = TRUE;
  525. }
  526. EXIT_THE_FUNCTION:
  527. DavDbgTrace(DAV_TRACE_DETAIL,
  528. ("%ld: Leaving MRxDAVFormatUserModeCreateRequest with NtStatus"
  529. " = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  530. if (NtStatus != STATUS_SUCCESS) {
  531. if (CreateRequest->CompletePathName != NULL) {
  532. UMRxFreeSecondaryBuffer(AsyncEngineContext,
  533. (PBYTE)CreateRequest->CompletePathName);
  534. CreateRequest->CompletePathName = NULL;
  535. }
  536. //
  537. // Free the FileNameInfo buffer only if it was allocated in this call.
  538. //
  539. if (DavFcb->FileNameInfo.Buffer != NULL && didIAllocateFileNameInfo) {
  540. RxFreePool(DavFcb->FileNameInfo.Buffer);
  541. DavFcb->FileNameInfo.Buffer = NULL;
  542. DavFcb->FileNameInfo.Length = 0;
  543. DavFcb->FileNameInfo.MaximumLength = 0;
  544. DavFcb->FileNameInfoAllocated = FALSE;
  545. }
  546. }
  547. return(NtStatus);
  548. }
  549. BOOL
  550. MRxDAVPrecompleteUserModeCreateRequest(
  551. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  552. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  553. ULONG WorkItemLength,
  554. BOOL OperationCancelled
  555. )
  556. /*++
  557. Routine Description:
  558. Arguments:
  559. RxContext - The RDBSS context.
  560. AsyncEngineContext - The reflctor's context.
  561. WorkItem - The work item buffer.
  562. WorkItemLength - The length of the work item buffer.
  563. OperationCancelled - TRUE if this operation was cancelled by the user.
  564. Return Value:
  565. TRUE - UMRxAsyncEngineCalldownIrpCompletion is called by the function
  566. UMRxCompleteUserModeRequest after we return.
  567. --*/
  568. {
  569. NTSTATUS NtStatus = STATUS_SUCCESS;
  570. PDAV_USERMODE_WORKITEM WorkItem = NULL;
  571. PWEBDAV_CONTEXT DavContext = NULL;
  572. RxCaptureFcb;
  573. PMRX_SRV_OPEN SrvOpen = NULL;
  574. PWEBDAV_SRV_OPEN davSrvOpen = NULL;
  575. PMRX_FCB Fcb = NULL;
  576. PWEBDAV_FCB DavFcb = NULL;
  577. PDAV_USERMODE_CREATE_RESPONSE CreateResponse = NULL;
  578. PDAV_USERMODE_CREATE_REQUEST CreateRequest = NULL;
  579. HANDLE OpenHandle;
  580. PSECURITY_CLIENT_CONTEXT SecurityClientContext = NULL;
  581. PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
  582. PMRX_SRV_CALL SrvCall = NULL;
  583. PMRX_NET_ROOT NetRoot = NULL;
  584. PWEBDAV_SRV_CALL DavSrvCall = NULL;
  585. PAGED_CODE();
  586. DavDbgTrace(DAV_TRACE_DETAIL,
  587. ("%ld: Entering MRxDAVPrecompleteUserModeCreateRequest!!!!\n",
  588. PsGetCurrentThreadId()));
  589. DavDbgTrace(DAV_TRACE_CONTEXT,
  590. ("%ld: MRxDAVPrecompleteUserModeCreateRequest: "
  591. "AsyncEngineContext = %08lx, RxContext = %08lx.\n",
  592. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  593. //
  594. // A Create operation can never be Async.
  595. //
  596. ASSERT(AsyncEngineContext->AsyncOperation == FALSE);
  597. WorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  598. DavContext = (PWEBDAV_CONTEXT)AsyncEngineContext;
  599. CreateResponse = &(WorkItem->CreateResponse);
  600. CreateRequest = &(WorkItem->CreateRequest);
  601. //
  602. // If the operation is cancelled, then there is no guarantee that the FCB,
  603. // FOBX etc are still valid. All that we need to do is cleanup and bail.
  604. //
  605. if (!OperationCancelled) {
  606. SrvOpen = RxContext->pRelevantSrvOpen;
  607. davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  608. Fcb = SrvOpen->pFcb;
  609. DavFcb = MRxDAVGetFcbExtension(Fcb);
  610. DavVNetRoot = (PWEBDAV_V_NET_ROOT)RxContext->pRelevantSrvOpen->pVNetRoot->Context;
  611. SrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;
  612. DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall);
  613. NetRoot = SrvOpen->pFcb->pNetRoot;
  614. }
  615. NtStatus = AsyncEngineContext->Status;
  616. //
  617. // We need to free up the heap we allocated in the format routine.
  618. //
  619. if (CreateRequest->CompletePathName != NULL) {
  620. if (NtStatus != STATUS_SUCCESS) {
  621. DavDbgTrace(DAV_TRACE_DETAIL,
  622. ("%ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest:"
  623. "Open failed for file \"%ws\" with NtStatus = %08lx.\n",
  624. PsGetCurrentThreadId(), CreateRequest->CompletePathName,
  625. NtStatus));
  626. }
  627. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  628. (PBYTE)CreateRequest->CompletePathName);
  629. if (NtStatus != STATUS_SUCCESS) {
  630. DavDbgTrace(DAV_TRACE_ERROR,
  631. ("%ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest/"
  632. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  633. PsGetCurrentThreadId(), NtStatus));
  634. }
  635. }
  636. //
  637. // If the operation has been cancelled and we created a handle in the
  638. // usermode then we need to set callWorkItemCleanup to TRUE which will
  639. // land up closing this handle. In any case, if the operation has been
  640. // cancelled, we can leave right away.
  641. //
  642. if (OperationCancelled) {
  643. DavDbgTrace(DAV_TRACE_ERROR,
  644. ("%ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest: "
  645. "Operation Cancelled.\n", PsGetCurrentThreadId()));
  646. if (CreateResponse->Handle) {
  647. DavDbgTrace(DAV_TRACE_DETAIL,
  648. ("%ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest: "
  649. "callWorkItemCleanup\n", PsGetCurrentThreadId()));
  650. WorkItem->callWorkItemCleanup = TRUE;
  651. }
  652. goto EXIT_THE_FUNCTION;
  653. }
  654. //
  655. // Open didn't work. We can bail out now.
  656. //
  657. if (AsyncEngineContext->Status != STATUS_SUCCESS) {
  658. //
  659. // If the file was already locked on the server then we need to create
  660. // a LockConflictEntry and add it to the list. The apps can then use
  661. // the FileName to query who has locked this file.
  662. //
  663. if (CreateResponse->FileWasAlreadyLocked) {
  664. ULONG PathLengthInBytes = 0, OwnerLengthInBytes = 0;
  665. PWEBDAV_LOCK_CONFLICT_ENTRY LockConflictEntry;
  666. PBYTE TempBuffer = NULL;
  667. LockConflictEntry = RxAllocatePoolWithTag(PagedPool,
  668. sizeof(WEBDAV_LOCK_CONFLICT_ENTRY),
  669. DAV_LOCKCONFLICTENTRY_POOLTAG);
  670. if (LockConflictEntry == NULL) {
  671. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  672. DavDbgTrace(DAV_TRACE_ERROR,
  673. ("ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest/"
  674. "RxAllocatePoolWithTag: NtStatus = %08lx\n",
  675. PsGetCurrentThreadId(), NtStatus));
  676. goto EXIT_THE_FUNCTION;
  677. }
  678. RtlZeroMemory(LockConflictEntry, sizeof(WEBDAV_LOCK_CONFLICT_ENTRY));
  679. //
  680. // Set the current system time as the creation time of the entry.
  681. //
  682. KeQueryTickCount( &(LockConflictEntry->CreationTimeInTickCount) );
  683. //
  684. // Allocate memory for the complete path name and copy it.
  685. //
  686. PathLengthInBytes = SrvOpen->pVNetRoot->pNetRoot->pNetRootName->Length;
  687. PathLengthInBytes += SrvOpen->pAlreadyPrefixedName->Length;
  688. PathLengthInBytes += sizeof(WCHAR);
  689. TempBuffer = RxAllocatePoolWithTag(PagedPool,
  690. PathLengthInBytes,
  691. DAV_LOCKCONFLICTENTRY_POOLTAG);
  692. if (TempBuffer == NULL) {
  693. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  694. DavDbgTrace(DAV_TRACE_ERROR,
  695. ("ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest/"
  696. "RxAllocatePoolWithTag: NtStatus = %08lx\n",
  697. PsGetCurrentThreadId(), NtStatus));
  698. goto EXIT_THE_FUNCTION;
  699. }
  700. LockConflictEntry->CompletePathName = (PWCHAR)TempBuffer;
  701. RtlZeroMemory(TempBuffer, PathLengthInBytes);
  702. //
  703. // Copy the NetRootName. It includes the server name and the share
  704. // name.
  705. //
  706. RtlCopyMemory(TempBuffer,
  707. SrvOpen->pVNetRoot->pNetRoot->pNetRootName->Buffer,
  708. SrvOpen->pVNetRoot->pNetRoot->pNetRootName->Length);
  709. //
  710. // Copy the AlreadyPrefixedName after the NetRootName to make the
  711. // complete path name.
  712. //
  713. RtlCopyMemory((TempBuffer + SrvOpen->pVNetRoot->pNetRoot->pNetRootName->Length),
  714. SrvOpen->pAlreadyPrefixedName->Buffer,
  715. SrvOpen->pAlreadyPrefixedName->Length);
  716. //
  717. // Allocate memory for the OwnerName and copy it.
  718. //
  719. OwnerLengthInBytes = (1 + wcslen(CreateResponse->LockOwner)) * sizeof(WCHAR);
  720. LockConflictEntry->LockOwner = RxAllocatePoolWithTag(PagedPool,
  721. OwnerLengthInBytes,
  722. DAV_LOCKCONFLICTENTRY_POOLTAG);
  723. if (LockConflictEntry->LockOwner == NULL) {
  724. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  725. DavDbgTrace(DAV_TRACE_ERROR,
  726. ("ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest/"
  727. "RxAllocatePoolWithTag: NtStatus = %08lx\n",
  728. PsGetCurrentThreadId(), NtStatus));
  729. goto EXIT_THE_FUNCTION;
  730. }
  731. RtlZeroMemory(LockConflictEntry->LockOwner, OwnerLengthInBytes);
  732. RtlCopyMemory(LockConflictEntry->LockOwner,
  733. CreateResponse->LockOwner,
  734. OwnerLengthInBytes);
  735. //
  736. // Add the newly created entry to the global LockConflictEntryList.
  737. //
  738. ExAcquireResourceExclusiveLite(&(LockConflictEntryListLock), TRUE);
  739. InsertHeadList(&(LockConflictEntryList), &(LockConflictEntry->listEntry));
  740. ExReleaseResourceLite(&(LockConflictEntryListLock));
  741. }
  742. goto EXIT_THE_FUNCTION;
  743. }
  744. //
  745. // We need to do the "handle to fileobject" association only if its a file.
  746. // If the create was for a directory, no handle would have been created in
  747. // the user mode.
  748. //
  749. if (!CreateResponse->StandardInformation.Directory) {
  750. OpenHandle = CreateResponse->Handle;
  751. DavDbgTrace(DAV_TRACE_DETAIL,
  752. ("%ld: MRxDAVPrecompleteUserModeCreateRequest: "
  753. "OpenHandle = %08lx.\n", PsGetCurrentThreadId(),
  754. OpenHandle));
  755. DavFcb->isDirectory = FALSE;
  756. if ( (OpenHandle != NULL) ) {
  757. NtStatus = ObReferenceObjectByHandle(OpenHandle,
  758. 0L,
  759. NULL,
  760. KernelMode,
  761. (PVOID *)&(davSrvOpen->UnderlyingFileObject),
  762. NULL);
  763. if (NtStatus == STATUS_SUCCESS) {
  764. DavDbgTrace(DAV_TRACE_DETAIL,
  765. ("%ld: MRxDAVPrecompleteUserModeCreateRequest: UFO(1) = %08lx\n",
  766. PsGetCurrentThreadId(), davSrvOpen->UnderlyingFileObject));
  767. davSrvOpen->UnderlyingHandle = OpenHandle;
  768. davSrvOpen->UserModeKey = CreateResponse->UserModeKey;
  769. davSrvOpen->UnderlyingDeviceObject = IoGetRelatedDeviceObject(davSrvOpen->UnderlyingFileObject);
  770. //
  771. // Copy the local file name into the FCB.
  772. //
  773. wcscpy(DavFcb->FileName, CreateResponse->FileName);
  774. wcscpy(DavFcb->Url, CreateResponse->Url);
  775. DavFcb->LocalFileIsEncrypted = CreateResponse->LocalFileIsEncrypted;
  776. MRxDAVGetSecurityClientContext();
  777. ASSERT(SecurityClientContext != NULL);
  778. RtlCopyMemory(&(DavFcb->SecurityClientContext),
  779. SecurityClientContext,
  780. sizeof(SECURITY_CLIENT_CONTEXT));
  781. DavDbgTrace(DAV_TRACE_DETAIL,
  782. ("%ld: MRxDAVPrecompleteUserModeCreateRequest: "
  783. "LocalFileName = %ws.\n", PsGetCurrentThreadId(),
  784. DavFcb->FileName));
  785. //
  786. // We only get/create the file/dir on the first open. On
  787. // subsequent opens, we do the create in the kernel itself since
  788. // the file exists in the WinInet cache. This caching is used
  789. // till the FCB for the file exists.
  790. //
  791. DavFcb->isFileCached = TRUE;
  792. } else {
  793. DavDbgTrace(DAV_TRACE_ERROR,
  794. ("%ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest/"
  795. "ObReferenceObjectByHandle: NtStatus = %08lx.\n",
  796. PsGetCurrentThreadId(), NtStatus));
  797. //
  798. // If we have a valid handle, then why should
  799. // ObReferenceObjectByHandle fail?
  800. //
  801. DbgBreakPoint();
  802. ZwClose(OpenHandle);
  803. goto EXIT_THE_FUNCTION;
  804. }
  805. //
  806. // If "FILE_DELETE_ON_CLOSE" flag was specified as one of
  807. // the CreateOptions, then we need to remember this and
  808. // delete this file on close.
  809. //
  810. if (CreateResponse->DeleteOnClose) {
  811. DavFcb->DeleteOnClose = TRUE;
  812. }
  813. //
  814. // If a new file has been created then we need to set the attributes
  815. // of this new file on close on the server.
  816. //
  817. if (CreateResponse->NewFileCreatedAndSetAttributes) {
  818. DavFcb->fFileAttributesChanged = TRUE;
  819. }
  820. //
  821. // This file exists on the server, but this create operation
  822. // has FILE_OVERWRITE_IF as its CreateDisposition. So, we
  823. // can create this file locally overwrite the one on the
  824. // server on close. We set DoNotTakeTheCurrentTimeAsLMT to
  825. // TRUE since the LMT has been just set on Create and we do
  826. // not need to set it to the current time on close.
  827. //
  828. if (CreateResponse->ExistsAndOverWriteIf) {
  829. InterlockedExchange(&(DavFcb->FileWasModified), 1);
  830. DavFcb->DoNotTakeTheCurrentTimeAsLMT = TRUE;
  831. }
  832. //
  833. // If a new file or directory is created, we need to PROPPATCH the
  834. // time values on close. This is because we use the time values from
  835. // the client when the name cache entry is created for this new
  836. // file. The same time value needs to be on the server.
  837. //
  838. if (CreateResponse->PropPatchTheTimeValues) {
  839. DavFcb->fCreationTimeChanged = TRUE;
  840. DavFcb->fLastAccessTimeChanged = TRUE;
  841. DavFcb->fLastModifiedTimeChanged = TRUE;
  842. }
  843. } else {
  844. //
  845. // We don't have an OpenHandle for a file. This should only happen
  846. // in case where the open is for read/setting sttributes of a file
  847. // or deleting/renaming a file.
  848. //
  849. if (!CreateResponse->fPsuedoOpen) {
  850. DavDbgTrace(DAV_TRACE_ERROR,
  851. ("%ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest: No OpenHandle\n"));
  852. DbgBreakPoint();
  853. }
  854. //
  855. // If "FILE_DELETE_ON_CLOSE" flag was specified as one of
  856. // the CreateOptions, then we need to remember this and
  857. // delete this file on close.
  858. //
  859. if (CreateResponse->DeleteOnClose) {
  860. DavFcb->DeleteOnClose = TRUE;
  861. }
  862. }
  863. //
  864. // If the LOCK was taken on this Create, we need to do the following.
  865. // 1. Add the OpaqueLockToken to the davSrvOpen.
  866. // 2. Create a LockTokenEntry and add it to the list which will be
  867. // used to refresh the LOCKs on the server.
  868. //
  869. if (CreateResponse->LockWasTakenOnThisCreate) {
  870. PWEBDAV_LOCK_TOKEN_ENTRY LockTokenEntry = NULL;
  871. PBYTE TempBuffer = NULL, PathName = NULL;
  872. ULONG LockTokenLengthInBytes = 0, ServerNameLengthInBytes = 0;
  873. ULONG NetRootNameLengthInBytes = 0, PathNameLengthInBytes = 0;
  874. PWCHAR NetRootName = NULL;
  875. //
  876. // We will be sending the OpaqueLockToken in the following format.
  877. // If: (<opaquelocktoken:sdfsdfdsfgsdgdsfgd>)
  878. // So, we store the token in the same format.
  879. //
  880. LockTokenLengthInBytes = (1 + wcslen(CreateResponse->OpaqueLockToken)) * sizeof(WCHAR);
  881. LockTokenLengthInBytes += (wcslen(L"If: (<>)") * sizeof(WCHAR));
  882. TempBuffer = RxAllocatePoolWithTag(PagedPool,
  883. LockTokenLengthInBytes,
  884. DAV_SRVOPEN_POOLTAG);
  885. if (TempBuffer == NULL) {
  886. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  887. DavDbgTrace(DAV_TRACE_ERROR,
  888. ("ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest/"
  889. "RxAllocatePoolWithTag: NtStatus = %08lx\n",
  890. PsGetCurrentThreadId(), NtStatus));
  891. goto EXIT_THE_FUNCTION;
  892. }
  893. davSrvOpen->OpaqueLockToken = (PWCHAR)TempBuffer;
  894. RtlZeroMemory(TempBuffer, LockTokenLengthInBytes);
  895. RtlCopyMemory(TempBuffer,
  896. L"If: (<",
  897. wcslen(L"If: (<") * sizeof(WCHAR));
  898. RtlCopyMemory(TempBuffer + (wcslen(L"If: (<") * sizeof(WCHAR)),
  899. CreateResponse->OpaqueLockToken,
  900. wcslen(CreateResponse->OpaqueLockToken) * sizeof(WCHAR));
  901. RtlCopyMemory(TempBuffer + (wcslen(L"If: (<") * sizeof(WCHAR)) + (wcslen(CreateResponse->OpaqueLockToken) * sizeof(WCHAR)),
  902. L">)",
  903. wcslen(L">)") * sizeof(WCHAR));
  904. DavDbgTrace(DAV_TRACE_DETAIL,
  905. ("ld: MRxDAVPrecompleteUserModeCreateRequest. "
  906. "OpaqueLockToken: %ws\n",
  907. PsGetCurrentThreadId(), davSrvOpen->OpaqueLockToken));
  908. LockTokenEntry = RxAllocatePoolWithTag(PagedPool,
  909. sizeof(WEBDAV_LOCK_TOKEN_ENTRY),
  910. DAV_LOCKTOKENENTRY_POOLTAG);
  911. if (LockTokenEntry == NULL) {
  912. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  913. DavDbgTrace(DAV_TRACE_ERROR,
  914. ("ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest/"
  915. "RxAllocatePoolWithTag: NtStatus = %08lx\n",
  916. PsGetCurrentThreadId(), NtStatus));
  917. goto EXIT_THE_FUNCTION;
  918. }
  919. RtlZeroMemory(LockTokenEntry, sizeof(WEBDAV_LOCK_TOKEN_ENTRY));
  920. //
  921. // Set the current system time as the creation time of the entry.
  922. //
  923. KeQueryTickCount( &(LockTokenEntry->CreationTimeInTickCount) );
  924. //
  925. // The OpaqueLockToken will be included in the request that is
  926. // sent to the server.
  927. //
  928. LockTokenEntry->OpaqueLockToken = davSrvOpen->OpaqueLockToken;
  929. //
  930. // The SecurityClientContext will be used to impersonate this
  931. // client while refreshing the LOCK request.
  932. //
  933. LockTokenEntry->SecurityClientContext = &(DavVNetRoot->SecurityClientContext);
  934. //
  935. // Set the timeout value of the LOCK. This will be used to determine
  936. // when to send the refresh requests out.
  937. //
  938. LockTokenEntry->LockTimeOutValueInSec = CreateResponse->LockTimeout;
  939. LockTokenEntry->LogonID.LowPart = DavVNetRoot->LogonID.LowPart;
  940. LockTokenEntry->LogonID.HighPart = DavVNetRoot->LogonID.HighPart;
  941. LockTokenEntry->ServerID = DavSrvCall->ServerID;
  942. LockTokenEntry->ShouldThisEntryBeRefreshed = TRUE;
  943. //
  944. // Allocate memory for the ServerName and copy it.
  945. //
  946. ServerNameLengthInBytes = SrvCall->pSrvCallName->Length + sizeof(WCHAR);
  947. LockTokenEntry->ServerName = RxAllocatePoolWithTag(PagedPool,
  948. ServerNameLengthInBytes,
  949. DAV_LOCKTOKENENTRY_POOLTAG);
  950. if (LockTokenEntry->ServerName == NULL) {
  951. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  952. DavDbgTrace(DAV_TRACE_ERROR,
  953. ("ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest/"
  954. "RxAllocatePoolWithTag: NtStatus = %08lx\n",
  955. PsGetCurrentThreadId(), NtStatus));
  956. goto EXIT_THE_FUNCTION;
  957. }
  958. RtlZeroMemory(LockTokenEntry->ServerName, ServerNameLengthInBytes);
  959. RtlCopyBytes(LockTokenEntry->ServerName,
  960. SrvCall->pSrvCallName->Buffer,
  961. SrvCall->pSrvCallName->Length);
  962. //
  963. // Allocate memory for the PathName and copy it.
  964. //
  965. NetRootName = &(NetRoot->pNetRootName->Buffer[1]);
  966. NetRootName = wcschr(NetRootName, L'\\');
  967. //
  968. // The sizeof(WCHAR) is for the final '\0' char.
  969. //
  970. NetRootNameLengthInBytes = (NetRoot->pNetRootName->Length - NetRoot->pSrvCall->pSrvCallName->Length);
  971. PathNameLengthInBytes = (NetRootNameLengthInBytes + sizeof(WCHAR));
  972. if (SrvOpen->pAlreadyPrefixedName->Length) {
  973. //
  974. // The sizeof(WCHAR) is for the backslash after the NetRootName.
  975. //
  976. PathNameLengthInBytes += (SrvOpen->pAlreadyPrefixedName->Length + sizeof(WCHAR));
  977. }
  978. PathName = RxAllocatePoolWithTag(PagedPool,
  979. PathNameLengthInBytes,
  980. DAV_LOCKTOKENENTRY_POOLTAG);
  981. if (PathName == NULL) {
  982. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  983. DavDbgTrace(DAV_TRACE_ERROR,
  984. ("ld: ERROR: MRxDAVPrecompleteUserModeCreateRequest/"
  985. "RxAllocatePoolWithTag: NtStatus = %08lx\n",
  986. PsGetCurrentThreadId(), NtStatus));
  987. goto EXIT_THE_FUNCTION;
  988. }
  989. LockTokenEntry->PathName = (PWCHAR)PathName;
  990. RtlZeroMemory(PathName, PathNameLengthInBytes);
  991. //
  992. // Copy the NetRootName.
  993. //
  994. RtlCopyMemory(PathName, NetRootName, NetRootNameLengthInBytes);
  995. //
  996. // We need to copy the backclash and the remaining path name only if
  997. // the remaining path name exists.
  998. //
  999. if (SrvOpen->pAlreadyPrefixedName->Length) {
  1000. if (SrvOpen->pAlreadyPrefixedName->Buffer[0] != L'\\') {
  1001. //
  1002. // Copy the backslash.
  1003. //
  1004. RtlCopyMemory((PathName + NetRootNameLengthInBytes), L"\\", sizeof(WCHAR));
  1005. //
  1006. // Copy the remaining path name after the NetRootName.
  1007. //
  1008. RtlCopyMemory((PathName + NetRootNameLengthInBytes + sizeof(WCHAR)),
  1009. SrvOpen->pAlreadyPrefixedName->Buffer,
  1010. SrvOpen->pAlreadyPrefixedName->Length);
  1011. } else {
  1012. //
  1013. // Copy the remaining path name after the NetRootName which has the leading
  1014. // backslash already.
  1015. //
  1016. RtlCopyMemory((PathName + NetRootNameLengthInBytes),
  1017. SrvOpen->pAlreadyPrefixedName->Buffer,
  1018. SrvOpen->pAlreadyPrefixedName->Length);
  1019. }
  1020. }
  1021. //
  1022. // Add the newly created entry to the global LockTokenEntryList.
  1023. //
  1024. ExAcquireResourceExclusiveLite(&(LockTokenEntryListLock), TRUE);
  1025. InsertHeadList(&(LockTokenEntryList), &(LockTokenEntry->listEntry));
  1026. ExReleaseResourceLite(&(LockTokenEntryListLock));
  1027. //
  1028. // Keep a link to this LockTokenEntry in the davSrvOpen. On close
  1029. // of this SrvOpen, we will delete this entry.
  1030. //
  1031. davSrvOpen->LockTokenEntry = LockTokenEntry;
  1032. //
  1033. // We set this to TRUE since the file has been LOCKed on the server
  1034. // on this Create. All the requests that modify the file on the
  1035. // server from now on should contain the OpaqueLockToken.
  1036. //
  1037. DavFcb->FileIsLockedOnTheServer = TRUE;
  1038. }
  1039. } else {
  1040. //
  1041. // This was a directory open.
  1042. //
  1043. DavFcb->isDirectory = TRUE;
  1044. if (CreateResponse->DeleteOnClose) {
  1045. DavFcb->DeleteOnClose = TRUE;
  1046. }
  1047. //
  1048. // If a new directory has been created then we need to set the
  1049. // attributes of this new file on close on the server.
  1050. //
  1051. if (CreateResponse->NewFileCreatedAndSetAttributes) {
  1052. DavFcb->fFileAttributesChanged = TRUE;
  1053. }
  1054. //
  1055. // If a new file or directory is created, we need to PROPPATCH the
  1056. // time values on close. This is because we use the time values from
  1057. // the client when the name cache entry is created for this new
  1058. // file. The same time value needs to be on the server.
  1059. //
  1060. if (CreateResponse->PropPatchTheTimeValues) {
  1061. DavFcb->fCreationTimeChanged = TRUE;
  1062. DavFcb->fLastAccessTimeChanged = TRUE;
  1063. DavFcb->fLastModifiedTimeChanged = TRUE;
  1064. }
  1065. }
  1066. if (NtStatus == STATUS_SUCCESS) {
  1067. RxContext->Create.ReturnedCreateInformation = (ULONG)WorkItem->Information;
  1068. *(DavContext->CreateReturnedFileInfo) = CreateResponse->CreateReturnedFileInfo;
  1069. capFcb->Attributes = CreateResponse->CreateReturnedFileInfo.BasicInformation.FileAttributes;
  1070. if ((capFcb->Attributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  1071. ((RxContext->Create.ReturnedCreateInformation == FILE_CREATED) ||
  1072. (RxContext->Create.ReturnedCreateInformation == FILE_OVERWRITTEN))) {
  1073. //
  1074. // The encryption user information is added to the file. This
  1075. // information need to be sent to the server even if the file
  1076. // itself is created empty. We set DoNotTakeTheCurrentTimeAsLMT to
  1077. // TRUE since the LMT has been just set on Create and we do not
  1078. // need to set it to the current time on close.
  1079. //
  1080. InterlockedExchange(&(DavFcb->FileWasModified), 1);
  1081. DavFcb->DoNotTakeTheCurrentTimeAsLMT = TRUE;
  1082. DavFcb->fFileAttributesChanged = TRUE;
  1083. DavDbgTrace(DAV_TRACE_DETAIL,
  1084. ("MRxDAVPrecompleteUserModeCreateRequest: Encrypted file/dir was created %x %x %x\n",
  1085. DavFcb, Fcb, ((PFCB)Fcb)->Attributes));
  1086. }
  1087. if (capFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) {
  1088. if (capFcb->Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  1089. //
  1090. // We update the registry if the directory has been encrypted
  1091. // by someone else.
  1092. //
  1093. NtStatus = MRxDAVCreateEncryptedDirectoryKey(&DavFcb->FileNameInfo);
  1094. } else {
  1095. //
  1096. // Query the registry to see if the directory should be encrypted.
  1097. //
  1098. NtStatus = MRxDAVQueryEncryptedDirectoryKey(&DavFcb->FileNameInfo);
  1099. if (NtStatus == STATUS_SUCCESS) {
  1100. capFcb->Attributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1101. } else if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  1102. NtStatus = STATUS_SUCCESS;
  1103. }
  1104. }
  1105. }
  1106. DavDbgTrace(DAV_TRACE_DETAIL,
  1107. ("MRxDAVPrecompleteUserModeCreateRequest file info %x %x %x %x %x %x %ws\n",
  1108. capFcb->Attributes,
  1109. CreateResponse->BasicInformation.CreationTime.HighPart,
  1110. CreateResponse->BasicInformation.CreationTime.LowPart,
  1111. CreateResponse->StandardInformation.EndOfFile.LowPart,
  1112. DavFcb,
  1113. Fcb,
  1114. DavFcb->FileName));
  1115. }
  1116. EXIT_THE_FUNCTION:
  1117. DavDbgTrace(DAV_TRACE_DETAIL,
  1118. ("%ld: Leaving MRxDAVPrecompleteUserModeCreateRequest with "
  1119. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1120. return TRUE;
  1121. }
  1122. NTSTATUS
  1123. MRxDAVCreateContinuation(
  1124. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. This is the continuation routine for the create operation.
  1129. Arguments:
  1130. AsyncEngineContext - The Reflectors context.
  1131. RxContext - The RDBSS context.
  1132. Return Value:
  1133. RXSTATUS - The return status for the operation
  1134. --*/
  1135. {
  1136. NTSTATUS NtStatus = STATUS_SUCCESS;
  1137. PWEBDAV_CONTEXT DavContext = (PWEBDAV_CONTEXT)AsyncEngineContext;
  1138. RxCaptureFcb;
  1139. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  1140. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  1141. PMRX_FCB Fcb = SrvOpen->pFcb;
  1142. PWEBDAV_FCB DavFcb = MRxDAVGetFcbExtension(Fcb);
  1143. PDAV_USERMODE_CREATE_RETURNED_FILEINFO CreateReturnedFileInfo = NULL;
  1144. PNT_CREATE_PARAMETERS NtCreateParameters = NULL;
  1145. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  1146. OBJECT_ATTRIBUTES ObjectAttributes;
  1147. IO_STATUS_BLOCK IoStatusBlock;
  1148. UNICODE_STRING UnicodeFileName;
  1149. PWCHAR NtFileName = NULL;
  1150. BOOL isFileCached = FALSE, isVNRInitialized = FALSE, didIAllocateFcbResource = FALSE;
  1151. PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
  1152. ULONG Disposition = RxContext->Create.NtCreateParameters.Disposition;
  1153. BOOLEAN CacheFound = FALSE;
  1154. PAGED_CODE();
  1155. DavDbgTrace(DAV_TRACE_DETAIL,
  1156. ("%ld: Entering MRxDAVCreateContinuation!!!!\n",
  1157. PsGetCurrentThreadId()));
  1158. DavDbgTrace(DAV_TRACE_CONTEXT,
  1159. ("%ld: MRxDAVCreateContinuation: "
  1160. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  1161. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  1162. DavDbgTrace(DAV_TRACE_DETAIL,
  1163. ("%ld: MRxDAVCreateContinuation: Attempt to open: %wZ\n",
  1164. PsGetCurrentThreadId(),
  1165. GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb)));
  1166. NtCreateParameters = &(RxContext->Create.NtCreateParameters);
  1167. if (MRxDAVIsFileNotFoundCached(RxContext)) {
  1168. DavContext->AsyncEngineContext.FileNotExists = TRUE;
  1169. if ( !( (Disposition==FILE_CREATE) || (Disposition==FILE_OPEN_IF) ||
  1170. (Disposition==FILE_OVERWRITE_IF) || (Disposition==FILE_SUPERSEDE) ) ) {
  1171. //
  1172. // If file does not exist on the server and we're not going to
  1173. // create it, no further operation is necessary.
  1174. //
  1175. DavDbgTrace(DAV_TRACE_DETAIL,
  1176. ("MRxDAVCreateContinuation file not found %wZ\n",GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext)));
  1177. NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  1178. goto EXIT_THE_FUNCTION;
  1179. }
  1180. }
  1181. DavVNetRoot = (PWEBDAV_V_NET_ROOT)RxContext->pRelevantSrvOpen->pVNetRoot->Context;
  1182. isFileCached = DavFcb->isFileCached;
  1183. //
  1184. // We need to initialize the resource that is used to synchronize the
  1185. // "read-modify-write" sequence if its not been done already.
  1186. //
  1187. if (DavFcb->DavReadModifyWriteLock == NULL) {
  1188. //
  1189. // Allocate memory for the resource.
  1190. //
  1191. DavFcb->DavReadModifyWriteLock = RxAllocatePoolWithTag(NonPagedPool,
  1192. sizeof(ERESOURCE),
  1193. DAV_READWRITE_POOLTAG);
  1194. if (DavFcb->DavReadModifyWriteLock == NULL) {
  1195. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1196. DavDbgTrace(DAV_TRACE_ERROR,
  1197. ("%ld: MRxDAVCreateContinuation/RxAllocatePoolWithTag\n",
  1198. PsGetCurrentThreadId()));
  1199. goto EXIT_THE_FUNCTION;
  1200. }
  1201. didIAllocateFcbResource = TRUE;
  1202. //
  1203. // Now that we have allocated memory, we need to initialize it.
  1204. //
  1205. ExInitializeResourceLite(DavFcb->DavReadModifyWriteLock);
  1206. }
  1207. //
  1208. // If we have a V_NET_ROOT whose LogonID has not been initialized, we need
  1209. // to go to the user mode to create an entry for the user, in case this
  1210. // new V_NET_ROOT has different user credentials than the one that opened
  1211. // this file. We need to do this even if the file is cached since the user
  1212. // that opened the file could be different from the current user. Its
  1213. // possible for multiple V_NET_ROOTS to be associate with the same FCB since
  1214. // FCB is associated with a NET_ROOT.
  1215. //
  1216. isVNRInitialized = DavVNetRoot->LogonIDSet;
  1217. //
  1218. // Since we set the LogonId during the creation of the V_NET_ROOT, this
  1219. // should always be TRUE.
  1220. //
  1221. ASSERT(isVNRInitialized == TRUE);
  1222. //
  1223. // We can look at the FCB and figure out if this file was already opened
  1224. // and cached in the WinInet cache. If it was, then we already have the
  1225. // local name of the cached file in the FCB. All we need to do is open
  1226. // a handle to the file with the create options specified by the caller.
  1227. //
  1228. if ( !isFileCached || !isVNRInitialized ) {
  1229. if ((NtCreateParameters->Disposition == FILE_CREATE) &&
  1230. (NtCreateParameters->FileAttributes & FILE_ATTRIBUTE_SYSTEM) &&
  1231. (NtCreateParameters->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  1232. //
  1233. // Remove the Encryption flag if creating a SYSTEM file.
  1234. //
  1235. NtCreateParameters->FileAttributes &= ~FILE_ATTRIBUTE_ENCRYPTED;
  1236. }
  1237. CreateReturnedFileInfo = RxAllocatePoolWithTag(PagedPool,
  1238. sizeof(DAV_USERMODE_CREATE_RETURNED_FILEINFO),
  1239. DAV_FILEINFO_POOLTAG);
  1240. if (CreateReturnedFileInfo == NULL) {
  1241. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1242. DavDbgTrace(DAV_TRACE_ERROR,
  1243. ("%ld: MRxDAVCreateContinuation/RxAllocatePool: Error Val"
  1244. " = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  1245. goto EXIT_THE_FUNCTION;
  1246. }
  1247. RtlZeroMemory(CreateReturnedFileInfo, sizeof(DAV_USERMODE_CREATE_RETURNED_FILEINFO));
  1248. DavContext->CreateReturnedFileInfo = CreateReturnedFileInfo;
  1249. CacheFound = MRxDAVIsFileInfoCacheFound(RxContext,
  1250. CreateReturnedFileInfo,
  1251. &(NtStatus),
  1252. NULL);
  1253. if (CacheFound) {
  1254. //
  1255. // If it exists in the cache, we perform a few checks before
  1256. // succeeding the create.
  1257. //
  1258. //
  1259. // If the FileAttributes had the READ_ONLY bit set, then these
  1260. // cannot be TRUE.
  1261. // 1. CreateDisposition cannot be FILE_OVERWRITE_IF or
  1262. // FILE_OVERWRITE or FILE_SUPERSEDE.
  1263. // 2. CreateDisposition cannot be FILE_DELETE_ON_CLOSE.
  1264. // 3. DesiredAccess cannot be GENERIC_ALL or GENERIC_WRITE or
  1265. // FILE_WRITE_DATA or FILE_APPEND_DATA.
  1266. // This is because these intend to overwrite the existing file.
  1267. //
  1268. if ( (CreateReturnedFileInfo->BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY) &&
  1269. ( (NtCreateParameters->Disposition == FILE_OVERWRITE) ||
  1270. (NtCreateParameters->Disposition == FILE_OVERWRITE_IF) ||
  1271. (NtCreateParameters->Disposition == FILE_SUPERSEDE) ||
  1272. (NtCreateParameters->CreateOptions & (FILE_DELETE_ON_CLOSE) ||
  1273. (NtCreateParameters->DesiredAccess & (GENERIC_ALL | GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA)) ) ) ) {
  1274. DavDbgTrace(DAV_TRACE_ERROR,
  1275. ("%ld: MRxDAVCreateContinuation: ReadOnly & ObjectMismatch\n",
  1276. PsGetCurrentThreadId()));
  1277. NtStatus = STATUS_ACCESS_DENIED;
  1278. goto EXIT_THE_FUNCTION;
  1279. }
  1280. //
  1281. // We return failure if FILE_CREATE was specified since the file
  1282. // already exists.
  1283. //
  1284. if (NtCreateParameters->Disposition == FILE_CREATE) {
  1285. DavDbgTrace(DAV_TRACE_ERROR,
  1286. ("%ld: MRxDAVCreateContinuation: FILE_CREATE\n",
  1287. PsGetCurrentThreadId()));
  1288. NtStatus = STATUS_OBJECT_NAME_COLLISION;
  1289. goto EXIT_THE_FUNCTION;
  1290. }
  1291. //
  1292. // If the file is a directory and the caller supplied
  1293. // FILE_NON_DIRECTORY_FILE as one of the CreateOptions or if the
  1294. // file as a file and the CreateOptions has FILE_DIRECTORY_FILE
  1295. // then we return STATUS_ACCESS_DENIED.
  1296. //
  1297. if ( (NtCreateParameters->CreateOptions & FILE_DIRECTORY_FILE) &&
  1298. !(CreateReturnedFileInfo->StandardInformation.Directory) ) {
  1299. DavDbgTrace(DAV_TRACE_ERROR,
  1300. ("%ld: MRxDAVCreateContinuation: File & FILE_DIRECTORY_FILE\n",
  1301. PsGetCurrentThreadId()));
  1302. NtStatus = STATUS_NOT_A_DIRECTORY;
  1303. goto EXIT_THE_FUNCTION;
  1304. }
  1305. if ( (NtCreateParameters->CreateOptions & FILE_NON_DIRECTORY_FILE) &&
  1306. (CreateReturnedFileInfo->StandardInformation.Directory) ) {
  1307. DavDbgTrace(DAV_TRACE_ERROR,
  1308. ("%ld: MRxDAVCreateContinuation: Directory & FILE_NON_DIRECTORY_FILE\n",
  1309. PsGetCurrentThreadId()));
  1310. NtStatus = STATUS_FILE_IS_A_DIRECTORY;
  1311. goto EXIT_THE_FUNCTION;
  1312. }
  1313. //
  1314. // If the delete is for a directory and the path is of the form
  1315. // \\server\share then we return STATUS_ACCESS_DENIED. This is
  1316. // because we do not allow a client to delete a share on the server.
  1317. // If the path is of the form \\server\share then the value of
  1318. // SrvOpen->pAlreadyPrefixedName->Length is 0.
  1319. //
  1320. if ( (CreateReturnedFileInfo->StandardInformation.Directory) &&
  1321. (SrvOpen->pAlreadyPrefixedName->Length == 0) &&
  1322. ( (NtCreateParameters->CreateOptions & FILE_DELETE_ON_CLOSE) ||
  1323. (NtCreateParameters->DesiredAccess & DELETE) ) ) {
  1324. DavDbgTrace(DAV_TRACE_ERROR,
  1325. ("%ld: MRxDAVCreateContinuation: ServerShareDelete\n",
  1326. PsGetCurrentThreadId()));
  1327. NtStatus = STATUS_ACCESS_DENIED;
  1328. goto EXIT_THE_FUNCTION;
  1329. }
  1330. if ((NtCreateParameters->DesiredAccess & DELETE ||
  1331. NtCreateParameters->CreateOptions & FILE_DELETE_ON_CLOSE) &&
  1332. CreateReturnedFileInfo->BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1333. //
  1334. // If it is a open for directory deletion, we want to make sure
  1335. // no files are under the directory before return success.
  1336. //
  1337. CacheFound = FALSE;
  1338. } else {
  1339. DavContext->AsyncEngineContext.FileInformationCached = TRUE;
  1340. }
  1341. }
  1342. //
  1343. // We short circuit the open in kernel under the following conditions.
  1344. // 1. If the file is in the name cache and open is for a directory.
  1345. // 2. The file is NOT encrypted. This is because when we short circuit
  1346. // the open, we do not create a local file and hence no local file
  1347. // handle and no underlyingdeviceobject. This is needed by some of
  1348. // the FSCTLs that are issued against the EFS files. Hence we skip
  1349. // short circuiting them.
  1350. // 3. A file with desire access of delete or read attributes.
  1351. //
  1352. if (CacheFound &&
  1353. ((CreateReturnedFileInfo->BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
  1354. (NtCreateParameters->Disposition == FILE_OPEN) &&
  1355. !(NtCreateParameters->DesiredAccess & ~(SYNCHRONIZE | DELETE | FILE_READ_ATTRIBUTES)) &&
  1356. !(CreateReturnedFileInfo->BasicInformation.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED))) {
  1357. if (CreateReturnedFileInfo->BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1358. DavFcb->isDirectory = TRUE;
  1359. }
  1360. //
  1361. // If this Create was with FILE_DELETE_ON_CLOSE, we need to set this
  1362. // information in the FCB since we'll need to DELETE this file on
  1363. // Close.
  1364. //
  1365. if (NtCreateParameters->CreateOptions & FILE_DELETE_ON_CLOSE) {
  1366. DavFcb->DeleteOnClose = TRUE;
  1367. }
  1368. DavDbgTrace(DAV_TRACE_DETAIL,
  1369. ("%ld: MRxDAVCreateContinuation: Pseudo Open: %wZ\n",
  1370. PsGetCurrentThreadId(),
  1371. GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb)));
  1372. } else {
  1373. UNICODE_STRING ParentDirName;
  1374. SHORT i;
  1375. FILE_BASIC_INFORMATION BasicInformation;
  1376. PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1377. DavDbgTrace(DAV_TRACE_DETAIL,
  1378. ("%ld: MRxDAVCreateContinuation: Usermode Open: %wZ\n",
  1379. PsGetCurrentThreadId(),
  1380. GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb)));
  1381. if (FileName->Length > 0) {
  1382. //
  1383. // Try to get the parent directory information from cache so that we don't
  1384. // have to query the server.
  1385. //
  1386. for ( i = ( (FileName->Length / sizeof(WCHAR)) - 1 ); i >= 0; i-- ) {
  1387. if (FileName->Buffer[i] == L'\\') {
  1388. break;
  1389. }
  1390. }
  1391. //
  1392. // Only if we found a wack will i be > 0. If we did not find
  1393. // a wack (==> i == -1), it means that the parent directory was
  1394. // not specified in the path. Hence we do not perform the check
  1395. // below.
  1396. //
  1397. if (i > 0) {
  1398. ParentDirName.Length = (i * sizeof(WCHAR));
  1399. ParentDirName.MaximumLength = (i * sizeof(WCHAR));
  1400. ParentDirName.Buffer = FileName->Buffer;
  1401. if (MRxDAVIsBasicFileInfoCacheFound(RxContext,&BasicInformation,&NtStatus,&ParentDirName)) {
  1402. DavContext->AsyncEngineContext.ParentDirInfomationCached = TRUE;
  1403. DavContext->AsyncEngineContext.ParentDirIsEncrypted = BooleanFlagOn(BasicInformation.FileAttributes,FILE_ATTRIBUTE_ENCRYPTED);
  1404. DavDbgTrace(DAV_TRACE_INFOCACHE,
  1405. ("MRxDAVCreateContinuation parent dir found %d %wZ\n",
  1406. DavContext->AsyncEngineContext.ParentDirIsEncrypted,
  1407. &ParentDirName));
  1408. } else {
  1409. NtStatus = MRxDAVGetFullParentDirectoryPath(RxContext, &ParentDirName);
  1410. if (NtStatus != STATUS_SUCCESS) {
  1411. goto EXIT_THE_FUNCTION;
  1412. }
  1413. if (ParentDirName.Buffer != NULL) {
  1414. NtStatus = MRxDAVQueryEncryptedDirectoryKey(&ParentDirName);
  1415. if (NtStatus == STATUS_SUCCESS) {
  1416. DavContext->AsyncEngineContext.ParentDirInfomationCached = TRUE;
  1417. DavContext->AsyncEngineContext.ParentDirIsEncrypted = TRUE;
  1418. }
  1419. }
  1420. }
  1421. }
  1422. }
  1423. //
  1424. // If the file is not in the name cache we have to send the request to the webclient
  1425. //
  1426. NtStatus = UMRxSubmitAsyncEngUserModeRequest(
  1427. UMRX_ASYNCENGINE_ARGUMENTS,
  1428. MRxDAVFormatUserModeCreateRequest,
  1429. MRxDAVPrecompleteUserModeCreateRequest
  1430. );
  1431. ASSERT(NtStatus != STATUS_PENDING);
  1432. switch (NtStatus) {
  1433. case STATUS_SUCCESS:
  1434. MRxDAVInvalidateFileNotFoundCache(RxContext);
  1435. MRxDAVCreateFileInfoCache(RxContext,CreateReturnedFileInfo,STATUS_SUCCESS);
  1436. break;
  1437. case STATUS_OBJECT_NAME_NOT_FOUND:
  1438. MRxDAVCacheFileNotFound(RxContext);
  1439. MRxDAVInvalidateFileInfoCache(RxContext);
  1440. break;
  1441. default:
  1442. //
  1443. // Invalid the name based file not found cache if other error
  1444. // happens.
  1445. //
  1446. MRxDAVInvalidateFileInfoCache(RxContext);
  1447. MRxDAVInvalidateFileNotFoundCache(RxContext);
  1448. }
  1449. }
  1450. } else {
  1451. ULONG SizeInBytes;
  1452. ACCESS_MASK DesiredAccess = 0;
  1453. //
  1454. // If the FileAttributes had the READ_ONLY bit set, then these
  1455. // cannot be TRUE.
  1456. // 1. CreateDisposition cannot be FILE_OVERWRITE_IF or
  1457. // FILE_OVERWRITE or FILE_SUPERSEDE.
  1458. // 2. CreateDisposition cannot be FILE_DELETE_ON_CLOSE.
  1459. // 3. DesiredAccess cannot be GENERIC_ALL or GENERIC_WRITE or
  1460. // FILE_WRITE_DATA or FILE_APPEND_DATA.
  1461. // This is because these intend to overwrite the existing file.
  1462. //
  1463. if ( (Fcb->Attributes & FILE_ATTRIBUTE_READONLY) &&
  1464. ( (NtCreateParameters->Disposition == FILE_OVERWRITE) ||
  1465. (NtCreateParameters->Disposition == FILE_OVERWRITE_IF) ||
  1466. (NtCreateParameters->Disposition == FILE_SUPERSEDE) ||
  1467. (NtCreateParameters->CreateOptions & (FILE_DELETE_ON_CLOSE) ||
  1468. (NtCreateParameters->DesiredAccess & (GENERIC_ALL | GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA)) ) ) ) {
  1469. DavDbgTrace(DAV_TRACE_ERROR,
  1470. ("%ld: MRxDAVCreateContinuation(1): ReadOnly & ObjectMismatch\n",
  1471. PsGetCurrentThreadId()));
  1472. NtStatus = STATUS_ACCESS_DENIED;
  1473. goto EXIT_THE_FUNCTION;
  1474. }
  1475. //
  1476. // We return failure if FILE_CREATE was specified since the file
  1477. // already exists.
  1478. //
  1479. if (NtCreateParameters->Disposition == FILE_CREATE) {
  1480. DavDbgTrace(DAV_TRACE_ERROR,
  1481. ("%ld: MRxDAVCreateContinuation(1): FILE_CREATE\n",
  1482. PsGetCurrentThreadId()));
  1483. NtStatus = STATUS_OBJECT_NAME_COLLISION;
  1484. goto EXIT_THE_FUNCTION;
  1485. }
  1486. //
  1487. // If the file is a directory and the caller supplied
  1488. // FILE_NON_DIRECTORY_FILE as one of the CreateOptions or if the
  1489. // file as a file and the CreateOptions has FILE_DIRECTORY_FILE
  1490. // then we return STATUS_ACCESS_DENIED.
  1491. //
  1492. if ( (NtCreateParameters->CreateOptions & FILE_DIRECTORY_FILE) &&
  1493. !(DavFcb->isDirectory) ) {
  1494. DavDbgTrace(DAV_TRACE_ERROR,
  1495. ("%ld: MRxDAVCreateContinuation(1): File & FILE_DIRECTORY_FILE\n",
  1496. PsGetCurrentThreadId()));
  1497. NtStatus = STATUS_NOT_A_DIRECTORY;
  1498. goto EXIT_THE_FUNCTION;
  1499. }
  1500. if ( (NtCreateParameters->CreateOptions & FILE_NON_DIRECTORY_FILE) &&
  1501. (DavFcb->isDirectory) ) {
  1502. DavDbgTrace(DAV_TRACE_ERROR,
  1503. ("%ld: MRxDAVCreateContinuation(1): Directory & FILE_NON_DIRECTORY_FILE\n",
  1504. PsGetCurrentThreadId()));
  1505. NtStatus = STATUS_FILE_IS_A_DIRECTORY;
  1506. goto EXIT_THE_FUNCTION;
  1507. }
  1508. //
  1509. // If the delete is for a directory and the path is of the form
  1510. // \\server\share then we return STATUS_ACCESS_DENIED. This is
  1511. // because we do not allow a client to delete a share on the server.
  1512. // If the path is of the form \\server\share then the value of
  1513. // SrvOpen->pAlreadyPrefixedName->Length is 0.
  1514. //
  1515. if ( (DavFcb->isDirectory) &&
  1516. (SrvOpen->pAlreadyPrefixedName->Length == 0) &&
  1517. ( (NtCreateParameters->CreateOptions & FILE_DELETE_ON_CLOSE) ||
  1518. (NtCreateParameters->DesiredAccess & DELETE) ) ) {
  1519. DavDbgTrace(DAV_TRACE_ERROR,
  1520. ("%ld: MRxDAVCreateContinuation(1): ServerShareDelete\n",
  1521. PsGetCurrentThreadId()));
  1522. NtStatus = STATUS_ACCESS_DENIED;
  1523. goto EXIT_THE_FUNCTION;
  1524. }
  1525. //
  1526. // We need to do the create only if its a file. If we are talking about
  1527. // a directory, then no create is needed.
  1528. //
  1529. if ( !DavFcb->isDirectory ) {
  1530. //
  1531. // We have a cached copy of the file which hasn't been closed. All we
  1532. // need to do is call ZwCreateFile on it.
  1533. //
  1534. //
  1535. // Create an NT path name for the cached file. This is used in the
  1536. // ZwCreateFile call below. If c:\foo\bar is the DOA path name,
  1537. // the NT path name is \??\c:\foo\bar.
  1538. //
  1539. SizeInBytes = ( MAX_PATH + wcslen(L"\\??\\") + 1 ) * sizeof(WCHAR);
  1540. NtFileName = RxAllocatePoolWithTag(PagedPool, SizeInBytes, DAV_FILENAME_POOLTAG);
  1541. if (NtFileName == NULL) {
  1542. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1543. DavDbgTrace(DAV_TRACE_ERROR,
  1544. ("%ld: MRxDAVCreateContinuation/RxAllocatePool: Error Val"
  1545. " = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  1546. goto EXIT_THE_FUNCTION;
  1547. }
  1548. RtlZeroMemory(NtFileName, SizeInBytes);
  1549. wcscpy( NtFileName, L"\\??\\" );
  1550. wcscpy( &(NtFileName[4]), DavFcb->FileName );
  1551. DavDbgTrace(DAV_TRACE_DETAIL,
  1552. ("%ld: MRxDAVCreateContinuation: NtFileName = %ws\n",
  1553. PsGetCurrentThreadId(), NtFileName));
  1554. RtlInitUnicodeString( &(UnicodeFileName), NtFileName );
  1555. //
  1556. // IMPROTANT!!!
  1557. // We use OBJ_KERNEL_HANDLE below for the following reason. While
  1558. // firing up a word file from explorer, I noticed that the create
  1559. // below was happening in one process (A) and the close for the handle
  1560. // which is stored in the SrvOpen extension came down in another
  1561. // process (B). This could happen if the process that is closing the
  1562. // handle (B) duplicated the handle created by A. By using OBJ_KERNEL_HANDLE
  1563. // the handle can be closed by any process.
  1564. //
  1565. InitializeObjectAttributes(&ObjectAttributes,
  1566. &UnicodeFileName,
  1567. (OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE),
  1568. 0,
  1569. NULL);
  1570. DavDbgTrace(DAV_TRACE_DETAIL,
  1571. ("%ld: MRxDAVCreateContinuation: DesiredAccess = %08lx,"
  1572. " FileAttributes = %08lx, ShareAccess = %d, Disposition"
  1573. " = %d, CreateOptions = %08lx\n",
  1574. PsGetCurrentThreadId(),
  1575. NtCreateParameters->DesiredAccess,
  1576. NtCreateParameters->FileAttributes,
  1577. NtCreateParameters->ShareAccess,
  1578. NtCreateParameters->Disposition,
  1579. NtCreateParameters->CreateOptions));
  1580. //
  1581. // We use FILE_SHARE_VALID_FLAGS for share access because RDBSS
  1582. // checks this for us. Moreover, we delay the close after the final
  1583. // close happens and this could cause problems. Consider the scenario.
  1584. // 1. Open with NO share access.
  1585. // 2. We create a local handle with this share access.
  1586. // 3. The app closes the handle. We delay the close and keep the local
  1587. // handle.
  1588. // 4. Another open comes with any share access. This will be
  1589. // conflicting share access since the first one was done with no
  1590. // share access. This should succeed since the previous open has
  1591. // been closed from the app and the I/O systems point of view.
  1592. // 5. It will not if we have created the local handle with the share
  1593. // access which came with the first open.
  1594. // Therefore we need to pass FILE_SHARE_VALID_FLAGS while creating
  1595. // the local handle.
  1596. //
  1597. //
  1598. // We have FILE_NO_INTERMEDIATE_BUFFERING ORed with the CreateOptions
  1599. // the user specified, becuase we don't want the underlying file
  1600. // system to create another cache map. This way all the I/O that comes
  1601. // to us will directly go to the disk. BUG 128843 in the Windows RAID
  1602. // database explains some deadlock scenarios that could happen with
  1603. // PagingIo if we don't do this. Also since we supply the
  1604. // FILE_NO_INTERMEDIATE_BUFFERING option we filter out the
  1605. // FILE_APPEND_DATA from the DesiredAccess flags since the underlying
  1606. // filesystem expects this.
  1607. //
  1608. //
  1609. // We also always create the file with DesiredAccess ORed with
  1610. // FILE_WRITE_DATA if either FILE_READ_DATA or FILE_EXECUTE was
  1611. // specified because there can be situations where we get write
  1612. // IRPs on a FILE_OBJECT which was not opened with Write Access
  1613. // and was only opened with FILE_READ_DATA or FILE_EXECUTE. This
  1614. // is BUG 284557. To get around the problem, we do this.
  1615. //
  1616. DesiredAccess = (NtCreateParameters->DesiredAccess & ~(FILE_APPEND_DATA));
  1617. if ( DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE) ) {
  1618. DesiredAccess |= (FILE_WRITE_DATA);
  1619. }
  1620. NtStatus = ZwCreateFile(&(FileHandle),
  1621. DesiredAccess,
  1622. &(ObjectAttributes),
  1623. &(IoStatusBlock),
  1624. &(NtCreateParameters->AllocationSize),
  1625. NtCreateParameters->FileAttributes,
  1626. FILE_SHARE_VALID_FLAGS,
  1627. NtCreateParameters->Disposition,
  1628. (NtCreateParameters->CreateOptions | FILE_NO_INTERMEDIATE_BUFFERING),
  1629. RxContext->Create.EaBuffer,
  1630. RxContext->Create.EaLength);
  1631. if (NtStatus != STATUS_SUCCESS) {
  1632. DavDbgTrace(DAV_TRACE_ERROR,
  1633. ("%ld: ERROR: MRxDAVCreateContinuation/ZwCreateFile: "
  1634. "Error Val = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  1635. goto EXIT_THE_FUNCTION;
  1636. }
  1637. DavDbgTrace(DAV_TRACE_DETAIL,
  1638. ("%ld: MRxDAVCreateContinuation: FileHandle = %08lx, "
  1639. "Process = %08lx, SrvOpen = %08lx, davSrvOpen = %08lx\n",
  1640. PsGetCurrentThreadId(), FileHandle, PsGetCurrentProcess(),
  1641. SrvOpen, davSrvOpen));
  1642. //
  1643. // On the final close we check this to figure out where the close of the
  1644. // handle should occur.
  1645. //
  1646. davSrvOpen->createdInKernel = TRUE;
  1647. NtStatus = ObReferenceObjectByHandle(
  1648. FileHandle,
  1649. 0L,
  1650. NULL,
  1651. KernelMode,
  1652. (PVOID *)&(davSrvOpen->UnderlyingFileObject),
  1653. NULL
  1654. );
  1655. if (NtStatus == STATUS_SUCCESS) {
  1656. DavDbgTrace(DAV_TRACE_DETAIL,
  1657. ("%ld: MRxDAVCreateContinuation: UFO(2) = %08lx\n",
  1658. PsGetCurrentThreadId(), davSrvOpen->UnderlyingFileObject));
  1659. davSrvOpen->UnderlyingHandle = FileHandle;
  1660. davSrvOpen->UserModeKey = (PVOID)FileHandle;
  1661. davSrvOpen->UnderlyingDeviceObject =
  1662. IoGetRelatedDeviceObject(davSrvOpen->UnderlyingFileObject);
  1663. } else {
  1664. DavDbgTrace(DAV_TRACE_ERROR,
  1665. ("%ld: ERROR: MRxDAVCreateContinuation/"
  1666. "ObReferenceObjectByHandle: NtStatus = %08lx.\n",
  1667. PsGetCurrentThreadId(), NtStatus));
  1668. ZwClose(FileHandle);
  1669. }
  1670. }
  1671. }
  1672. ASSERT(RxIsFcbAcquiredExclusive(capFcb));
  1673. if ( NtStatus == STATUS_SUCCESS && ( !isFileCached || !isVNRInitialized ) ) {
  1674. RX_FILE_TYPE StorageType = 0;
  1675. PFILE_BASIC_INFORMATION pBasicInformation =
  1676. &(CreateReturnedFileInfo->BasicInformation);
  1677. PFILE_STANDARD_INFORMATION pStandardInformation =
  1678. &(CreateReturnedFileInfo->StandardInformation);
  1679. FCB_INIT_PACKET InitPacket;
  1680. // StorageType = RxInferFileType(RxContext);
  1681. DavDbgTrace(DAV_TRACE_DETAIL,
  1682. ("%ld: MRxDAVCreateContinuation: Storagetype = %08lx\n",
  1683. PsGetCurrentThreadId(), StorageType));
  1684. //
  1685. // If we have never obtained the characteristics, we have to get them.
  1686. //
  1687. if ((capFcb->OpenCount == 0)
  1688. || !FlagOn(capFcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET)) {
  1689. if (StorageType == 0) {
  1690. StorageType = pStandardInformation->Directory?
  1691. (FileTypeDirectory):(FileTypeFile);
  1692. DavDbgTrace(DAV_TRACE_DETAIL,
  1693. ("%ld: MRxDAVCreateContinuation: "
  1694. "ChangedStoragetype %08lx\n",
  1695. PsGetCurrentThreadId(), StorageType));
  1696. }
  1697. DavDbgTrace(DAV_TRACE_DETAIL,
  1698. ("%ld: MRxDAVCreateContinuation: Name: %wZ, FileType: %d\n",
  1699. PsGetCurrentThreadId(),
  1700. GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb), StorageType));
  1701. DavDbgTrace(DAV_TRACE_DETAIL,
  1702. ("%ld: MRxDAVCreateContinuation: FileSize %08lx\n",
  1703. PsGetCurrentThreadId(),
  1704. pStandardInformation->EndOfFile.LowPart));
  1705. RxFinishFcbInitialization(capFcb,
  1706. RDBSS_STORAGE_NTC(StorageType),
  1707. RxFormInitPacket(
  1708. InitPacket,
  1709. &pBasicInformation->FileAttributes,
  1710. &pStandardInformation->NumberOfLinks,
  1711. &pBasicInformation->CreationTime,
  1712. &pBasicInformation->LastAccessTime,
  1713. &pBasicInformation->LastWriteTime,
  1714. &pBasicInformation->ChangeTime,
  1715. &pStandardInformation->AllocationSize,
  1716. &pStandardInformation->EndOfFile,
  1717. &pStandardInformation->EndOfFile));
  1718. }
  1719. }
  1720. if (NtStatus == STATUS_SUCCESS) {
  1721. RxContext->pFobx = RxCreateNetFobx(RxContext, SrvOpen);
  1722. if ( !RxContext->pFobx ) {
  1723. NTSTATUS PostedCloseStatus;
  1724. DavDbgTrace(DAV_TRACE_ERROR,
  1725. ("%ld: MRxDAVCreateContinuation/RxCreateNetFobx.\n",
  1726. PsGetCurrentThreadId()));
  1727. if ( !davSrvOpen->createdInKernel ) {
  1728. PostedCloseStatus = UMRxSubmitAsyncEngUserModeRequest(
  1729. UMRX_ASYNCENGINE_ARGUMENTS,
  1730. MRxDAVFormatUserModeCloseRequest,
  1731. MRxDAVPrecompleteUserModeCloseRequest
  1732. );
  1733. } else {
  1734. ZwClose(davSrvOpen->UnderlyingHandle);
  1735. davSrvOpen->UnderlyingHandle = davSrvOpen->UserModeKey = NULL;
  1736. }
  1737. ObDereferenceObject(davSrvOpen->UnderlyingFileObject);
  1738. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1739. } else {
  1740. //
  1741. // Note, collapsing is enabled on fcb but not on any srvopen.
  1742. //
  1743. SrvOpen->BufferingFlags |= (FCB_STATE_WRITECACHING_ENABLED |
  1744. FCB_STATE_FILESIZECACHEING_ENABLED |
  1745. FCB_STATE_FILETIMECACHEING_ENABLED |
  1746. FCB_STATE_WRITEBUFFERING_ENABLED |
  1747. FCB_STATE_LOCK_BUFFERING_ENABLED |
  1748. FCB_STATE_READBUFFERING_ENABLED |
  1749. FCB_STATE_READCACHING_ENABLED);
  1750. }
  1751. }
  1752. EXIT_THE_FUNCTION:
  1753. if (CreateReturnedFileInfo != NULL) {
  1754. RxFreePool(CreateReturnedFileInfo);
  1755. }
  1756. if (NtFileName != NULL) {
  1757. RxFreePool(NtFileName);
  1758. }
  1759. //
  1760. // If we allocated the FCB resource and the create failed, we need to free
  1761. // up the resource.
  1762. //
  1763. if (NtStatus != STATUS_SUCCESS && didIAllocateFcbResource) {
  1764. ASSERT(DavFcb->DavReadModifyWriteLock != NULL);
  1765. ExDeleteResourceLite(DavFcb->DavReadModifyWriteLock);
  1766. RxFreePool(DavFcb->DavReadModifyWriteLock);
  1767. DavFcb->DavReadModifyWriteLock = NULL;
  1768. }
  1769. DavDbgTrace(DAV_TRACE_DETAIL,
  1770. ("%ld: Leaving MRxDAVCreateContinuation with NtStatus = %08lx.\n",
  1771. PsGetCurrentThreadId(), NtStatus));
  1772. #ifdef DAV_DEBUG_READ_WRITE_CLOSE_PATH
  1773. if (NtStatus == STATUS_SUCCESS && (SrvOpen->pAlreadyPrefixedName->Length > 0) ) {
  1774. DavAddEntryToGlobalList(SrvOpen->pAlreadyPrefixedName);
  1775. }
  1776. #endif // DAV_DEBUG_READ_WRITE_CLOSE_PATH
  1777. return(NtStatus);
  1778. }
  1779. NTSTATUS
  1780. MRxDAVCollapseOpen(
  1781. IN OUT PRX_CONTEXT RxContext
  1782. )
  1783. /*++
  1784. Routine Description:
  1785. This routine collapses a open locally
  1786. Arguments:
  1787. RxContext - the RDBSS context
  1788. Return Value:
  1789. RXSTATUS - The return status for the operation
  1790. --*/
  1791. {
  1792. NTSTATUS Status = STATUS_SUCCESS;
  1793. RxCaptureFcb;
  1794. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  1795. PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall;
  1796. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1797. PAGED_CODE();
  1798. DavDbgTrace(DAV_TRACE_DETAIL,
  1799. ("%ld: Entering MRxDAVCollapseOpen!!!!\n",
  1800. PsGetCurrentThreadId()));
  1801. //
  1802. // We should never come here since we never collapse the Open.
  1803. //
  1804. ASSERT(FALSE);
  1805. RxContext->pFobx = (PMRX_FOBX) RxCreateNetFobx(RxContext, SrvOpen);
  1806. if (RxContext->pFobx != NULL) {
  1807. ASSERT(RxIsFcbAcquiredExclusive(capFcb));
  1808. RxContext->pFobx->OffsetOfNextEaToReturn = 1;
  1809. } else {
  1810. Status = STATUS_INSUFFICIENT_RESOURCES;
  1811. }
  1812. return Status;
  1813. }
  1814. NTSTATUS
  1815. MRxDAVComputeNewBufferingState(
  1816. IN OUT PMRX_SRV_OPEN pMRxSrvOpen,
  1817. IN PVOID pMRxContext,
  1818. OUT PULONG pNewBufferingState
  1819. )
  1820. /*++
  1821. Routine Description:
  1822. This routine computes the appropriate RDBSS buffering state flags
  1823. Arguments:
  1824. pMRxSrvOpen - the MRX SRV_OPEN extension
  1825. pMRxContext - the context passed to RDBSS at Oplock indication time
  1826. pNewBufferingState - the place holder for the new buffering state
  1827. Return Value:
  1828. Notes:
  1829. --*/
  1830. {
  1831. ULONG NewBufferingState;
  1832. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(pMRxSrvOpen);
  1833. PAGED_CODE();
  1834. ASSERT(pNewBufferingState != NULL);
  1835. NewBufferingState = 0;
  1836. pMRxSrvOpen->BufferingFlags = NewBufferingState;
  1837. *pNewBufferingState = pMRxSrvOpen->BufferingFlags;
  1838. return STATUS_SUCCESS;
  1839. }
  1840. NTSTATUS
  1841. MRxDAVTruncate(
  1842. IN PRX_CONTEXT pRxContext
  1843. )
  1844. /*++
  1845. Routine Description:
  1846. This routine truncates the contents of a file system object
  1847. Arguments:
  1848. pRxContext - the RDBSS context
  1849. Return Value:
  1850. RXSTATUS - The return status for the operation
  1851. --*/
  1852. {
  1853. DavDbgTrace(DAV_TRACE_DETAIL,
  1854. ("%ld: Entering MRxDAVTruncate.\n", PsGetCurrentThreadId()));
  1855. PAGED_CODE();
  1856. return STATUS_NOT_IMPLEMENTED;
  1857. }
  1858. NTSTATUS
  1859. MRxDAVForcedClose(
  1860. IN PMRX_SRV_OPEN pSrvOpen
  1861. )
  1862. /*++
  1863. Routine Description:
  1864. This routine closes a file system object
  1865. Arguments:
  1866. pSrvOpen - the instance to be closed
  1867. Return Value:
  1868. RXSTATUS - The return status for the operation
  1869. Notes:
  1870. --*/
  1871. {
  1872. DavDbgTrace(DAV_TRACE_DETAIL,
  1873. ("%ld: Entering MRxDAVForcedClose.\n", PsGetCurrentThreadId()));
  1874. PAGED_CODE();
  1875. return STATUS_NOT_IMPLEMENTED;
  1876. }
  1877. NTSTATUS
  1878. MRxDAVCloseSrvOpen(
  1879. IN PRX_CONTEXT RxContext
  1880. )
  1881. /*++
  1882. Routine Description:
  1883. This routine handles requests to close the srvopen data structure.
  1884. Arguments:
  1885. RxContext - the RDBSS context
  1886. Return Value:
  1887. RXSTATUS - The return status for the operation
  1888. --*/
  1889. {
  1890. NTSTATUS NtStatus = STATUS_SUCCESS;
  1891. PAGED_CODE();
  1892. DavDbgTrace(DAV_TRACE_DETAIL,
  1893. ("%ld: Entering MRxDAVCloseSrvOpen!!!!\n",
  1894. PsGetCurrentThreadId()));
  1895. DavDbgTrace(DAV_TRACE_CONTEXT,
  1896. ("%ld: MRxDAVCloseSrvOpen: RxContext: %08lx\n",
  1897. PsGetCurrentThreadId(), RxContext));
  1898. NtStatus = UMRxAsyncEngOuterWrapper(RxContext,
  1899. SIZEOF_DAV_SPECIFIC_CONTEXT,
  1900. MRxDAVFormatTheDAVContext,
  1901. DAV_MINIRDR_ENTRY_FROM_CLOSESRVOPEN,
  1902. MRxDAVCloseSrvOpenContinuation,
  1903. "MRxDAVCloseSrvOpen");
  1904. DavDbgTrace(DAV_TRACE_DETAIL,
  1905. ("%ld: Leaving MRxDAVCloseSrvOpen with NtStatus = %08lx\n",
  1906. PsGetCurrentThreadId(), NtStatus));
  1907. return(NtStatus);
  1908. }
  1909. NTSTATUS
  1910. MRxDAVFormatUserModeCloseRequest(
  1911. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  1912. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  1913. ULONG WorkItemLength,
  1914. PULONG_PTR ReturnedLength
  1915. )
  1916. /*++
  1917. Routine Description:
  1918. This routine formats the arguments of the close request which is being
  1919. sent to the user mode for processing.
  1920. Arguments:
  1921. RxContext - The RDBSS context.
  1922. AsyncEngineContext - The reflctor's context.
  1923. WorkItem - The work item buffer.
  1924. WorkItemLength - The length of the work item buffer.
  1925. ReturnedLength -
  1926. Return Value:
  1927. STATUS_SUCCESS.
  1928. --*/
  1929. {
  1930. NTSTATUS NtStatus = STATUS_SUCCESS;
  1931. PMRX_SRV_CALL SrvCall = NULL;
  1932. PWEBDAV_SRV_CALL DavSrvCall = NULL;
  1933. PDAV_USERMODE_WORKITEM WorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  1934. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  1935. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  1936. PMRX_FCB Fcb = SrvOpen->pFcb;
  1937. PWEBDAV_FCB DavFcb = MRxDAVGetFcbExtension(Fcb);
  1938. PDAV_USERMODE_CLOSE_REQUEST CloseRequest = &(WorkItem->CloseRequest);
  1939. PWCHAR ServerName = NULL, PathName = NULL;
  1940. ULONG ServerNameLengthInBytes = 0, PathNameLengthInBytes = 0;
  1941. PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
  1942. PSECURITY_CLIENT_CONTEXT SecurityClientContext = NULL;
  1943. PMRX_NET_ROOT NetRoot = NULL;
  1944. PWCHAR NetRootName = NULL, JustTheNetRootName = NULL;
  1945. ULONG NetRootNameLengthInBytes = 0, NetRootNameLengthInWChars = 0;
  1946. LONG FileWasModified = 0;
  1947. RxCaptureFobx;
  1948. PAGED_CODE();
  1949. DavDbgTrace(DAV_TRACE_DETAIL,
  1950. ("%ld: Entering MRxDAVFormatUserModeCloseRequest!!!!\n",
  1951. PsGetCurrentThreadId()));
  1952. DavDbgTrace(DAV_TRACE_CONTEXT,
  1953. ("%ld: MRxDAVFormatUserModeCloseRequest: "
  1954. "AsyncEngineContext = %08lx, RxContext = %08lx.\n",
  1955. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  1956. IF_DEBUG {
  1957. ASSERT (capFobx != NULL);
  1958. ASSERT (capFobx->pSrvOpen == RxContext->pRelevantSrvOpen);
  1959. }
  1960. WorkItem->WorkItemType = UserModeClose;
  1961. SrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;
  1962. ASSERT(SrvCall != NULL);
  1963. DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall);
  1964. ASSERT(DavSrvCall != NULL);
  1965. //
  1966. // Copy the local file name.
  1967. //
  1968. wcscpy(CloseRequest->FileName, DavFcb->FileName);
  1969. wcscpy(CloseRequest->Url, DavFcb->Url);
  1970. //
  1971. // See if the underlying local file has been modified.
  1972. //
  1973. FileWasModified = InterlockedCompareExchange(&(DavFcb->FileWasModified), 0, 0);
  1974. //
  1975. // If the FileWasModified field in the DavFcb is not equal to zero, we need
  1976. // to clear the FileWasModified field in the DavFcb since we are going to
  1977. // PUT the data on the server. We also set FileModifiedBitReset in the
  1978. // DavFcb structure to TRUE. If the PUT fails in the usermode we reset the
  1979. // FileWasModified in the DavFcb to TRUE (in the PreComplete function).
  1980. //
  1981. if (FileWasModified != 0) {
  1982. InterlockedExchange(&(DavFcb->FileWasModified), 0);
  1983. DavFcb->FileModifiedBitReset = TRUE;
  1984. }
  1985. //
  1986. // We need to tell the user mode process about the following file
  1987. // information.
  1988. //
  1989. CloseRequest->DeleteOnClose = DavFcb->DeleteOnClose;
  1990. CloseRequest->FileWasModified = (BOOL)FileWasModified;
  1991. //
  1992. // If this file was modified and DeleteOnClose is not set, we need to
  1993. // set RaiseHardErrorIfCloseFails to TRUE. On the precomplete close call,
  1994. // if the usermode operation failed and RaiseHardErrorIfCloseFails is TRUE,
  1995. // we call IoRaiseInformationalHardError to notify the user (the calls pops
  1996. // up a box) that the data could have been lost.
  1997. //
  1998. if ( (FileWasModified != 0) && !(DavFcb->DeleteOnClose) ) {
  1999. davSrvOpen->RaiseHardErrorIfCloseFails = TRUE;
  2000. } else {
  2001. davSrvOpen->RaiseHardErrorIfCloseFails = FALSE;
  2002. }
  2003. if (!CloseRequest->DeleteOnClose) {
  2004. //
  2005. // If the file is modified, just propatch again. This is to get around
  2006. // the docfile issue where on a PUT, the properties get cleaned up.
  2007. //
  2008. if (FileWasModified != 0) {
  2009. LARGE_INTEGER CurrentTime;
  2010. CloseRequest->fCreationTimeChanged = (((PFCB)Fcb)->CreationTime.QuadPart != 0);
  2011. CloseRequest->fLastAccessTimeChanged = (((PFCB)Fcb)->LastAccessTime.QuadPart != 0);
  2012. CloseRequest->fLastModifiedTimeChanged = (((PFCB)Fcb)->LastWriteTime.QuadPart != 0);
  2013. //
  2014. // We query the Current system time and make that the LastWrite
  2015. // and the LastAccess time of the file. Even though RxCommonCleanup
  2016. // modifies these time values, it only modifies them on FileObjects
  2017. // which have FO_FILE_MODIFIED set. Consider the case where h1 and
  2018. // h2 are two handles created. A write is issued on h2 setting
  2019. // FO_FILE_MODIFIED in its FileObject. CloseHandle(h1) leads to the
  2020. // file being PUT on the server since DavFcb->FileWasModified is
  2021. // TRUE (write on h2 caused this). But since the FileObject of
  2022. // h1 doesn't have FO_FILE_MODIFIED set, in the RxCommonCleanup
  2023. // code the LastWrite and LastAccess time values of this FCB are
  2024. // not modifed causing us to PROPPATCH the old values on the server.
  2025. // To avoid this we query the current time value and set it
  2026. // ourselves in the FCB. If "DavFcb->DoNotTakeTheCurrentTimeAsLMT"
  2027. // is TRUE then we don't do this since the application explicitly
  2028. // set the LastModifiedTime after all the changes were done.
  2029. //
  2030. if (DavFcb->DoNotTakeTheCurrentTimeAsLMT == FALSE) {
  2031. KeQuerySystemTime( &(CurrentTime) );
  2032. ((PFCB)Fcb)->LastAccessTime.QuadPart = CurrentTime.QuadPart;
  2033. ((PFCB)Fcb)->LastWriteTime.QuadPart = CurrentTime.QuadPart;
  2034. }
  2035. //
  2036. // If FILE_ATTRIBUTE_NORMAL was the only attribute set on the file
  2037. // and the file was modified, then we should replace this with the
  2038. // FILE_ATTRIBUTE_ARCHIVE attribute.
  2039. //
  2040. if ( ((PFCB)Fcb)->Attributes == FILE_ATTRIBUTE_NORMAL ) {
  2041. DavDbgTrace(DAV_TRACE_DETAIL,
  2042. ("ld: ERROR: MRxDAVFormatUserModeCloseRequest: "
  2043. "FILE_ATTRIBUTE_NORMAL ===> FILE_ATTRIBUTE_ARCHIVE\n",
  2044. PsGetCurrentThreadId()));
  2045. ((PFCB)Fcb)->Attributes = FILE_ATTRIBUTE_ARCHIVE;
  2046. DavFcb->fFileAttributesChanged = TRUE;
  2047. }
  2048. if ((((PFCB)Fcb)->Attributes != 0) || DavFcb->fFileAttributesChanged) {
  2049. CloseRequest->fFileAttributesChanged = TRUE;
  2050. }
  2051. } else {
  2052. //
  2053. // If any of the following times have changed, then we need to PROPPATCH
  2054. // them to the server.
  2055. //
  2056. CloseRequest->fCreationTimeChanged = DavFcb->fCreationTimeChanged;
  2057. CloseRequest->fLastAccessTimeChanged = DavFcb->fLastAccessTimeChanged;
  2058. CloseRequest->fLastModifiedTimeChanged = DavFcb->fLastModifiedTimeChanged;
  2059. CloseRequest->fFileAttributesChanged = DavFcb->fFileAttributesChanged;
  2060. }
  2061. }
  2062. //
  2063. // Copy the various time values.
  2064. //
  2065. CloseRequest->CreationTime = ((PFCB)Fcb)->CreationTime;
  2066. CloseRequest->LastAccessTime = ((PFCB)Fcb)->LastAccessTime;
  2067. CloseRequest->LastModifiedTime = ((PFCB)Fcb)->LastWriteTime;
  2068. CloseRequest->dwFileAttributes = ((PFCB)Fcb)->Attributes;
  2069. CloseRequest->FileSize = Fcb->Header.FileSize.LowPart;
  2070. //
  2071. // Copy the ServerName.
  2072. //
  2073. ServerNameLengthInBytes = ( SrvCall->pSrvCallName->Length + sizeof(WCHAR) );
  2074. ServerName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  2075. ServerNameLengthInBytes);
  2076. if (ServerName == NULL) {
  2077. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2078. DavDbgTrace(DAV_TRACE_ERROR,
  2079. ("ld: ERROR: MRxDAVFormatUserModeCloseRequest/"
  2080. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  2081. PsGetCurrentThreadId(), NtStatus));
  2082. goto EXIT_THE_FUNCTION;
  2083. }
  2084. RtlCopyBytes(ServerName,
  2085. SrvCall->pSrvCallName->Buffer,
  2086. SrvCall->pSrvCallName->Length);
  2087. ServerName[( ( (ServerNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0';
  2088. CloseRequest->ServerName = ServerName;
  2089. //
  2090. // Copy the ServerID.
  2091. //
  2092. CloseRequest->ServerID = DavSrvCall->ServerID;
  2093. NetRoot = SrvOpen->pFcb->pNetRoot;
  2094. //
  2095. // The NetRootName (pNetRootName) includes the ServerName. Hence to get the
  2096. // NetRootNameLengthInBytes, we do the following.
  2097. //
  2098. NetRootNameLengthInBytes = (NetRoot->pNetRootName->Length - NetRoot->pSrvCall->pSrvCallName->Length);
  2099. NetRootNameLengthInWChars = ( NetRootNameLengthInBytes / sizeof(WCHAR) );
  2100. NetRootName = &(NetRoot->pNetRootName->Buffer[1]);
  2101. JustTheNetRootName = wcschr(NetRootName, L'\\');
  2102. //
  2103. // Copy the PathName of the Directory. If the file was renamed, we need to
  2104. // copy the new path name which is stored in the DavFcb and not the
  2105. // AlreadyPrefixedName of the SrvOpen.
  2106. //
  2107. if (DavFcb->FileWasRenamed) {
  2108. PathNameLengthInBytes = ( NetRootNameLengthInBytes +
  2109. DavFcb->NewFileNameLength +
  2110. sizeof(WCHAR) );
  2111. } else {
  2112. PathNameLengthInBytes = ( NetRootNameLengthInBytes +
  2113. SrvOpen->pAlreadyPrefixedName->Length +
  2114. sizeof(WCHAR) );
  2115. }
  2116. PathName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  2117. PathNameLengthInBytes);
  2118. if (PathName == NULL) {
  2119. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2120. DavDbgTrace(DAV_TRACE_ERROR,
  2121. ("ld: ERROR: MRxDAVFormatUserModeCloseRequest/"
  2122. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  2123. PsGetCurrentThreadId(), NtStatus));
  2124. goto EXIT_THE_FUNCTION;
  2125. }
  2126. RtlZeroMemory(PathName, PathNameLengthInBytes);
  2127. RtlCopyBytes(PathName, JustTheNetRootName, NetRootNameLengthInBytes);
  2128. if (DavFcb->FileWasRenamed) {
  2129. RtlCopyBytes((PathName + NetRootNameLengthInWChars),
  2130. DavFcb->NewFileName,
  2131. DavFcb->NewFileNameLength);
  2132. DavDbgTrace(DAV_TRACE_DETAIL,
  2133. ("ld: MRxDAVFormatUserModeCloseRequest. ReNamed!!! NewFileName = %ws\n",
  2134. PsGetCurrentThreadId(), PathName));
  2135. } else {
  2136. RtlCopyBytes((PathName + NetRootNameLengthInWChars),
  2137. SrvOpen->pAlreadyPrefixedName->Buffer,
  2138. SrvOpen->pAlreadyPrefixedName->Length);
  2139. }
  2140. PathName[( ( (PathNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0';
  2141. CloseRequest->PathName = PathName;
  2142. DavDbgTrace(DAV_TRACE_DETAIL,
  2143. ("ld: MRxDAVFormatUserModeCloseRequest. PathName = %ws\n",
  2144. PsGetCurrentThreadId(), PathName));
  2145. //
  2146. // Set the LogonID stored in the Dav V_NET_ROOT. This value is used in the
  2147. // user mode.
  2148. //
  2149. DavVNetRoot = (PWEBDAV_V_NET_ROOT)SrvOpen->pVNetRoot->Context;
  2150. ASSERT(DavVNetRoot != NULL);
  2151. CloseRequest->LogonID.LowPart = DavVNetRoot->LogonID.LowPart;
  2152. CloseRequest->LogonID.HighPart = DavVNetRoot->LogonID.HighPart;
  2153. if ( !DavFcb->isDirectory ) {
  2154. CloseRequest->isDirectory = FALSE;
  2155. if ( !davSrvOpen->createdInKernel ) {
  2156. CloseRequest->Handle = davSrvOpen->UnderlyingHandle;
  2157. CloseRequest->UserModeKey = davSrvOpen->UserModeKey;
  2158. } else {
  2159. CloseRequest->Handle = NULL;
  2160. CloseRequest->UserModeKey = NULL;
  2161. CloseRequest->createdInKernel = davSrvOpen->createdInKernel; // TRUE
  2162. }
  2163. } else {
  2164. CloseRequest->isDirectory = TRUE;
  2165. }
  2166. //
  2167. // If an OpaqueLockToken is associated with this SrvOpen (which means that
  2168. // the file was LOCKed on the server) then we need to add this token to
  2169. // the requests (PUT etc.) we send to the server.
  2170. //
  2171. if (davSrvOpen->OpaqueLockToken != NULL) {
  2172. ULONG LockTokenLengthInBytes = 0;
  2173. ASSERT(davSrvOpen->LockTokenEntry != NULL);
  2174. LockTokenLengthInBytes = (1 + wcslen(davSrvOpen->OpaqueLockToken)) * sizeof(WCHAR);
  2175. CloseRequest->OpaqueLockToken = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  2176. LockTokenLengthInBytes);
  2177. if (CloseRequest->OpaqueLockToken == NULL) {
  2178. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2179. DavDbgTrace(DAV_TRACE_ERROR,
  2180. ("ld: ERROR: MRxDAVFormatUserModeCloseRequest/"
  2181. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  2182. PsGetCurrentThreadId(), NtStatus));
  2183. goto EXIT_THE_FUNCTION;
  2184. }
  2185. RtlZeroMemory(CloseRequest->OpaqueLockToken, LockTokenLengthInBytes);
  2186. RtlCopyBytes(CloseRequest->OpaqueLockToken,
  2187. davSrvOpen->OpaqueLockToken,
  2188. (wcslen(davSrvOpen->OpaqueLockToken) * sizeof(WCHAR)));
  2189. DavDbgTrace(DAV_TRACE_DETAIL,
  2190. ("%ld: MRxDAVFormatUserModeCloseRequest: CloseRequest->OpaqueLockToken = %ws\n",
  2191. PsGetCurrentThreadId(), CloseRequest->OpaqueLockToken));
  2192. }
  2193. SecurityClientContext = &(DavVNetRoot->SecurityClientContext);
  2194. //
  2195. // Impersonate the client who initiated the request. If we fail to
  2196. // impersonate, tough luck.
  2197. //
  2198. if (SecurityClientContext != NULL) {
  2199. NtStatus = UMRxImpersonateClient(SecurityClientContext, WorkItemHeader);
  2200. if (!NT_SUCCESS(NtStatus)) {
  2201. DavDbgTrace(DAV_TRACE_ERROR,
  2202. ("%ld: ERROR: MRxDAVFormatUserModeCloseRequest/"
  2203. "UMRxImpersonateClient. NtStatus = %08lx.\n",
  2204. PsGetCurrentThreadId(), NtStatus));
  2205. }
  2206. } else {
  2207. NtStatus = STATUS_INVALID_PARAMETER;
  2208. DavDbgTrace(DAV_TRACE_ERROR,
  2209. ("%ld: ERROR: MRxDAVFormatUserModeCloseRequest: "
  2210. "SecurityClientContext is NULL.\n",
  2211. PsGetCurrentThreadId()));
  2212. }
  2213. EXIT_THE_FUNCTION:
  2214. #ifdef DAV_DEBUG_READ_WRITE_CLOSE_PATH
  2215. //
  2216. // If we created a LocalFileHandle, we need to close it now.
  2217. //
  2218. if (LocalFileHandle != INVALID_HANDLE_VALUE) {
  2219. ZwClose(LocalFileHandle);
  2220. }
  2221. //
  2222. // If we allocated an NtFileName to do the create, we need to free it now.
  2223. //
  2224. if (NtFileName) {
  2225. RxFreePool(NtFileName);
  2226. }
  2227. #endif // DAV_DEBUG_READ_WRITE_CLOSE_PATH
  2228. DavDbgTrace(DAV_TRACE_DETAIL,
  2229. ("%ld: Leaving MRxDAVFormatUserModeCloseRequest with NtStatus"
  2230. " = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  2231. return(NtStatus);
  2232. }
  2233. BOOL
  2234. MRxDAVPrecompleteUserModeCloseRequest(
  2235. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  2236. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  2237. ULONG WorkItemLength,
  2238. BOOL OperationCancelled
  2239. )
  2240. /*++
  2241. Routine Description:
  2242. The precompletion routine for the CloseSrvOpen request.
  2243. Arguments:
  2244. RxContext - The RDBSS context.
  2245. AsyncEngineContext - The reflctor's context.
  2246. WorkItem - The work item buffer.
  2247. WorkItemLength - The length of the work item buffer.
  2248. OperationCancelled - TRUE if this operation was cancelled by the user.
  2249. Return Value:
  2250. TRUE - UMRxAsyncEngineCalldownIrpCompletion is called by the function
  2251. UMRxCompleteUserModeRequest after we return.
  2252. --*/
  2253. {
  2254. NTSTATUS NtStatus = STATUS_SUCCESS;
  2255. PDAV_USERMODE_WORKITEM WorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  2256. PDAV_USERMODE_CLOSE_REQUEST CloseRequest = &(WorkItem->CloseRequest);
  2257. PMRX_SRV_OPEN SrvOpen = NULL;
  2258. PWEBDAV_SRV_OPEN davSrvOpen = NULL;
  2259. PMRX_FCB Fcb = NULL;
  2260. PWEBDAV_FCB DavFcb = NULL;
  2261. PAGED_CODE();
  2262. DavDbgTrace(DAV_TRACE_DETAIL,
  2263. ("%ld: Entering MRxDAVPrecompleteUserModeCloseRequest\n",
  2264. PsGetCurrentThreadId()));
  2265. DavDbgTrace(DAV_TRACE_CONTEXT,
  2266. ("%ld: MRxDAVPrecompleteUserModeCloseRequest: "
  2267. "AsyncEngineContext = %08lx, RxContext = %08lx.\n",
  2268. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  2269. //
  2270. // A CloseSrvOpen request can never by Async.
  2271. //
  2272. ASSERT(AsyncEngineContext->AsyncOperation == FALSE);
  2273. //
  2274. // If this operation was cancelled, then we don't need to do anything
  2275. // special in the CloseSrvOpen case.
  2276. //
  2277. if (OperationCancelled) {
  2278. DavDbgTrace(DAV_TRACE_ERROR,
  2279. ("%ld: MRxDAVPrecompleteUserModeCloseRequest: Operation Cancelled. "
  2280. "AsyncEngineContext = %08lx, RxContext = %08lx.\n",
  2281. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  2282. } else {
  2283. SrvOpen = RxContext->pRelevantSrvOpen;
  2284. davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  2285. Fcb = SrvOpen->pFcb;
  2286. DavFcb = MRxDAVGetFcbExtension(Fcb);
  2287. }
  2288. if (AsyncEngineContext->Status != STATUS_SUCCESS) {
  2289. DavDbgTrace(DAV_TRACE_ERROR,
  2290. ("%ld: MRxDAVPrecompleteUserModeCloseRequest "
  2291. "Close failed for file \"%ws\"\n",
  2292. PsGetCurrentThreadId(), CloseRequest->PathName));
  2293. if (!OperationCancelled) {
  2294. //
  2295. // If we failed and had reset FileWasModified to 0 in the Format
  2296. // function, then we need to reset it to 1.
  2297. //
  2298. if (DavFcb->FileModifiedBitReset) {
  2299. InterlockedExchange(&(DavFcb->FileWasModified), 1);
  2300. DavFcb->FileModifiedBitReset = FALSE;
  2301. }
  2302. }
  2303. } else {
  2304. if (!OperationCancelled) {
  2305. //
  2306. // If we were successful and FileModifiedBitReset is TRUE then we
  2307. // reset it to FALSE now.
  2308. //
  2309. if (DavFcb->FileModifiedBitReset) {
  2310. DavFcb->FileModifiedBitReset = FALSE;
  2311. }
  2312. }
  2313. }
  2314. //
  2315. // We need to free up the heaps, we allocated in the format routine.
  2316. //
  2317. if (CloseRequest->ServerName != NULL) {
  2318. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  2319. (PBYTE)CloseRequest->ServerName);
  2320. if (NtStatus != STATUS_SUCCESS) {
  2321. DavDbgTrace(DAV_TRACE_ERROR,
  2322. ("%ld: ERROR: MRxDAVPrecompleteUserModeCloseRequest/"
  2323. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  2324. PsGetCurrentThreadId(), NtStatus));
  2325. goto EXIT_THE_FUNCTION;
  2326. }
  2327. }
  2328. if (CloseRequest->PathName != NULL) {
  2329. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  2330. (PBYTE)CloseRequest->PathName);
  2331. if (NtStatus != STATUS_SUCCESS) {
  2332. DavDbgTrace(DAV_TRACE_ERROR,
  2333. ("%ld: ERROR: MRxDAVPrecompleteUserModeCloseRequest/"
  2334. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  2335. PsGetCurrentThreadId(), NtStatus));
  2336. }
  2337. }
  2338. if (CloseRequest->OpaqueLockToken != NULL) {
  2339. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  2340. (PBYTE)CloseRequest->OpaqueLockToken);
  2341. if (NtStatus != STATUS_SUCCESS) {
  2342. DavDbgTrace(DAV_TRACE_ERROR,
  2343. ("%ld: ERROR: MRxDAVPrecompleteUserModeCloseRequest/"
  2344. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  2345. PsGetCurrentThreadId(), NtStatus));
  2346. }
  2347. }
  2348. EXIT_THE_FUNCTION:
  2349. DavDbgTrace(DAV_TRACE_DETAIL,
  2350. ("%ld: Leaving MRxDAVPrecompleteUserModeCloseRequest with "
  2351. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  2352. return TRUE;
  2353. }
  2354. NTSTATUS
  2355. MRxDAVCloseSrvOpenContinuation(
  2356. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  2357. )
  2358. /*++
  2359. Routine Description:
  2360. This routine closes a file across the network.
  2361. Arguments:
  2362. AsyncEngineContext - The Reflectors context.
  2363. RxContext - The RDBSS context.
  2364. Return Value:
  2365. RXSTATUS - The return status for the operation
  2366. --*/
  2367. {
  2368. NTSTATUS NtStatus = STATUS_SUCCESS;
  2369. RxCaptureFcb;
  2370. RxCaptureFobx;
  2371. NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
  2372. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  2373. PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen, capFcb);
  2374. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  2375. PMRX_FCB Fcb = SrvOpen->pFcb;
  2376. PWEBDAV_FCB DavFcb = MRxDAVGetFcbExtension(Fcb);
  2377. BOOL WentToTheUserMode = FALSE;
  2378. ULONG FileWasModified = 0;
  2379. PAGED_CODE();
  2380. //
  2381. // Assert that the FCB has been exclusively acquired.
  2382. //
  2383. ASSERT( RxIsFcbAcquiredExclusive(Fcb) == TRUE );
  2384. if (RxIsFcbAcquiredExclusive(Fcb) != TRUE) {
  2385. DbgPrint("MRxDAVCloseSrvOpenContinuation: FCB NOT Exclusive\n");
  2386. DbgBreakPoint();
  2387. }
  2388. IF_DEBUG {
  2389. ASSERT (capFobx != NULL);
  2390. ASSERT (capFobx->pSrvOpen == RxContext->pRelevantSrvOpen);
  2391. }
  2392. ASSERT(NodeTypeIsFcb(capFcb));
  2393. ASSERT(SrvOpen->OpenCount == 0);
  2394. ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
  2395. DavDbgTrace(DAV_TRACE_DETAIL,
  2396. ("%ld: Entering MRxDAVCloseSrvOpenContinuation!!!!\n",
  2397. PsGetCurrentThreadId()));
  2398. DavDbgTrace(DAV_TRACE_CONTEXT,
  2399. ("%ld: MRxDAVCloseSrvOpenContinuation: "
  2400. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  2401. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  2402. DavDbgTrace(DAV_TRACE_DETAIL,
  2403. ("%ld: MRxDAVCloseSrvOpenContinuation: Attempt to Close: %wZ\n",
  2404. PsGetCurrentThreadId(), RemainingName));
  2405. //
  2406. // If this SrvOpen has an OpaqueLockToken associated with it, we don't need
  2407. // to refresh it anymore since we are going to finalize this SrvOpen.
  2408. //
  2409. if (davSrvOpen->OpaqueLockToken != NULL) {
  2410. ASSERT(davSrvOpen->LockTokenEntry != NULL);
  2411. ExAcquireResourceExclusiveLite(&(LockTokenEntryListLock), TRUE);
  2412. davSrvOpen->LockTokenEntry->ShouldThisEntryBeRefreshed = FALSE;
  2413. ExReleaseResourceLite(&(LockTokenEntryListLock));
  2414. }
  2415. FileWasModified = InterlockedCompareExchange(&(DavFcb->FileWasModified), 0, 0);
  2416. //
  2417. // We go to the usermode if one of the following is TRUE.
  2418. // 1. The File was not LOCked on the server on Create, OR,
  2419. // 2. The File was LOCked on create and this SrvOpen has the LockToken
  2420. // associated with the LOCK taken on the server.
  2421. // We do not want to go to the server if the file is LOCKed and the SrvOpen
  2422. // doesn't contain the LockToken since all the requests to modify the file
  2423. // are going to fail (423 - File Is Locked) in such a scenario.
  2424. //
  2425. if ( (DavFcb->FileIsLockedOnTheServer == FALSE) ||
  2426. (DavFcb->FileIsLockedOnTheServer == TRUE && davSrvOpen->OpaqueLockToken != NULL) ) {
  2427. WentToTheUserMode = TRUE;
  2428. NtStatus = UMRxSubmitAsyncEngUserModeRequest(
  2429. UMRX_ASYNCENGINE_ARGUMENTS,
  2430. MRxDAVFormatUserModeCloseRequest,
  2431. MRxDAVPrecompleteUserModeCloseRequest
  2432. );
  2433. if (NtStatus != STATUS_SUCCESS) {
  2434. DavDbgTrace(DAV_TRACE_ERROR,
  2435. ("%ld: MRxDAVCloseSrvOpenContinuation/"
  2436. "UMRxSubmitAsyncEngUserModeRequest: NtStatus = %08lx.\n",
  2437. PsGetCurrentThreadId(), NtStatus));
  2438. }
  2439. }
  2440. if (DavFcb->isDirectory == FALSE) {
  2441. //
  2442. // If this handle got created in the kernel, we need to close it now.
  2443. //
  2444. if (davSrvOpen->createdInKernel) {
  2445. DavDbgTrace(DAV_TRACE_DETAIL,
  2446. ("%ld: MRxDAVCloseSrvOpenContinuation: FileHandle = %08lx,"
  2447. " Process = %08lx, SrvOpen = %08lx, davSrvOpen = %08lx\n",
  2448. PsGetCurrentThreadId(), davSrvOpen->UnderlyingHandle,
  2449. PsGetCurrentProcess(), SrvOpen, davSrvOpen));
  2450. ZwClose(davSrvOpen->UnderlyingHandle);
  2451. davSrvOpen->UnderlyingHandle = NULL;
  2452. davSrvOpen->UserModeKey = NULL;
  2453. }
  2454. //
  2455. // Remove our reference which we would have taken on the FileObject
  2456. // when the Create succeeded.
  2457. //
  2458. if (davSrvOpen->UnderlyingFileObject) {
  2459. DavDbgTrace(DAV_TRACE_DETAIL,
  2460. ("%ld: MRxDAVCloseSrvOpenContinuation: Attempt to close"
  2461. " %wZ.\n", PsGetCurrentThreadId(), RemainingName));
  2462. ObDereferenceObject(davSrvOpen->UnderlyingFileObject);
  2463. davSrvOpen->UnderlyingFileObject = NULL;
  2464. }
  2465. }
  2466. if (WentToTheUserMode) {
  2467. if (DavFcb->DeleteOnClose) {
  2468. MRxDAVInvalidateFileInfoCache(RxContext);
  2469. MRxDAVCacheFileNotFound(RxContext);
  2470. if ((capFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) &&
  2471. (capFcb->Attributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  2472. //
  2473. // Remove the directory from the registry since it has been deleted.
  2474. //
  2475. MRxDAVRemoveEncryptedDirectoryKey(&DavFcb->FileNameInfo);
  2476. }
  2477. }
  2478. if (FileWasModified != 0) {
  2479. //
  2480. // We cannot predict the size of the file on the server.
  2481. //
  2482. MRxDAVInvalidateFileInfoCache(RxContext);
  2483. }
  2484. NtStatus = AsyncEngineContext->Status;
  2485. }
  2486. //
  2487. // If we succeeded in the usermode, we need to reset some values in the
  2488. // DavFcb so that we don't do this again.
  2489. //
  2490. if (NtStatus == STATUS_SUCCESS && WentToTheUserMode) {
  2491. DavFcb->fCreationTimeChanged = FALSE;
  2492. DavFcb->fFileAttributesChanged = FALSE;
  2493. DavFcb->fLastAccessTimeChanged = FALSE;
  2494. DavFcb->fLastModifiedTimeChanged = FALSE;
  2495. }
  2496. //
  2497. // If we have a non-NULL OpaqueLockToken then we need to free it now. Also,
  2498. // we need to remove the LockTokenEntry associated with this token from
  2499. // the global list and free it as well.
  2500. //
  2501. if (davSrvOpen->OpaqueLockToken != NULL) {
  2502. ASSERT(WentToTheUserMode == TRUE);
  2503. ASSERT(davSrvOpen->LockTokenEntry != NULL);
  2504. //
  2505. // Remove the LockTokenEntry associated with this OpaqueLockToken from
  2506. // the global LockTokenEntryList.
  2507. //
  2508. ExAcquireResourceExclusiveLite(&(LockTokenEntryListLock), TRUE);
  2509. RemoveEntryList( &(davSrvOpen->LockTokenEntry->listEntry) );
  2510. ExReleaseResourceLite(&(LockTokenEntryListLock));
  2511. //
  2512. // Free the PagedPool that was allocated for the ServerName.
  2513. //
  2514. RxFreePool(davSrvOpen->LockTokenEntry->ServerName);
  2515. davSrvOpen->LockTokenEntry->ServerName = NULL;
  2516. //
  2517. // Free the PagedPool that was allocated for the PathName.
  2518. //
  2519. RxFreePool(davSrvOpen->LockTokenEntry->PathName);
  2520. davSrvOpen->LockTokenEntry->PathName = NULL;
  2521. //
  2522. // Free the PagedPool that was allocated for this LockTokenEntry.
  2523. //
  2524. RxFreePool(davSrvOpen->LockTokenEntry);
  2525. davSrvOpen->LockTokenEntry = NULL;
  2526. //
  2527. // Free the PagedPool that was allocated for this OpaqueLockToken.
  2528. //
  2529. RxFreePool(davSrvOpen->OpaqueLockToken);
  2530. davSrvOpen->OpaqueLockToken = NULL;
  2531. //
  2532. // The file has now been UnLocked on the server.
  2533. //
  2534. DavFcb->FileIsLockedOnTheServer = FALSE;
  2535. }
  2536. DavDbgTrace(DAV_TRACE_DETAIL,
  2537. ("%ld: Leaving MRxDAVCloseSrvOpenContinuation with NtStatus = "
  2538. "%08lx\n", PsGetCurrentThreadId(), NtStatus));
  2539. return(NtStatus);
  2540. }
  2541. NTSTATUS
  2542. MRxDAVGetFullParentDirectoryPath(
  2543. PRX_CONTEXT RxContext,
  2544. PUNICODE_STRING ParentDirName
  2545. )
  2546. /*++
  2547. Routine Description:
  2548. This routine returns the parent directory name of the file on the RxContext including
  2549. server and share.
  2550. Here is an example of the FileName on a file object:
  2551. \;Y:000000000000cdef\www.msnusers.com\dv1@usa.com\files\mydoc.doc
  2552. We want to return the middle part of the FileName:
  2553. \www.msnusers.com\dv1@usa.com\files
  2554. Arguments:
  2555. RxContext - The RDBSS context.
  2556. ParentDirName - The full path name of the parent directory starting from the server.
  2557. Return Value:
  2558. NTSTATUS - The return status for the operation
  2559. --*/
  2560. {
  2561. USHORT i, j;
  2562. NTSTATUS NtStatus = STATUS_SUCCESS;
  2563. PUNICODE_STRING FileName = &RxContext->CurrentIrpSp->FileObject->FileName;
  2564. ParentDirName->Buffer = NULL;
  2565. for (i = 1; i < (FileName->Length / sizeof(WCHAR)); i++) {
  2566. if (FileName->Buffer[i] == L'\\') {
  2567. break;
  2568. }
  2569. }
  2570. if ( i < (FileName->Length / sizeof(WCHAR)) ) {
  2571. for (j = ( (FileName->Length / sizeof(WCHAR)) - 1 ); j > i; j--) {
  2572. if (FileName->Buffer[j] == L'\\') {
  2573. break;
  2574. }
  2575. }
  2576. if (i < j) {
  2577. ParentDirName->Buffer = &FileName->Buffer[i];
  2578. ParentDirName->Length = ParentDirName->MaximumLength = (j - i) * sizeof(WCHAR);
  2579. }
  2580. }
  2581. DavDbgTrace(DAV_TRACE_DETAIL, ("MRxDAVGetFullParentDirectoryPath: ParentDirName: %wZ\n", ParentDirName));
  2582. return NtStatus;
  2583. }
  2584. NTSTATUS
  2585. MRxDAVGetFullDirectoryPath(
  2586. PRX_CONTEXT RxContext,
  2587. PUNICODE_STRING FileName,
  2588. PUNICODE_STRING DirName
  2589. )
  2590. /*++
  2591. Routine Description:
  2592. This routine returns the full directory name including the server and share.
  2593. Arguments:
  2594. RxContext - The RDBSS context.
  2595. FileName - If provided, it will be included in the returned path.
  2596. If not provided, the file name on the file object will be returned.
  2597. DirName - The full path name of the parent directory starting from the server.
  2598. Return Value:
  2599. NTSTATUS - The return status for the operation
  2600. Note:
  2601. If FileName is provided, the caller should free up the the UNICODE buffer.
  2602. --*/
  2603. {
  2604. NTSTATUS NtStatus = STATUS_SUCCESS;
  2605. DirName->Buffer = NULL;
  2606. DirName->Length = DirName->MaximumLength = 0;
  2607. if (FileName == NULL) {
  2608. USHORT i;
  2609. FileName = &RxContext->CurrentIrpSp->FileObject->FileName;
  2610. for (i = 1; i < (FileName->Length / sizeof(WCHAR)); i++) {
  2611. if (FileName->Buffer[i] == L'\\') {
  2612. break;
  2613. }
  2614. }
  2615. if ( i < (FileName->Length / sizeof(WCHAR)) ) {
  2616. DirName->Buffer = &FileName->Buffer[i];
  2617. DirName->Length = DirName->MaximumLength = FileName->Length - i*sizeof(WCHAR);
  2618. }
  2619. } else {
  2620. RxCaptureFcb;
  2621. USHORT NameLength = 0;
  2622. if (FileName->Length == 0) {
  2623. goto EXIT_THE_FUNCTION;
  2624. }
  2625. NameLength = capFcb->pNetRoot->pNetRootName->Length + FileName->Length;
  2626. DirName->Length = DirName->MaximumLength = NameLength;
  2627. DirName->Buffer = RxAllocatePoolWithTag(PagedPool,
  2628. NameLength + sizeof(WCHAR),
  2629. DAV_FILEINFO_POOLTAG);
  2630. if (DirName->Buffer == NULL) {
  2631. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2632. DavDbgTrace(DAV_TRACE_ERROR,
  2633. ("%ld: MRxDAVGetParentDirectory/RxAllocatePool: Error Val"
  2634. " = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  2635. goto EXIT_THE_FUNCTION;
  2636. }
  2637. RtlZeroMemory(DirName->Buffer,NameLength + sizeof(WCHAR));
  2638. RtlCopyMemory(DirName->Buffer,
  2639. capFcb->pNetRoot->pNetRootName->Buffer,
  2640. capFcb->pNetRoot->pNetRootName->Length);
  2641. RtlCopyMemory(&DirName->Buffer[capFcb->pNetRoot->pNetRootName->Length/sizeof(WCHAR)],
  2642. FileName->Buffer,
  2643. FileName->Length);
  2644. }
  2645. EXIT_THE_FUNCTION:
  2646. DavDbgTrace(DAV_TRACE_DETAIL, ("MRxDAVGetFullDirectoryPath: DirName: %wZ\n", DirName));
  2647. return NtStatus;
  2648. }
  2649. NTSTATUS
  2650. MRxDAVCreateEncryptedDirectoryKey(
  2651. PUNICODE_STRING DirName
  2652. )
  2653. /*++
  2654. Routine Description:
  2655. This routine creates the registry key for the encrypted directory.
  2656. Arguments:
  2657. DirName - The full path name of the directory starting from the server.
  2658. Return Value:
  2659. NTSTATUS - The return status for the operation
  2660. --*/
  2661. {
  2662. NTSTATUS Status;
  2663. ULONG i = 0;
  2664. HKEY Key = NULL;
  2665. ULONG RequiredLength = 0;
  2666. UNICODE_STRING UnicodeRegKeyName;
  2667. OBJECT_ATTRIBUTES ObjectAttributes;
  2668. DavDbgTrace(DAV_TRACE_DETAIL, ("MRxDAVCreateEncryptedDirectoryKey: DirName: %wZ\n", DirName));
  2669. RtlInitUnicodeString(&(UnicodeRegKeyName), MRXDAV_ENCRYPTED_DIRECTORY_KEY);
  2670. InitializeObjectAttributes(&(ObjectAttributes),
  2671. &(UnicodeRegKeyName),
  2672. OBJ_CASE_INSENSITIVE,
  2673. NULL,
  2674. NULL);
  2675. Status = ZwOpenKey(&Key, KEY_ALL_ACCESS, &ObjectAttributes);
  2676. if (Status != STATUS_SUCCESS) {
  2677. Status = ZwCreateKey(&Key,
  2678. KEY_ALL_ACCESS,
  2679. &ObjectAttributes,
  2680. 0,
  2681. NULL,
  2682. 0,
  2683. NULL);
  2684. if (Status == STATUS_SUCCESS) {
  2685. Status = ZwSetValueKey(Key,
  2686. DirName,
  2687. 0,
  2688. REG_DWORD,
  2689. &i,
  2690. sizeof(ULONG));
  2691. ZwClose(Key);
  2692. }
  2693. } else {
  2694. Status = ZwQueryValueKey(Key,
  2695. DirName,
  2696. KeyValuePartialInformation,
  2697. NULL,
  2698. 0,
  2699. &(RequiredLength));
  2700. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  2701. Status = ZwSetValueKey(Key,
  2702. DirName,
  2703. 0,
  2704. REG_DWORD,
  2705. &i,
  2706. sizeof(ULONG));
  2707. } else if (Status == STATUS_BUFFER_TOO_SMALL) {
  2708. Status = STATUS_SUCCESS;
  2709. }
  2710. ZwClose(Key);
  2711. }
  2712. if (Status != STATUS_SUCCESS) {
  2713. DavDbgTrace(DAV_TRACE_ERROR,
  2714. ("%ld: ERROR: MRxDAVCreateEncryptedDirectoryKey. NtStatus = "
  2715. "%08lx\n", PsGetCurrentThreadId(), Status));
  2716. }
  2717. return Status;
  2718. }
  2719. NTSTATUS
  2720. MRxDAVRemoveEncryptedDirectoryKey(
  2721. PUNICODE_STRING DirName
  2722. )
  2723. /*++
  2724. Routine Description:
  2725. This routine deletes the registry key for the directory.
  2726. Arguments:
  2727. DirName - The full path name of the directory starting from the server.
  2728. Return Value:
  2729. NTSTATUS - The return status for the operation
  2730. --*/
  2731. {
  2732. NTSTATUS Status;
  2733. ULONG i = 0;
  2734. HKEY Key = NULL;
  2735. ULONG RequiredLength = 0;
  2736. UNICODE_STRING UnicodeRegKeyName;
  2737. OBJECT_ATTRIBUTES ObjectAttributes;
  2738. DavDbgTrace(DAV_TRACE_DETAIL, ("MRxDAVRemoveEncryptedDirectoryKey: DirName: %wZ\n", DirName));
  2739. RtlInitUnicodeString(&(UnicodeRegKeyName), MRXDAV_ENCRYPTED_DIRECTORY_KEY);
  2740. InitializeObjectAttributes(&(ObjectAttributes),
  2741. &(UnicodeRegKeyName),
  2742. OBJ_CASE_INSENSITIVE,
  2743. NULL,
  2744. NULL);
  2745. Status = ZwOpenKey(&Key, KEY_ALL_ACCESS, &ObjectAttributes);
  2746. if (Status == STATUS_SUCCESS) {
  2747. Status = ZwDeleteValueKey(Key,DirName);
  2748. ZwClose(Key);
  2749. }
  2750. if (Status != STATUS_SUCCESS) {
  2751. DavDbgTrace(DAV_TRACE_ERROR,
  2752. ("%ld: ERROR: MRxDAVRemoveEncryptedDirectoryKey. NtStatus = "
  2753. "%08lx\n", PsGetCurrentThreadId(), Status));
  2754. }
  2755. return Status;
  2756. }
  2757. NTSTATUS
  2758. MRxDAVQueryEncryptedDirectoryKey(
  2759. PUNICODE_STRING DirName
  2760. )
  2761. /*++
  2762. Routine Description:
  2763. This routine queries the registry key for the directory.
  2764. Arguments:
  2765. DirName - The full path name of the directory starting from the server.
  2766. Return Value:
  2767. NTSTATUS - The return status for the operation
  2768. --*/
  2769. {
  2770. NTSTATUS Status;
  2771. ULONG i = 0;
  2772. HKEY Key = NULL;
  2773. ULONG RequiredLength = 0;
  2774. UNICODE_STRING UnicodeRegKeyName;
  2775. OBJECT_ATTRIBUTES ObjectAttributes;
  2776. DavDbgTrace(DAV_TRACE_DETAIL, ("MRxDAVQueryEncryptedDirectoryKey: DirName: %wZ\n", DirName));
  2777. RtlInitUnicodeString(&(UnicodeRegKeyName), MRXDAV_ENCRYPTED_DIRECTORY_KEY);
  2778. InitializeObjectAttributes(&(ObjectAttributes),
  2779. &(UnicodeRegKeyName),
  2780. OBJ_CASE_INSENSITIVE,
  2781. NULL,
  2782. NULL);
  2783. Status = ZwOpenKey(&Key, KEY_ALL_ACCESS, &ObjectAttributes);
  2784. if (Status == STATUS_SUCCESS) {
  2785. Status = ZwQueryValueKey(Key,
  2786. DirName,
  2787. KeyValuePartialInformation,
  2788. NULL,
  2789. 0,
  2790. &(RequiredLength));
  2791. if (Status == STATUS_BUFFER_TOO_SMALL) {
  2792. Status = STATUS_SUCCESS;
  2793. }
  2794. ZwClose(Key);
  2795. }
  2796. if (Status != STATUS_SUCCESS) {
  2797. DavDbgTrace(DAV_TRACE_DETAIL,
  2798. ("%ld: ERROR: MRxDAVQueryEncryptedDirectoryKey. NtStatus = "
  2799. "%08lx\n", PsGetCurrentThreadId(), Status));
  2800. }
  2801. return Status;
  2802. }