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.

2570 lines
92 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. fileinfo.c
  5. Abstract:
  6. This module implements the DAV mini redirector call down routines pertaining
  7. to query/set file/volume information.
  8. Author:
  9. Rohan Kumar [RohanK] 27-Sept-1999
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "webdav.h"
  15. #define DEFAULT_BYTES_PER_SECTOR 512
  16. #define DEFAULT_SECTORS_PER_ALLOCATION_UNIT 1
  17. //
  18. // Mentioned below are the prototypes of functions tht are used only within
  19. // this module (file). These functions should not be exposed outside.
  20. //
  21. NTSTATUS
  22. MRxDAVReNameContinuation(
  23. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  24. );
  25. NTSTATUS
  26. MRxDAVFormatUserModeReNameRequest(
  27. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  28. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  29. ULONG WorkItemLength,
  30. PULONG_PTR ReturnedLength
  31. );
  32. BOOL
  33. MRxDAVPrecompleteUserModeReNameRequest(
  34. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  35. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  36. ULONG WorkItemLength,
  37. BOOL OperationCancelled
  38. );
  39. NTSTATUS
  40. MRxDAVSetFileInformationContinuation(
  41. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  42. );
  43. NTSTATUS
  44. MRxDAVFormatUserModeSetFileInformationRequest(
  45. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  46. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  47. ULONG WorkItemLength,
  48. PULONG_PTR ReturnedLength
  49. );
  50. BOOL
  51. MRxDAVPrecompleteUserModeSetFileInformationRequest(
  52. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  53. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  54. ULONG WorkItemLength,
  55. BOOL OperationCancelled
  56. );
  57. NTSTATUS
  58. MRxDAVQueryVolumeInformationContinuation(
  59. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  60. );
  61. NTSTATUS
  62. MRxDAVFormatUserModeQueryVolumeInformationRequest(
  63. IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  64. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  65. IN ULONG WorkItemLength,
  66. OUT PULONG_PTR ReturnedLength
  67. );
  68. BOOL
  69. MRxDAVPrecompleteUserModeQueryVolumeInformationRequest(
  70. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  71. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  72. ULONG WorkItemLength,
  73. BOOL OperationCancelled
  74. );
  75. BOOL
  76. DavIsValidDate(
  77. PLARGE_INTEGER pFileTime
  78. );
  79. #ifdef ALLOC_PRAGMA
  80. #pragma alloc_text(PAGE, MRxDAVQueryVolumeInformation)
  81. #pragma alloc_text(PAGE, MRxDAVQueryFileInformation)
  82. #pragma alloc_text(PAGE, MRxDAVSetFileInformation)
  83. #pragma alloc_text(PAGE, MRxDAVReNameContinuation)
  84. #pragma alloc_text(PAGE, MRxDAVFormatUserModeReNameRequest)
  85. #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeReNameRequest)
  86. #pragma alloc_text(PAGE, MRxDAVSetFileInformationContinuation)
  87. #pragma alloc_text(PAGE, MRxDAVFormatUserModeSetFileInformationRequest)
  88. #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeSetFileInformationRequest)
  89. #pragma alloc_text(PAGE, MRxDAVQueryVolumeInformationContinuation)
  90. #pragma alloc_text(PAGE, MRxDAVFormatUserModeQueryVolumeInformationRequest)
  91. #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeQueryVolumeInformationRequest)
  92. #pragma alloc_text(PAGE, DavIsValidDate)
  93. #pragma alloc_text(PAGE, MRxDAVIsValidDirectory)
  94. #endif
  95. //
  96. // Implementation of functions begins here.
  97. //
  98. NTSTATUS
  99. MRxDAVQueryVolumeInformation(
  100. IN PRX_CONTEXT RxContext
  101. )
  102. /*++
  103. Routine Description:
  104. This routine handles query volume info requests for the DAV MiniRedir.
  105. Arguments:
  106. RxContext - The RDBSS context.
  107. Return Value:
  108. RXSTATUS - The return status for the operation
  109. --*/
  110. {
  111. NTSTATUS NtStatus = STATUS_SUCCESS;
  112. FS_INFORMATION_CLASS FsInfoClass;
  113. PVOID Buffer;
  114. ULONG BufferLength = 0, BufferLengthUsed = 0;
  115. PFILE_FS_SIZE_INFORMATION FileFsSizeInfo = NULL;
  116. PFILE_FS_FULL_SIZE_INFORMATION FileFsFullSizeInfo = NULL;
  117. PFILE_FS_VOLUME_INFORMATION FileFsVolInfo = NULL;
  118. PFILE_FS_DEVICE_INFORMATION FileFsDeviceInfo = NULL;
  119. PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttributeInfo = NULL;
  120. RxCaptureFcb;
  121. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  122. BOOLEAN SynchronousIo = FALSE;
  123. OBJECT_ATTRIBUTES ObjectAttributes;
  124. HANDLE FileHandle = NULL;
  125. IO_STATUS_BLOCK IoStatusBlock;
  126. UNICODE_STRING UnicodeFileName;
  127. PWCHAR NtFileName = NULL;
  128. FILE_FS_FULL_SIZE_INFORMATION SizeInfo;
  129. ULONG SizeInBytes = 0;
  130. PWEBDAV_V_NET_ROOT DavVNetRoot = (PWEBDAV_V_NET_ROOT)RxContext->pRelevantSrvOpen->pVNetRoot->Context;
  131. PAGED_CODE();
  132. FsInfoClass = RxContext->Info.FsInformationClass;
  133. BufferLength = RxContext->Info.LengthRemaining;
  134. Buffer = RxContext->Info.Buffer;
  135. DavDbgTrace(DAV_TRACE_DETAIL,
  136. ("%ld: MRxDAVQueryVolumeInformation. FsInfoClass = %d.\n",
  137. PsGetCurrentThreadId(), FsInfoClass));
  138. if ( FsInfoClass == FileFsSizeInformation ||
  139. FsInfoClass == FileFsFullSizeInformation ) {
  140. //
  141. // If the Driver initialization went smoothly then DavWinInetCachePath
  142. // should be containing the WinInetCachePath value.
  143. //
  144. ASSERT(DavWinInetCachePath[0] != L'\0');
  145. DavDbgTrace(DAV_TRACE_DETAIL,
  146. ("%ld: MRxDAVQueryVolumeInformation: DavWinInetCachePath: %ws\n",
  147. PsGetCurrentThreadId(), DavWinInetCachePath));
  148. //
  149. // Create an NT path name for the cached file. This is used in the
  150. // NtCreateFile call below. If c:\foo\bar is the DOA path name,
  151. // the NT path name is \??\c:\foo\bar.
  152. //
  153. SizeInBytes = ( MAX_PATH + wcslen(L"\\??\\") + 1 ) * sizeof(WCHAR);
  154. NtFileName = RxAllocatePoolWithTag(PagedPool, SizeInBytes, DAV_FILENAME_POOLTAG);
  155. if (NtFileName == NULL) {
  156. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  157. DavDbgTrace(DAV_TRACE_ERROR,
  158. ("%ld: MRxDAVQueryVolumeInformation/RxAllocatePool: Error Val"
  159. " = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  160. goto EXIT_THE_FUNCTION;
  161. }
  162. RtlZeroMemory(NtFileName, SizeInBytes);
  163. wcscpy( NtFileName, L"\\??\\" );
  164. wcscpy( &(NtFileName[4]), DavWinInetCachePath );
  165. DavDbgTrace(DAV_TRACE_DETAIL,
  166. ("%ld: MRxDAVQueryVolumeInformation: NtFileName = %ws\n",
  167. PsGetCurrentThreadId(), NtFileName));
  168. RtlInitUnicodeString( &(UnicodeFileName), NtFileName );
  169. InitializeObjectAttributes(&(ObjectAttributes),
  170. &(UnicodeFileName),
  171. OBJ_CASE_INSENSITIVE,
  172. NULL,
  173. NULL);
  174. NtStatus = ZwOpenFile(&(FileHandle),
  175. (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
  176. &(ObjectAttributes),
  177. &(IoStatusBlock),
  178. FILE_SHARE_READ | FILE_SHARE_WRITE,
  179. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_FREE_SPACE_QUERY);
  180. if ( !NT_SUCCESS(NtStatus) ) {
  181. FileHandle = NULL;
  182. DavDbgTrace(DAV_TRACE_ERROR,
  183. ("%ld: ERROR: MRxDAVQueryVolumeInformation/NtOpenFile: "
  184. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  185. goto EXIT_THE_FUNCTION;
  186. }
  187. NtStatus = ZwQueryVolumeInformationFile(FileHandle,
  188. &(IoStatusBlock),
  189. &(SizeInfo),
  190. sizeof(SizeInfo),
  191. FileFsFullSizeInformation);
  192. if ( !NT_SUCCESS(NtStatus) ) {
  193. NtStatus = IoStatusBlock.Status;
  194. DavDbgTrace(DAV_TRACE_ERROR,
  195. ("%ld: ERROR: MRxDAVQueryVolumeInformation/NtQueryVolumeInformationFile: "
  196. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  197. goto EXIT_THE_FUNCTION;
  198. }
  199. }
  200. switch (FsInfoClass) {
  201. case FileFsVolumeInformation:
  202. if ( BufferLength < sizeof(FILE_FS_VOLUME_INFORMATION) ) {
  203. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  204. DavDbgTrace(DAV_TRACE_ERROR,
  205. ("%ld: ERROR: MRxDAVQueryVolumeInformation. Insufficient Buffer.\n",
  206. PsGetCurrentThreadId()));
  207. break;
  208. }
  209. FileFsVolInfo = (PFILE_FS_VOLUME_INFORMATION)Buffer;
  210. FileFsVolInfo->VolumeCreationTime.LowPart = 0;
  211. FileFsVolInfo->VolumeCreationTime.HighPart = 0;
  212. FileFsVolInfo->VolumeSerialNumber = 0;
  213. FileFsVolInfo->SupportsObjects = FALSE;
  214. FileFsVolInfo->VolumeLabelLength = 0;
  215. FileFsVolInfo->VolumeLabel[0] = 0;
  216. BufferLengthUsed += sizeof(FILE_FS_VOLUME_INFORMATION);
  217. break;
  218. case FileFsSizeInformation:
  219. if ( BufferLength < sizeof(FILE_FS_SIZE_INFORMATION) ) {
  220. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  221. DavDbgTrace(DAV_TRACE_ERROR,
  222. ("%ld: ERROR: MRxDAVQueryVolumeInformation. Insufficient Buffer.\n",
  223. PsGetCurrentThreadId()));
  224. break;
  225. }
  226. if (!DavVNetRoot->fReportsAvailableSpace)
  227. {
  228. FileFsSizeInfo = (PFILE_FS_SIZE_INFORMATION)Buffer;
  229. FileFsSizeInfo->AvailableAllocationUnits.LowPart = SizeInfo.ActualAvailableAllocationUnits.LowPart;
  230. FileFsSizeInfo->AvailableAllocationUnits.HighPart = SizeInfo.ActualAvailableAllocationUnits.HighPart;
  231. FileFsSizeInfo->BytesPerSector = SizeInfo.BytesPerSector;
  232. FileFsSizeInfo->SectorsPerAllocationUnit = SizeInfo.SectorsPerAllocationUnit;
  233. FileFsSizeInfo->TotalAllocationUnits.LowPart = SizeInfo.TotalAllocationUnits.LowPart;
  234. FileFsSizeInfo->TotalAllocationUnits.HighPart = SizeInfo.TotalAllocationUnits.HighPart;
  235. BufferLengthUsed += sizeof(FILE_FS_SIZE_INFORMATION);
  236. }
  237. else
  238. {
  239. NtStatus = UMRxAsyncEngOuterWrapper(RxContext,
  240. SIZEOF_DAV_SPECIFIC_CONTEXT,
  241. MRxDAVFormatTheDAVContext,
  242. (USHORT)DAV_MINIRDR_ENTRY_FROM_QUERYVOLUMEINFORMATION,
  243. MRxDAVQueryVolumeInformationContinuation,
  244. "MRxDAVQueryVolumeInformation");
  245. if (NtStatus == STATUS_SUCCESS)
  246. {
  247. BufferLengthUsed += sizeof(FILE_FS_SIZE_INFORMATION);
  248. }
  249. }
  250. break;
  251. case FileFsFullSizeInformation:
  252. if ( BufferLength < sizeof(FILE_FS_FULL_SIZE_INFORMATION) ) {
  253. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  254. DavDbgTrace(DAV_TRACE_ERROR,
  255. ("%ld: ERROR: MRxDAVQueryVolumeInformation. Insufficient Buffer.\n",
  256. PsGetCurrentThreadId()));
  257. break;
  258. }
  259. if (!DavVNetRoot->fReportsAvailableSpace)
  260. {
  261. FileFsFullSizeInfo = (PFILE_FS_FULL_SIZE_INFORMATION)Buffer;
  262. FileFsFullSizeInfo->ActualAvailableAllocationUnits.LowPart = SizeInfo.ActualAvailableAllocationUnits.LowPart;
  263. FileFsFullSizeInfo->ActualAvailableAllocationUnits.HighPart = SizeInfo.ActualAvailableAllocationUnits.HighPart;
  264. FileFsFullSizeInfo->BytesPerSector = SizeInfo.BytesPerSector;
  265. FileFsFullSizeInfo->CallerAvailableAllocationUnits.LowPart = SizeInfo.CallerAvailableAllocationUnits.LowPart;
  266. FileFsFullSizeInfo->CallerAvailableAllocationUnits.HighPart = SizeInfo.CallerAvailableAllocationUnits.HighPart;
  267. FileFsFullSizeInfo->SectorsPerAllocationUnit = SizeInfo.SectorsPerAllocationUnit;
  268. FileFsFullSizeInfo->TotalAllocationUnits.LowPart = SizeInfo.TotalAllocationUnits.LowPart;
  269. FileFsFullSizeInfo->TotalAllocationUnits.HighPart = SizeInfo.TotalAllocationUnits.HighPart;
  270. BufferLengthUsed += sizeof(FILE_FS_FULL_SIZE_INFORMATION);
  271. }
  272. else
  273. {
  274. NtStatus = UMRxAsyncEngOuterWrapper(RxContext,
  275. SIZEOF_DAV_SPECIFIC_CONTEXT,
  276. MRxDAVFormatTheDAVContext,
  277. (USHORT)DAV_MINIRDR_ENTRY_FROM_QUERYVOLUMEINFORMATION,
  278. MRxDAVQueryVolumeInformationContinuation,
  279. "MRxDAVQueryVolumeInformation");
  280. if (NtStatus == STATUS_SUCCESS)
  281. {
  282. BufferLengthUsed += sizeof(FILE_FS_FULL_SIZE_INFORMATION);
  283. }
  284. }
  285. break;
  286. case FileFsDeviceInformation:
  287. if ( BufferLength < sizeof(FILE_FS_DEVICE_INFORMATION) ) {
  288. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  289. DavDbgTrace(DAV_TRACE_ERROR,
  290. ("%ld: ERROR: MRxDAVQueryVolumeInformation. Insufficient Buffer.\n",
  291. PsGetCurrentThreadId()));
  292. break;
  293. }
  294. FileFsDeviceInfo = (PFILE_FS_DEVICE_INFORMATION)Buffer;
  295. DavDbgTrace(DAV_TRACE_DETAIL,
  296. ("%ld: MRxDAVQueryVolumeInformation. DeviceType = %d.\n",
  297. PsGetCurrentThreadId(), NetRoot->DeviceType));
  298. FileFsDeviceInfo->DeviceType = NetRoot->DeviceType;
  299. FileFsDeviceInfo->Characteristics = FILE_REMOTE_DEVICE;
  300. BufferLengthUsed += sizeof(FILE_FS_DEVICE_INFORMATION);
  301. break;
  302. case FileFsAttributeInformation: {
  303. ULONG LengthNeeded, FileSystemNameLength;
  304. LengthNeeded = sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
  305. LengthNeeded += ( wcslen(DD_DAV_FILESYS_NAME_U) * sizeof(WCHAR) );
  306. if ( BufferLength < LengthNeeded ) {
  307. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  308. DavDbgTrace(DAV_TRACE_ERROR,
  309. ("%ld: ERROR: MRxDAVQueryVolumeInformation. Insufficient Buffer.\n",
  310. PsGetCurrentThreadId()));
  311. break;
  312. }
  313. FileFsAttributeInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
  314. FileFsAttributeInfo->FileSystemAttributes = (FILE_CASE_PRESERVED_NAMES | FILE_SUPPORTS_ENCRYPTION);
  315. FileFsAttributeInfo->MaximumComponentNameLength = 255;
  316. FileSystemNameLength = ( 1 + wcslen(DD_DAV_FILESYS_NAME_U) ) * sizeof(WCHAR);
  317. FileFsAttributeInfo->FileSystemNameLength = FileSystemNameLength;
  318. wcscpy(&(FileFsAttributeInfo->FileSystemName[0]), DD_DAV_FILESYS_NAME_U);
  319. BufferLengthUsed += LengthNeeded;
  320. }
  321. break;
  322. default:
  323. DavDbgTrace(DAV_TRACE_ERROR,
  324. ("%ld: ERROR: MRxDAVQueryVolumeInformation. FsInfoClass = %d.\n",
  325. PsGetCurrentThreadId(), FsInfoClass));
  326. NtStatus = STATUS_NOT_IMPLEMENTED;
  327. break;
  328. }
  329. EXIT_THE_FUNCTION:
  330. RxContext->Info.LengthRemaining -= BufferLengthUsed;
  331. //
  332. // Close the handle if we opened the handle to the WinInetCachePath.
  333. //
  334. if (FileHandle) {
  335. NtClose(FileHandle);
  336. }
  337. //
  338. // Free the NtFileName buffer if we allocated one.
  339. //
  340. if (NtFileName) {
  341. RxFreePool(NtFileName);
  342. }
  343. return NtStatus;
  344. }
  345. NTSTATUS
  346. MRxDAVQueryFileInformation(
  347. IN PRX_CONTEXT RxContext
  348. )
  349. /*++
  350. Routine Description:
  351. This routine handles query file info requests for the DAV mini--redir.
  352. Arguments:
  353. RxContext - The RDBSS context.
  354. Return Value:
  355. RXSTATUS - The return status for the operation
  356. --*/
  357. {
  358. NTSTATUS NtStatus = STATUS_SUCCESS;
  359. FS_INFORMATION_CLASS FsInfoClass;
  360. PFCB thisFcb = NULL;
  361. PVOID Buffer = NULL;
  362. ULONG BufferLength = 0, BufferLengthUsed = 0, fileAttributes = 0;
  363. PFILE_BASIC_INFORMATION FileBasicInfo = NULL;
  364. PFILE_STANDARD_INFORMATION FileStandardInfo = NULL;
  365. PFILE_INTERNAL_INFORMATION FileInternalInfo = NULL;
  366. PFILE_EA_INFORMATION FileEaInfo = NULL;
  367. PFILE_ATTRIBUTE_TAG_INFORMATION FileAttTagInfo = NULL;
  368. PFILE_NAME_INFORMATION FileAltNameInfo = NULL;
  369. PFILE_STREAM_INFORMATION FileStreamInfo = NULL;
  370. PAGED_CODE();
  371. FsInfoClass = RxContext->Info.FsInformationClass;
  372. BufferLength = RxContext->Info.LengthRemaining;
  373. Buffer = RxContext->Info.Buffer;
  374. thisFcb = (PFCB)RxContext->pFcb;
  375. //
  376. // If the file attributes is 0, then we set return FILE_ATTRIBUTE_ARCHIVE.
  377. // We fake this since the apps expect this.
  378. //
  379. fileAttributes = thisFcb->Attributes;
  380. if (fileAttributes == 0) {
  381. fileAttributes = FILE_ATTRIBUTE_ARCHIVE;
  382. }
  383. DavDbgTrace(DAV_TRACE_DETAIL,
  384. ("%ld: MRxDAVQueryFileInformation. FsInfoClass = %d.\n",
  385. PsGetCurrentThreadId(), FsInfoClass));
  386. switch (FsInfoClass) {
  387. case FileBasicInformation:
  388. FileBasicInfo = (PFILE_BASIC_INFORMATION)Buffer;
  389. if ( BufferLength < sizeof(FILE_BASIC_INFORMATION) ) {
  390. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  391. DavDbgTrace(DAV_TRACE_ERROR,
  392. ("%ld: ERROR: MRxDAVQueryFileInformation. Insufficient Buffer.\n",
  393. PsGetCurrentThreadId()));
  394. break;
  395. }
  396. FileBasicInfo->ChangeTime.LowPart = thisFcb->LastChangeTime.LowPart;
  397. FileBasicInfo->ChangeTime.HighPart = thisFcb->LastChangeTime.HighPart;
  398. FileBasicInfo->CreationTime.LowPart = thisFcb->CreationTime.LowPart;
  399. FileBasicInfo->CreationTime.HighPart = thisFcb->CreationTime.HighPart;
  400. FileBasicInfo->LastAccessTime.LowPart = thisFcb->LastAccessTime.LowPart;
  401. FileBasicInfo->LastAccessTime.HighPart = thisFcb->LastAccessTime.HighPart;
  402. FileBasicInfo->LastWriteTime.LowPart = thisFcb->LastWriteTime.LowPart;
  403. FileBasicInfo->LastWriteTime.HighPart = thisFcb->LastWriteTime.HighPart;
  404. FileBasicInfo->FileAttributes = fileAttributes;
  405. BufferLengthUsed += sizeof(FILE_BASIC_INFORMATION);
  406. break;
  407. case FileStandardInformation:
  408. FileStandardInfo = (PFILE_STANDARD_INFORMATION)Buffer;
  409. if ( BufferLength < sizeof(FILE_STANDARD_INFORMATION) ) {
  410. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  411. DavDbgTrace(DAV_TRACE_ERROR,
  412. ("%ld: ERROR: MRxDAVQueryFileInformation. Insufficient Buffer.\n",
  413. PsGetCurrentThreadId()));
  414. break;
  415. }
  416. FileStandardInfo->AllocationSize.LowPart = thisFcb->Header.AllocationSize.LowPart;
  417. FileStandardInfo->AllocationSize.HighPart = thisFcb->Header.AllocationSize.HighPart;
  418. FileStandardInfo->EndOfFile.LowPart = thisFcb->Header.FileSize.LowPart;
  419. FileStandardInfo->EndOfFile.HighPart = thisFcb->Header.FileSize.HighPart;
  420. FileStandardInfo->DeletePending = 0;
  421. FileStandardInfo->Directory = (BOOLEAN)(fileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  422. FileStandardInfo->NumberOfLinks = thisFcb->NumberOfLinks;
  423. BufferLengthUsed += sizeof(FILE_STANDARD_INFORMATION);
  424. break;
  425. case FileInternalInformation:
  426. FileInternalInfo = (PFILE_INTERNAL_INFORMATION)Buffer;
  427. if ( BufferLength < sizeof(FILE_INTERNAL_INFORMATION) ) {
  428. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  429. DavDbgTrace(DAV_TRACE_ERROR,
  430. ("%ld: ERROR: MRxDAVQueryFileInformation. Insufficient Buffer.\n",
  431. PsGetCurrentThreadId()));
  432. break;
  433. }
  434. FileInternalInfo->IndexNumber.LowPart = 0;
  435. FileInternalInfo->IndexNumber.HighPart = 0;
  436. BufferLengthUsed += sizeof(FILE_INTERNAL_INFORMATION);
  437. break;
  438. case FileEaInformation:
  439. FileEaInfo = (PFILE_EA_INFORMATION)Buffer;
  440. if ( BufferLength < sizeof(FILE_EA_INFORMATION) ) {
  441. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  442. DavDbgTrace(DAV_TRACE_ERROR,
  443. ("%ld: ERROR: MRxDAVQueryFileInformation. Insufficient Buffer.\n",
  444. PsGetCurrentThreadId()));
  445. break;
  446. }
  447. FileEaInfo->EaSize = 0;
  448. BufferLengthUsed += sizeof(FILE_EA_INFORMATION);
  449. break;
  450. case FileAttributeTagInformation:
  451. FileAttTagInfo = (PFILE_ATTRIBUTE_TAG_INFORMATION)Buffer;
  452. if ( BufferLength < sizeof(FILE_ATTRIBUTE_TAG_INFORMATION) ) {
  453. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  454. DavDbgTrace(DAV_TRACE_ERROR,
  455. ("%ld: ERROR: MRxDAVQueryFileInformation. Insufficient Buffer.\n",
  456. PsGetCurrentThreadId()));
  457. break;
  458. }
  459. FileAttTagInfo->FileAttributes = fileAttributes;
  460. FileAttTagInfo->ReparseTag = 0;
  461. BufferLengthUsed += sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
  462. break;
  463. case FileAlternateNameInformation:
  464. FileAltNameInfo = (PFILE_NAME_INFORMATION)Buffer;
  465. if ( BufferLength < sizeof(FILE_NAME_INFORMATION) ) {
  466. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  467. DavDbgTrace(DAV_TRACE_ERROR,
  468. ("%ld: ERROR: MRxDAVQueryFileInformation. Insufficient Buffer.\n",
  469. PsGetCurrentThreadId()));
  470. break;
  471. }
  472. //
  473. // We don't return any alternate names.
  474. //
  475. FileAltNameInfo->FileNameLength = 0;
  476. FileAltNameInfo->FileName[0] = L'\0';
  477. BufferLengthUsed += sizeof(FILE_NAME_INFORMATION);
  478. break;
  479. case FileStreamInformation: {
  480. FileStreamInfo = (PFILE_STREAM_INFORMATION)Buffer;
  481. if ( BufferLength < sizeof(FILE_STREAM_INFORMATION) + 6 * sizeof(WCHAR) ) {
  482. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  483. DavDbgTrace(DAV_TRACE_ERROR,
  484. ("%ld: ERROR: MRxDAVQueryFileInformation. Insufficient Buffer.\n",
  485. PsGetCurrentThreadId()));
  486. break;
  487. }
  488. // Return the default stream information of the dav file
  489. FileStreamInfo->NextEntryOffset = 0;
  490. FileStreamInfo->StreamNameLength = 7 * sizeof(WCHAR);
  491. FileStreamInfo->StreamSize.QuadPart = thisFcb->Header.FileSize.QuadPart;
  492. FileStreamInfo->StreamAllocationSize.QuadPart = thisFcb->Header.AllocationSize.QuadPart;
  493. RtlCopyMemory(&FileStreamInfo->StreamName[0], L"::$DATA", 7 * sizeof(WCHAR));
  494. BufferLengthUsed += sizeof(FILE_STREAM_INFORMATION) + 6 * sizeof(WCHAR);
  495. /*
  496. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  497. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  498. NtStatus = DavXxxInformation(IRP_MJ_QUERY_INFORMATION,
  499. davSrvOpen->UnderlyingFileObject,
  500. FileStreamInformation,
  501. RxContext->Info.Length,
  502. RxContext->Info.Buffer,
  503. NULL);*/
  504. }
  505. break;
  506. default:
  507. DavDbgTrace(DAV_TRACE_ERROR,
  508. ("%ld: ERROR: MRxDAVQueryFileInformation. FsInfoClass = %d.\n",
  509. PsGetCurrentThreadId(), FsInfoClass));
  510. NtStatus = STATUS_NOT_IMPLEMENTED;
  511. break;
  512. }
  513. RxContext->Info.LengthRemaining -= BufferLengthUsed;
  514. return NtStatus;
  515. }
  516. NTSTATUS
  517. MRxDAVSetFileInformation(
  518. IN PRX_CONTEXT RxContext
  519. )
  520. /*++
  521. Routine Description:
  522. This routine handles query file info requests for the DAV mini--redir.
  523. Arguments:
  524. RxContext - The RDBSS context.
  525. Return Value:
  526. RXSTATUS - The return status for the operation
  527. --*/
  528. {
  529. NTSTATUS NtStatus = STATUS_SUCCESS;
  530. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  531. PFCB thisFcb = NULL;
  532. PWEBDAV_FCB DavFcb = MRxDAVGetFcbExtension(SrvOpen->pFcb);
  533. FILE_INFORMATION_CLASS FileInformationClass;
  534. PVOID Buffer = NULL;
  535. PFILE_DISPOSITION_INFORMATION FileDispInfo = NULL;
  536. PFILE_RENAME_INFORMATION FileRenInfo = NULL;
  537. PFILE_END_OF_FILE_INFORMATION FileEOFInfo = NULL;
  538. PFILE_BASIC_INFORMATION FileBasicInfo = NULL;
  539. PFILE_ALLOCATION_INFORMATION FileAllocInfo = NULL;
  540. PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
  541. BOOLEAN FileAttributesChanged = FALSE;
  542. PAGED_CODE();
  543. FileInformationClass = RxContext->Info.FileInformationClass;
  544. Buffer = RxContext->Info.Buffer;
  545. thisFcb = (PFCB)RxContext->pFcb;
  546. DavVNetRoot = (PWEBDAV_V_NET_ROOT)SrvOpen->pVNetRoot->Context;
  547. DavDbgTrace(DAV_TRACE_DETAIL,
  548. ("%ld: MRxDAVSetFileInformation: FileInformationClass = %d\n",
  549. PsGetCurrentThreadId(), FileInformationClass));
  550. switch (FileInformationClass) {
  551. case FileDispositionInformation:
  552. FileDispInfo = (PFILE_DISPOSITION_INFORMATION)Buffer;
  553. //
  554. // If we have been asked to delete this file or directory and its read
  555. // only, then we return STATUS_CANNOT_DELETE.
  556. //
  557. if ( FileDispInfo->DeleteFile && (thisFcb->Attributes & (FILE_ATTRIBUTE_READONLY)) ) {
  558. DavDbgTrace(DAV_TRACE_ERROR,
  559. ("%ld: MRxDAvSetFileInformation: STATUS_CANNOT_DELETE %wZ\n",
  560. PsGetCurrentThreadId(), SrvOpen->pAlreadyPrefixedName));
  561. NtStatus = STATUS_CANNOT_DELETE;
  562. goto EXIT_THE_FUNCTION;
  563. }
  564. if (FileDispInfo->DeleteFile) {
  565. DavDbgTrace(DAV_TRACE_DETAIL,
  566. ("%ld: MRxDAvSetFileInformation: DELETE %wZ\n",
  567. PsGetCurrentThreadId(), SrvOpen->pAlreadyPrefixedName));
  568. }
  569. //
  570. // This file needs to be deleted on close OR a previous delete of this
  571. // file is being nullified.
  572. //
  573. DavFcb->DeleteOnClose = ( (FileDispInfo->DeleteFile == TRUE) ? TRUE : FALSE );
  574. break;
  575. case FileRenameInformation:
  576. FileRenInfo = (PFILE_RENAME_INFORMATION)Buffer;
  577. DavDbgTrace(DAV_TRACE_DETAIL,
  578. ("%ld: MRxDAvSetFileInformation: NewFileName = %ws\n",
  579. PsGetCurrentThreadId(), FileRenInfo->FileName));
  580. //
  581. // If the FileNameLength is greater than (MAX_PATH * sizeof(WCHAR)),
  582. // we return STATUS_NAME_TOO_LONG since the NewFileName in the FCB
  583. // cannot hold names greater than this size.
  584. //
  585. if ( FileRenInfo->FileNameLength > (MAX_PATH * sizeof(WCHAR)) ) {
  586. DavDbgTrace(DAV_TRACE_ERROR,
  587. ("%ld: MRxDAvSetFileInformation: STATUS_NAME_TOO_LONG %wZ\n",
  588. PsGetCurrentThreadId(), SrvOpen->pAlreadyPrefixedName));
  589. NtStatus = STATUS_NAME_TOO_LONG;
  590. goto EXIT_THE_FUNCTION;
  591. }
  592. //
  593. // Copy the new file name.
  594. //
  595. RtlCopyMemory(DavFcb->NewFileName, FileRenInfo->FileName, FileRenInfo->FileNameLength);
  596. DavFcb->NewFileNameLength = FileRenInfo->FileNameLength;
  597. NtStatus = UMRxAsyncEngOuterWrapper(RxContext,
  598. SIZEOF_DAV_SPECIFIC_CONTEXT,
  599. MRxDAVFormatTheDAVContext,
  600. DAV_MINIRDR_ENTRY_FROM_RENAME,
  601. MRxDAVReNameContinuation,
  602. "MRxDAVSetFileInformation");
  603. if (NtStatus != ERROR_SUCCESS) {
  604. DavDbgTrace(DAV_TRACE_ERROR,
  605. ("%ld: ERROR: MRxDAVSetFileInformation/UMRxAsyncEngOuterWrapper: "
  606. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  607. } else {
  608. //
  609. // We need to set this value in the DAV Fcb. We look at this value on
  610. // Close to figure out the new file name to do the PUT on.
  611. //
  612. DavFcb->FileWasRenamed = TRUE;
  613. //
  614. // Create the name based file not found cache.
  615. //
  616. MRxDAVCacheFileNotFound(RxContext);
  617. //
  618. // Invalidate the file not found cache for the new name if it exists.
  619. //
  620. MRxDAVInvalidateFileNotFoundCacheForRename(RxContext);
  621. MRxDAVInvalidateFileInfoCache(RxContext);
  622. if ((thisFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) &&
  623. (thisFcb->Attributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  624. UNICODE_STRING DirName;
  625. UNICODE_STRING RenameName;
  626. PFILE_RENAME_INFORMATION RenameInformation = RxContext->Info.Buffer;
  627. //
  628. // Remove the old directory name from the registry
  629. //
  630. MRxDAVRemoveEncryptedDirectoryKey(&DavFcb->FileNameInfo);
  631. RenameName.Buffer = &RenameInformation->FileName[0];
  632. RenameName.Length = (USHORT)RenameInformation->FileNameLength;
  633. NtStatus = MRxDAVGetFullDirectoryPath(RxContext,&RenameName,&DirName);
  634. if (NtStatus != STATUS_SUCCESS) {
  635. goto EXIT_THE_FUNCTION;
  636. }
  637. if (DirName.Buffer != NULL) {
  638. //
  639. // Create the new directory in the registry
  640. //
  641. NtStatus = MRxDAVCreateEncryptedDirectoryKey(&DirName);
  642. // The buffer was allocated in MRxDAVGetFullDirectoryPath
  643. RxFreePool(DirName.Buffer);
  644. }
  645. }
  646. }
  647. break;
  648. case FileEndOfFileInformation: {
  649. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  650. //
  651. // If the FileEndOfFileInformation is being done on a directory,
  652. // return STATUS_INVALID_PARAMETER since it doesn't make sense to
  653. // do this.
  654. //
  655. if (DavFcb->isDirectory) {
  656. NtStatus = STATUS_INVALID_PARAMETER;
  657. goto EXIT_THE_FUNCTION;
  658. }
  659. NtStatus = DavXxxInformation(IRP_MJ_SET_INFORMATION,
  660. davSrvOpen->UnderlyingFileObject,
  661. FileEndOfFileInformation,
  662. RxContext->Info.Length,
  663. RxContext->Info.Buffer,
  664. NULL);
  665. if (NtStatus == STATUS_SUCCESS) {
  666. thisFcb->Header.FileSize = ((PFILE_END_OF_FILE_INFORMATION)(RxContext->Info.Buffer))->EndOfFile;
  667. InterlockedExchange(&(DavFcb->FileWasModified), 1);
  668. DavFcb->DoNotTakeTheCurrentTimeAsLMT = FALSE;
  669. MRxDAVUpdateFileInfoCacheFileSize(RxContext,&thisFcb->Header.FileSize);
  670. } else {
  671. DavDbgTrace(DAV_TRACE_ERROR,
  672. ("%ld: ERROR: MRxDAvSetFileInformation/DavXxxInformation"
  673. ". FileInfoClass = %d\n", PsGetCurrentThreadId(), FileInformationClass));
  674. }
  675. }
  676. break;
  677. case FileBasicInformation:
  678. if (!DavVNetRoot->fAllowsProppatch) {
  679. NtStatus = STATUS_ACCESS_DENIED;
  680. break;
  681. }
  682. FileBasicInfo = (PFILE_BASIC_INFORMATION)Buffer;
  683. //
  684. // If the user specified -1 for a field, it means that we should leave
  685. // the field unchanged. We set the field to 0 then so we know not to
  686. // actually set the field to the user-specified (in this case, illegal)
  687. // value.
  688. //
  689. if (FileBasicInfo->LastWriteTime.QuadPart == -1) {
  690. FileBasicInfo->LastWriteTime.QuadPart = 0;
  691. }
  692. if (FileBasicInfo->LastAccessTime.QuadPart == -1) {
  693. FileBasicInfo->LastAccessTime.QuadPart = 0;
  694. }
  695. if (FileBasicInfo->CreationTime.QuadPart == -1) {
  696. FileBasicInfo->CreationTime.QuadPart = 0;
  697. }
  698. //
  699. // Let us first find what changed, we will try to change it on the server
  700. // if that succeeds, we will set it on the FCB.
  701. //
  702. if (FileBasicInfo->ChangeTime.QuadPart != 0) {
  703. if (!DavIsValidDate(&FileBasicInfo->ChangeTime)) {
  704. NtStatus = STATUS_INVALID_PARAMETER;
  705. break;
  706. }
  707. if ((thisFcb->LastChangeTime.LowPart != FileBasicInfo->ChangeTime.LowPart)||
  708. (thisFcb->LastChangeTime.HighPart != FileBasicInfo->ChangeTime.HighPart)) {
  709. thisFcb->LastChangeTime.LowPart = FileBasicInfo->ChangeTime.LowPart;
  710. thisFcb->LastChangeTime.HighPart = FileBasicInfo->ChangeTime.HighPart;
  711. }
  712. }
  713. if (FileBasicInfo->CreationTime.QuadPart != 0) {
  714. if (!DavIsValidDate(&FileBasicInfo->CreationTime)) {
  715. NtStatus = STATUS_INVALID_PARAMETER;
  716. break;
  717. }
  718. if ((thisFcb->CreationTime.LowPart != FileBasicInfo->CreationTime.LowPart)||
  719. (thisFcb->CreationTime.HighPart != FileBasicInfo->CreationTime.HighPart)) {
  720. DavFcb->fCreationTimeChanged = TRUE;
  721. }
  722. }
  723. if (FileBasicInfo->LastAccessTime.QuadPart != 0) {
  724. if (!DavIsValidDate(&FileBasicInfo->LastAccessTime)) {
  725. NtStatus = STATUS_INVALID_PARAMETER;
  726. break;
  727. }
  728. if ((thisFcb->LastAccessTime.LowPart != FileBasicInfo->LastAccessTime.LowPart)||
  729. (thisFcb->LastAccessTime.HighPart != FileBasicInfo->LastAccessTime.HighPart)) {
  730. DavFcb->fLastAccessTimeChanged = TRUE;
  731. }
  732. }
  733. if (FileBasicInfo->LastWriteTime.QuadPart != 0) {
  734. if (!DavIsValidDate(&FileBasicInfo->LastWriteTime)) {
  735. NtStatus = STATUS_INVALID_PARAMETER;
  736. break;
  737. }
  738. if ((thisFcb->LastWriteTime.LowPart != FileBasicInfo->LastWriteTime.LowPart)||
  739. (thisFcb->LastWriteTime.HighPart != FileBasicInfo->LastWriteTime.HighPart)) {
  740. DavFcb->fLastModifiedTimeChanged = TRUE;
  741. DavFcb->DoNotTakeTheCurrentTimeAsLMT = TRUE;
  742. }
  743. }
  744. if ((FileBasicInfo->FileAttributes != 0) && (thisFcb->Attributes != FileBasicInfo->FileAttributes)) {
  745. DavDbgTrace(DAV_TRACE_DETAIL,
  746. ("%ld: MRxDAVSetFileInformation: thisFcb->Attributes = %x, "
  747. "FileBasicInfo->FileAttributes = %x\n", PsGetCurrentThreadId(),
  748. thisFcb->Attributes, FileBasicInfo->FileAttributes));
  749. //
  750. // If this is a directory then when we OR the attributes with
  751. // FILE_ATTRIBUTE_DIRECTORY. This is because this gets filtered
  752. // by the time it comes to us and we have code in the usermode
  753. // which makes some validity checks when a user tries to set
  754. // attributes on a directory.
  755. //
  756. if ( (thisFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) ) {
  757. FileBasicInfo->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  758. }
  759. DavFcb->fFileAttributesChanged = TRUE;
  760. FileAttributesChanged = TRUE;
  761. }
  762. DavDbgTrace(DAV_TRACE_DETAIL,
  763. ("%ld: MRxDAVSetFileInformation: fCreationTimeChanged = %d, "
  764. "fLastAccessTimeChanged = %d, fLastModifiedTimeChanged = %d, "
  765. "fFileAttributesChanged = %d\n", PsGetCurrentThreadId(),
  766. DavFcb->fCreationTimeChanged, DavFcb->fLastAccessTimeChanged,
  767. DavFcb->fLastModifiedTimeChanged, DavFcb->fFileAttributesChanged));
  768. NtStatus = UMRxAsyncEngOuterWrapper(RxContext,
  769. SIZEOF_DAV_SPECIFIC_CONTEXT,
  770. MRxDAVFormatTheDAVContext,
  771. DAV_MINIRDR_ENTRY_FROM_SETFILEINFORMATION,
  772. MRxDAVSetFileInformationContinuation,
  773. "MRxDAVSetFileInformation");
  774. if (NtStatus != ERROR_SUCCESS) {
  775. DavDbgTrace(DAV_TRACE_ERROR,
  776. ("%ld: ERROR: MRxDAVSetFileInformation/UMRxAsyncEngOuterWrapper: "
  777. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  778. } else {
  779. //
  780. // Succeeded, modify on the FCB.
  781. //
  782. if(DavFcb->fCreationTimeChanged) {
  783. thisFcb->CreationTime.LowPart = FileBasicInfo->CreationTime.LowPart;
  784. thisFcb->CreationTime.HighPart = FileBasicInfo->CreationTime.HighPart;
  785. }
  786. if(DavFcb->fLastAccessTimeChanged) {
  787. thisFcb->LastAccessTime.LowPart = FileBasicInfo->LastAccessTime.LowPart;
  788. thisFcb->LastAccessTime.HighPart = FileBasicInfo->LastAccessTime.HighPart;
  789. }
  790. if(DavFcb->fLastModifiedTimeChanged) {
  791. thisFcb->LastWriteTime.LowPart = FileBasicInfo->LastWriteTime.LowPart;
  792. thisFcb->LastWriteTime.HighPart = FileBasicInfo->LastWriteTime.HighPart;
  793. }
  794. //
  795. // DavFcb->fFileAttributesChanged could be set on create, and the
  796. // FileBasicInfo->FileAttributes could be 0 here. So we should not
  797. // check DavFcb->fFileAttributesChanged.
  798. //
  799. if (FileAttributesChanged) {
  800. ULONG SavedAttributes = thisFcb->Attributes & FILE_ATTRIBUTE_ENCRYPTED;
  801. thisFcb->Attributes = FileBasicInfo->FileAttributes;
  802. //
  803. // SetFileInformation should not affect any extended NT file
  804. // attributes.
  805. //
  806. thisFcb->Attributes &= ~FILE_ATTRIBUTE_ENCRYPTED;
  807. thisFcb->Attributes |= SavedAttributes;
  808. }
  809. MRxDAVUpdateBasicFileInfoCache(RxContext, thisFcb->Attributes, &thisFcb->LastWriteTime);
  810. }
  811. //
  812. // Cleanup the FCB bits.
  813. //
  814. DavFcb->fCreationTimeChanged = DavFcb->fFileAttributesChanged =
  815. DavFcb->fLastAccessTimeChanged = DavFcb->fLastModifiedTimeChanged = 0;
  816. break;
  817. case FileAllocationInformation: {
  818. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  819. //
  820. // If the FileAllocationInformation is being done on a directory,
  821. // return STATUS_INVALID_PARAMETER since it doesn't make sense to
  822. // do this.
  823. //
  824. if (DavFcb->isDirectory) {
  825. NtStatus = STATUS_INVALID_PARAMETER;
  826. goto EXIT_THE_FUNCTION;
  827. }
  828. NtStatus = DavXxxInformation(IRP_MJ_SET_INFORMATION,
  829. davSrvOpen->UnderlyingFileObject,
  830. FileAllocationInformation,
  831. RxContext->Info.Length,
  832. RxContext->Info.Buffer,
  833. NULL);
  834. if (NtStatus == STATUS_SUCCESS) {
  835. InterlockedExchange(&(DavFcb->FileWasModified), 1);
  836. DavFcb->DoNotTakeTheCurrentTimeAsLMT = FALSE;
  837. } else {
  838. DavDbgTrace(DAV_TRACE_ERROR,
  839. ("%ld: ERROR: MRxDAvSetFileInformation/DavXxxInformation"
  840. ". FileInfoClass = %d\n", PsGetCurrentThreadId(), FileInformationClass));
  841. }
  842. }
  843. break;
  844. default:
  845. DavDbgTrace(DAV_TRACE_ERROR,
  846. ("%ld: ERROR: MRxDAvSetFileInformation: FileInformationClass"
  847. " = %d\n", PsGetCurrentThreadId(), FileInformationClass));
  848. NtStatus = STATUS_NOT_IMPLEMENTED;
  849. break;
  850. }
  851. EXIT_THE_FUNCTION:
  852. return NtStatus;
  853. }
  854. NTSTATUS
  855. MRxDAVReNameContinuation(
  856. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  857. )
  858. /*++
  859. Routine Description:
  860. This is the continuation routine which renames a file.
  861. Arguments:
  862. AsyncEngineContext - The Reflectors context.
  863. RxContext - The RDBSS context.
  864. Return Value:
  865. RXSTATUS - The return status for the operation
  866. --*/
  867. {
  868. NTSTATUS NtStatus;
  869. PAGED_CODE();
  870. DavDbgTrace(DAV_TRACE_DETAIL,
  871. ("%ld: Entering MRxDAVReNameContinuation!!!!\n",
  872. PsGetCurrentThreadId()));
  873. DavDbgTrace(DAV_TRACE_CONTEXT,
  874. ("%ld: MRxDAVReNameContinuation: "
  875. "AsyncEngineContext: %08lx, RxContext: %08lx\n",
  876. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  877. //
  878. // Try usermode.
  879. //
  880. NtStatus = UMRxSubmitAsyncEngUserModeRequest(
  881. UMRX_ASYNCENGINE_ARGUMENTS,
  882. MRxDAVFormatUserModeReNameRequest,
  883. MRxDAVPrecompleteUserModeReNameRequest
  884. );
  885. DavDbgTrace(DAV_TRACE_DETAIL,
  886. ("%ld: Leaving MRxDAVReNameContinuation with NtStatus"
  887. " = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  888. return NtStatus;
  889. }
  890. NTSTATUS
  891. MRxDAVFormatUserModeReNameRequest(
  892. IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  893. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  894. IN ULONG WorkItemLength,
  895. OUT PULONG_PTR ReturnedLength
  896. )
  897. /*++
  898. Routine Description:
  899. This routine formats the ReName request being sent to the user mode for
  900. processing.
  901. Arguments:
  902. RxContext - The RDBSS context.
  903. AsyncEngineContext - The reflctor's context.
  904. WorkItem - The work item buffer.
  905. WorkItemLength - The length of the work item buffer.
  906. ReturnedLength -
  907. Return Value:
  908. STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES.
  909. --*/
  910. {
  911. NTSTATUS NtStatus = STATUS_SUCCESS;
  912. PMRX_SRV_CALL SrvCall = NULL;
  913. PWEBDAV_SRV_CALL DavSrvCall = NULL;
  914. PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  915. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  916. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  917. PWEBDAV_FCB DavFcb = MRxDAVGetFcbExtension(SrvOpen->pFcb);
  918. PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
  919. PWCHAR ServerName = NULL, OldPathName = NULL, NewPathName = NULL;
  920. ULONG ServerNameLengthInBytes, OldPathNameLengthInBytes, NewPathNameLengthInBytes;
  921. PDAV_USERMODE_RENAME_REQUEST DavReNameRequest = NULL;
  922. PSECURITY_CLIENT_CONTEXT SecurityClientContext = NULL;
  923. PMRX_NET_ROOT NetRoot = NULL;
  924. PWCHAR NetRootName = NULL, JustTheNetRootName = NULL;
  925. ULONG NetRootNameLengthInBytes, NetRootNameLengthInWChars;
  926. PFILE_RENAME_INFORMATION FileRenInfo = NULL;
  927. PAGED_CODE();
  928. DavDbgTrace(DAV_TRACE_DETAIL,
  929. ("%ld: Entering MRxDAVFormatUserModeReNameRequest.\n",
  930. PsGetCurrentThreadId()));
  931. DavDbgTrace(DAV_TRACE_CONTEXT,
  932. ("%ld: MRxDAVFormatUserModeReNameRequest: "
  933. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  934. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  935. FileRenInfo = (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
  936. DavWorkItem->WorkItemType = UserModeReName;
  937. DavReNameRequest = &(DavWorkItem->ReNameRequest);
  938. //
  939. // If the destination file already exists, then we need to need to replace
  940. // the file only if ReplaceIfExists is set to TRUE.
  941. //
  942. DavReNameRequest->ReplaceIfExists = FileRenInfo->ReplaceIfExists;
  943. DavDbgTrace(DAV_TRACE_DETAIL,
  944. ("%ld: MRxDAVFormatUserModeReNameRequest: ReplaceIfExists: %d\n",
  945. PsGetCurrentThreadId(), DavReNameRequest->ReplaceIfExists));
  946. SrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;
  947. DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall);
  948. //
  949. // Copy the ServerName.
  950. //
  951. ServerNameLengthInBytes = ( SrvCall->pSrvCallName->Length + sizeof(WCHAR) );
  952. ServerName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  953. ServerNameLengthInBytes);
  954. if (ServerName == NULL) {
  955. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  956. DavDbgTrace(DAV_TRACE_ERROR,
  957. ("ld: ERROR: MRxDAVFormatUserModeReNameRequest/"
  958. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  959. PsGetCurrentThreadId(), NtStatus));
  960. goto EXIT_THE_FUNCTION;
  961. }
  962. RtlCopyBytes(ServerName,
  963. SrvCall->pSrvCallName->Buffer,
  964. SrvCall->pSrvCallName->Length);
  965. ServerName[( ( (ServerNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0';
  966. DavReNameRequest->ServerName = ServerName;
  967. DavDbgTrace(DAV_TRACE_DETAIL,
  968. ("%ld: MRxDAVFormatUserModeReNameRequest: ServerName: %ws\n",
  969. PsGetCurrentThreadId(), ServerName));
  970. //
  971. // Copy the ServerID.
  972. //
  973. DavReNameRequest->ServerID = DavSrvCall->ServerID;
  974. NetRoot = SrvOpen->pFcb->pNetRoot;
  975. //
  976. // The NetRootName (pNetRootName) includes the ServerName. Hence to get the
  977. // NetRootNameLengthInBytes, we do the following.
  978. //
  979. NetRootNameLengthInBytes = (NetRoot->pNetRootName->Length - NetRoot->pSrvCall->pSrvCallName->Length);
  980. NetRootNameLengthInWChars = ( NetRootNameLengthInBytes / sizeof(WCHAR) );
  981. NetRootName = &(NetRoot->pNetRootName->Buffer[1]);
  982. JustTheNetRootName = wcschr(NetRootName, L'\\');
  983. //
  984. // Copy the OldPathName of the Directory.
  985. //
  986. OldPathNameLengthInBytes = ( NetRootNameLengthInBytes +
  987. SrvOpen->pAlreadyPrefixedName->Length +
  988. sizeof(WCHAR) );
  989. OldPathName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  990. OldPathNameLengthInBytes);
  991. if (OldPathName == NULL) {
  992. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  993. DavDbgTrace(DAV_TRACE_ERROR,
  994. ("ld: ERROR: MRxDAVFormatUserModeReNameRequest/"
  995. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  996. PsGetCurrentThreadId(), NtStatus));
  997. goto EXIT_THE_FUNCTION;
  998. }
  999. RtlZeroMemory(OldPathName, OldPathNameLengthInBytes);
  1000. RtlCopyBytes(OldPathName, JustTheNetRootName, NetRootNameLengthInBytes);
  1001. RtlCopyBytes( (OldPathName + NetRootNameLengthInWChars),
  1002. SrvOpen->pAlreadyPrefixedName->Buffer,
  1003. SrvOpen->pAlreadyPrefixedName->Length );
  1004. OldPathName[( ( (OldPathNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0';
  1005. DavReNameRequest->OldPathName = OldPathName;
  1006. wcscpy(DavReNameRequest->Url, DavFcb->Url);
  1007. DavDbgTrace(DAV_TRACE_DETAIL,
  1008. ("%ld: MRxDAVFormatUserModeReNameRequest: pAlreadyPrefixedName: %wZ\n",
  1009. PsGetCurrentThreadId(), SrvOpen->pAlreadyPrefixedName));
  1010. DavDbgTrace(DAV_TRACE_DETAIL,
  1011. ("%ld: MRxDAVFormatUserModeReNameRequest: OldPathName: %ws\n",
  1012. PsGetCurrentThreadId(), OldPathName));
  1013. //
  1014. // Copy the NewPathName of the Directory. If DavFcb->NewFileName starts with
  1015. // a L'\\' then we don't need to add one, but if it doesn't, we need to add
  1016. // one.
  1017. //
  1018. if (DavFcb->NewFileName[0] == L'\\') {
  1019. NewPathNameLengthInBytes = ( NetRootNameLengthInBytes +
  1020. DavFcb->NewFileNameLength +
  1021. sizeof(WCHAR) );
  1022. } else {
  1023. NewPathNameLengthInBytes = ( NetRootNameLengthInBytes +
  1024. DavFcb->NewFileNameLength +
  1025. sizeof(WCHAR) +
  1026. sizeof(WCHAR) );
  1027. }
  1028. NewPathName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  1029. NewPathNameLengthInBytes);
  1030. if (NewPathName == NULL) {
  1031. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1032. DavDbgTrace(DAV_TRACE_ERROR,
  1033. ("ld: ERROR: MRxDAVFormatUserModeReNameRequest/"
  1034. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  1035. PsGetCurrentThreadId(), NtStatus));
  1036. goto EXIT_THE_FUNCTION;
  1037. }
  1038. RtlZeroMemory(NewPathName, NewPathNameLengthInBytes);
  1039. RtlCopyBytes(NewPathName, JustTheNetRootName, NetRootNameLengthInBytes);
  1040. //
  1041. // If DavFcb->NewFileName starts with a L'\\' then we don't need to add one,
  1042. // but if it doesn't, we need to copy one before we copy the new name.
  1043. //
  1044. if (DavFcb->NewFileName[0] == L'\\') {
  1045. RtlCopyBytes( (NewPathName + NetRootNameLengthInWChars),
  1046. DavFcb->NewFileName,
  1047. DavFcb->NewFileNameLength );
  1048. } else {
  1049. RtlCopyBytes( (NewPathName + NetRootNameLengthInWChars),
  1050. L"\\",
  1051. sizeof(WCHAR) );
  1052. RtlCopyBytes( (NewPathName + NetRootNameLengthInWChars + 1),
  1053. DavFcb->NewFileName,
  1054. DavFcb->NewFileNameLength );
  1055. }
  1056. NewPathName[( ( (NewPathNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0';
  1057. DavReNameRequest->NewPathName = NewPathName;
  1058. DavDbgTrace(DAV_TRACE_DETAIL,
  1059. ("%ld: MRxDAVFormatUserModeReNameRequest: NewFileName: %ws\n",
  1060. PsGetCurrentThreadId(), DavFcb->NewFileName));
  1061. DavDbgTrace(DAV_TRACE_DETAIL,
  1062. ("%ld: MRxDAVFormatUserModeReNameRequest: NewPathName: %ws\n",
  1063. PsGetCurrentThreadId(), NewPathName));
  1064. //
  1065. // Set the LogonID stored in the Dav V_NET_ROOT. This value is used in the
  1066. // user mode.
  1067. //
  1068. DavVNetRoot = (PWEBDAV_V_NET_ROOT)SrvOpen->pVNetRoot->Context;
  1069. DavReNameRequest->LogonID.LowPart = DavVNetRoot->LogonID.LowPart;
  1070. DavReNameRequest->LogonID.HighPart = DavVNetRoot->LogonID.HighPart;
  1071. //
  1072. // If an OpaqueLockToken is associated with this SrvOpen (which means that
  1073. // the file was LOCKed on the server) then we need to add this token to
  1074. // the MOVE request we send to the server to ReName the file.
  1075. //
  1076. if (davSrvOpen->OpaqueLockToken != NULL) {
  1077. ULONG LockTokenLengthInBytes = 0;
  1078. ASSERT(davSrvOpen->LockTokenEntry != NULL);
  1079. LockTokenLengthInBytes = (1 + wcslen(davSrvOpen->OpaqueLockToken)) * sizeof(WCHAR);
  1080. DavReNameRequest->OpaqueLockToken = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  1081. LockTokenLengthInBytes);
  1082. if (DavReNameRequest->OpaqueLockToken == NULL) {
  1083. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1084. DavDbgTrace(DAV_TRACE_ERROR,
  1085. ("ld: ERROR: MRxDAVFormatUserModeCloseRequest/"
  1086. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  1087. PsGetCurrentThreadId(), NtStatus));
  1088. goto EXIT_THE_FUNCTION;
  1089. }
  1090. RtlZeroMemory(DavReNameRequest->OpaqueLockToken, LockTokenLengthInBytes);
  1091. RtlCopyBytes(DavReNameRequest->OpaqueLockToken,
  1092. davSrvOpen->OpaqueLockToken,
  1093. (wcslen(davSrvOpen->OpaqueLockToken) * sizeof(WCHAR)));
  1094. }
  1095. SecurityClientContext = &(DavVNetRoot->SecurityClientContext);
  1096. if(!DavVNetRoot->SCAlreadyInitialized) {
  1097. DbgPrint("Not impersonated in MRxDAVFormatUserModeReNameRequest \n");
  1098. DbgBreakPoint();
  1099. }
  1100. //
  1101. // Impersonate the client who initiated the request. If we fail to
  1102. // impersonate, tough luck.
  1103. //
  1104. NtStatus = UMRxImpersonateClient(SecurityClientContext, WorkItemHeader);
  1105. if (!NT_SUCCESS(NtStatus)) {
  1106. DavDbgTrace(DAV_TRACE_ERROR,
  1107. ("%ld: ERROR: MRxDAVFormatUserModeReNameRequest/"
  1108. "UMRxImpersonateClient. NtStatus = %08lx.\n",
  1109. PsGetCurrentThreadId(), NtStatus));
  1110. }
  1111. EXIT_THE_FUNCTION:
  1112. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  1113. ("%ld: Leaving MRxDAVFormatUserModeReNameRequest with "
  1114. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1115. return(NtStatus);
  1116. }
  1117. BOOL
  1118. MRxDAVPrecompleteUserModeReNameRequest(
  1119. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  1120. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  1121. ULONG WorkItemLength,
  1122. BOOL OperationCancelled
  1123. )
  1124. /*++
  1125. Routine Description:
  1126. The precompletion routine for the ReName request.
  1127. Arguments:
  1128. RxContext - The RDBSS context.
  1129. AsyncEngineContext - The reflctor's context.
  1130. WorkItem - The work item buffer.
  1131. WorkItemLength - The length of the work item buffer.
  1132. OperationCancelled - TRUE if this operation was cancelled by the user.
  1133. Return Value:
  1134. TRUE - UMRxAsyncEngineCalldownIrpCompletion is called by the function
  1135. UMRxCompleteUserModeRequest after we return.
  1136. --*/
  1137. {
  1138. NTSTATUS NtStatus;
  1139. PDAV_USERMODE_RENAME_REQUEST DavReNameRequest = NULL;
  1140. PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  1141. PMRX_SRV_OPEN SrvOpen = NULL;
  1142. PWEBDAV_SRV_OPEN davSrvOpen = NULL;
  1143. PAGED_CODE();
  1144. if (!OperationCancelled) {
  1145. SrvOpen = RxContext->pRelevantSrvOpen;
  1146. davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  1147. }
  1148. DavReNameRequest = &(DavWorkItem->ReNameRequest);
  1149. //
  1150. // We need to free up the heaps, we allocated in the format routine.
  1151. //
  1152. if (DavReNameRequest->ServerName != NULL) {
  1153. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  1154. (PBYTE)DavReNameRequest->ServerName);
  1155. if (NtStatus != STATUS_SUCCESS) {
  1156. DavDbgTrace(DAV_TRACE_ERROR,
  1157. ("%ld: ERROR: MRxDAVPrecompleteUserModeReNameRequest/"
  1158. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  1159. PsGetCurrentThreadId(), NtStatus));
  1160. goto EXIT_THE_FUNCTION;
  1161. }
  1162. }
  1163. if (DavReNameRequest->OldPathName != NULL) {
  1164. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  1165. (PBYTE)DavReNameRequest->OldPathName);
  1166. if (NtStatus != STATUS_SUCCESS) {
  1167. DavDbgTrace(DAV_TRACE_ERROR,
  1168. ("%ld: ERROR: MRxDAVPrecompleteUserModeReNameRequest/"
  1169. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  1170. PsGetCurrentThreadId(), NtStatus));
  1171. goto EXIT_THE_FUNCTION;
  1172. }
  1173. }
  1174. if (DavReNameRequest->NewPathName != NULL) {
  1175. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  1176. (PBYTE)DavReNameRequest->NewPathName);
  1177. if (NtStatus != STATUS_SUCCESS) {
  1178. DavDbgTrace(DAV_TRACE_ERROR,
  1179. ("%ld: ERROR: MRxDAVPrecompleteUserModeReNameRequest/"
  1180. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  1181. PsGetCurrentThreadId(), NtStatus));
  1182. goto EXIT_THE_FUNCTION;
  1183. }
  1184. }
  1185. if (DavReNameRequest->OpaqueLockToken != NULL) {
  1186. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  1187. (PBYTE)DavReNameRequest->OpaqueLockToken);
  1188. if (NtStatus != STATUS_SUCCESS) {
  1189. DavDbgTrace(DAV_TRACE_ERROR,
  1190. ("%ld: ERROR: MRxDAVPrecompleteUserModeReNameRequest/"
  1191. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  1192. PsGetCurrentThreadId(), NtStatus));
  1193. goto EXIT_THE_FUNCTION;
  1194. }
  1195. }
  1196. //
  1197. // If this operation was cancelled, then we don't need to do anything
  1198. // special in the Rename case.
  1199. //
  1200. if (OperationCancelled) {
  1201. DavDbgTrace(DAV_TRACE_ERROR,
  1202. ("%ld: MRxDAVPrecompleteUserModeReNameRequest: Operation Cancelled. "
  1203. "AsyncEngineContext = %08lx, RxContext = %08lx.\n",
  1204. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  1205. goto EXIT_THE_FUNCTION;
  1206. }
  1207. NtStatus = AsyncEngineContext->Status;
  1208. if (NtStatus != STATUS_SUCCESS) {
  1209. DavDbgTrace(DAV_TRACE_ERROR,
  1210. ("%ld: ERROR: MRxDAVPrecompleteUserModeReNameRequest:"
  1211. "Rename failed with NtStatus = %08lx.\n",
  1212. PsGetCurrentThreadId(), NtStatus));
  1213. }
  1214. //
  1215. // If the OpaqueLockToken is non-NULL, we need to free it now. This is
  1216. // because after the MOVE "a", "b" (file "a" is being renamed to file "b")
  1217. // the OpaqueLockToken associated with file "a" is no longer valid for file
  1218. // "b".
  1219. //
  1220. if (davSrvOpen->OpaqueLockToken != NULL) {
  1221. ASSERT(davSrvOpen->LockTokenEntry != NULL);
  1222. //
  1223. // Remove the LockTokenEntry associated with this OpaqueLockToken from
  1224. // the global LockTokenEntryList.
  1225. //
  1226. ExAcquireResourceExclusiveLite(&(LockTokenEntryListLock), TRUE);
  1227. RemoveEntryList( &(davSrvOpen->LockTokenEntry->listEntry) );
  1228. ExReleaseResourceLite(&(LockTokenEntryListLock));
  1229. //
  1230. // Free the PagedPool that was allocated for the ServerName.
  1231. //
  1232. RxFreePool(davSrvOpen->LockTokenEntry->ServerName);
  1233. davSrvOpen->LockTokenEntry->ServerName = NULL;
  1234. //
  1235. // Free the PagedPool that was allocated for the PathName.
  1236. //
  1237. RxFreePool(davSrvOpen->LockTokenEntry->PathName);
  1238. davSrvOpen->LockTokenEntry->PathName = NULL;
  1239. //
  1240. // Free the PagedPool that was allocated for this LockTokenEntry.
  1241. //
  1242. RxFreePool(davSrvOpen->LockTokenEntry);
  1243. davSrvOpen->LockTokenEntry = NULL;
  1244. //
  1245. // Free the PagedPool that was allocated for this OpaqueLockToken.
  1246. //
  1247. RxFreePool(davSrvOpen->OpaqueLockToken);
  1248. davSrvOpen->OpaqueLockToken = NULL;
  1249. }
  1250. EXIT_THE_FUNCTION:
  1251. return(TRUE);
  1252. }
  1253. NTSTATUS
  1254. MRxDAVSetFileInformationContinuation(
  1255. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  1256. )
  1257. /*++
  1258. Routine Description:
  1259. The precompletion routine for the SetFileInformation request.
  1260. Arguments:
  1261. Return Value:
  1262. TRUE or FALSE.
  1263. --*/
  1264. {
  1265. NTSTATUS NtStatus;
  1266. PAGED_CODE();
  1267. DavDbgTrace(DAV_TRACE_DETAIL,
  1268. ("%ld: Entering MRxDAVSetFileInformationContinuation!!!!\n",
  1269. PsGetCurrentThreadId()));
  1270. DavDbgTrace(DAV_TRACE_CONTEXT,
  1271. ("%ld: MRxDAVSetFileInformationContinuation: "
  1272. "AsyncEngineContext: %08lx, RxContext: %08lx\n",
  1273. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  1274. //
  1275. // Try usermode.
  1276. //
  1277. NtStatus = UMRxSubmitAsyncEngUserModeRequest(
  1278. UMRX_ASYNCENGINE_ARGUMENTS,
  1279. MRxDAVFormatUserModeSetFileInformationRequest,
  1280. MRxDAVPrecompleteUserModeSetFileInformationRequest
  1281. );
  1282. DavDbgTrace(DAV_TRACE_DETAIL,
  1283. ("%ld: Leaving MRxDAVSetFileInformationContinuation with NtStatus"
  1284. " = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1285. return NtStatus;
  1286. }
  1287. NTSTATUS
  1288. MRxDAVFormatUserModeSetFileInformationRequest(
  1289. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  1290. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  1291. ULONG WorkItemLength,
  1292. PULONG_PTR ReturnedLength
  1293. )
  1294. /*++
  1295. Routine Description:
  1296. This routine formats the SetFileInformation request being sent to the user mode for
  1297. processing.
  1298. Arguments:
  1299. RxContext - The RDBSS context.
  1300. AsyncEngineContext - The reflector's context.
  1301. WorkItem - The work item buffer.
  1302. WorkItemLength - The length of the work item buffer.
  1303. ReturnedLength -
  1304. Return Value:
  1305. STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES.
  1306. --*/
  1307. {
  1308. NTSTATUS NtStatus = STATUS_SUCCESS;
  1309. PMRX_SRV_CALL SrvCall = NULL;
  1310. PWEBDAV_SRV_CALL DavSrvCall = NULL;
  1311. PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  1312. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  1313. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  1314. PFCB thisFcb = (PFCB)RxContext->pFcb;
  1315. PWEBDAV_FCB DavFcb = MRxDAVGetFcbExtension(SrvOpen->pFcb);
  1316. PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
  1317. PWCHAR ServerName = NULL, PathName = NULL;
  1318. ULONG ServerNameLengthInBytes, PathNameLengthInBytes;
  1319. PDAV_USERMODE_SETFILEINFORMATION_REQUEST DavSetFileInformationRequest = NULL;
  1320. PSECURITY_CLIENT_CONTEXT SecurityClientContext = NULL;
  1321. PMRX_NET_ROOT NetRoot = NULL;
  1322. PWCHAR NetRootName = NULL, JustTheNetRootName = NULL;
  1323. ULONG NetRootNameLengthInBytes, NetRootNameLengthInWChars;
  1324. PAGED_CODE();
  1325. DavDbgTrace(DAV_TRACE_DETAIL,
  1326. ("%ld: Entering MRxDAVFormatUserModeSetFileInformationRequest.\n",
  1327. PsGetCurrentThreadId()));
  1328. DavDbgTrace(DAV_TRACE_CONTEXT,
  1329. ("%ld: MRxDAVFormatUserModeSetFileInformationRequest: "
  1330. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  1331. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  1332. DavWorkItem->WorkItemType = UserModeSetFileInformation;
  1333. DavSetFileInformationRequest = &(DavWorkItem->SetFileInformationRequest);
  1334. SrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;
  1335. DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall);
  1336. //
  1337. // Copy the ServerName.
  1338. //
  1339. ServerNameLengthInBytes = ( SrvCall->pSrvCallName->Length + sizeof(WCHAR) );
  1340. ServerName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  1341. ServerNameLengthInBytes);
  1342. if (ServerName == NULL) {
  1343. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1344. DavDbgTrace(DAV_TRACE_ERROR,
  1345. ("ld: ERROR: MRxDAVFormatUserModeSetFileInformationRequest/"
  1346. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  1347. PsGetCurrentThreadId(), NtStatus));
  1348. goto EXIT_THE_FUNCTION;
  1349. }
  1350. RtlCopyBytes(ServerName,
  1351. SrvCall->pSrvCallName->Buffer,
  1352. SrvCall->pSrvCallName->Length);
  1353. ServerName[( ( (ServerNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0';
  1354. DavSetFileInformationRequest->ServerName = ServerName;
  1355. DavDbgTrace(DAV_TRACE_DETAIL,
  1356. ("%ld: MRxDAVFormatUserModeSetFileInformationRequest: ServerName: %ws\n",
  1357. PsGetCurrentThreadId(), ServerName));
  1358. //
  1359. // Copy the ServerID.
  1360. //
  1361. DavSetFileInformationRequest->ServerID = DavSrvCall->ServerID;
  1362. NetRoot = SrvOpen->pFcb->pNetRoot;
  1363. //
  1364. // The NetRootName (pNetRootName) includes the ServerName. Hence to get the
  1365. // NetRootNameLengthInBytes, we do the following.
  1366. //
  1367. NetRootNameLengthInBytes = (NetRoot->pNetRootName->Length - NetRoot->pSrvCall->pSrvCallName->Length);
  1368. NetRootNameLengthInWChars = ( NetRootNameLengthInBytes / sizeof(WCHAR) );
  1369. NetRootName = &(NetRoot->pNetRootName->Buffer[1]);
  1370. JustTheNetRootName = wcschr(NetRootName, L'\\');
  1371. //
  1372. // Copy the PathName of the Directory.
  1373. //
  1374. PathNameLengthInBytes = ( NetRootNameLengthInBytes +
  1375. SrvOpen->pAlreadyPrefixedName->Length +
  1376. sizeof(WCHAR) );
  1377. PathName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  1378. PathNameLengthInBytes);
  1379. if (PathName == NULL) {
  1380. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1381. DavDbgTrace(DAV_TRACE_ERROR,
  1382. ("ld: ERROR: MRxDAVFormatUserModeSetFileInformationRequest/"
  1383. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  1384. PsGetCurrentThreadId(), NtStatus));
  1385. goto EXIT_THE_FUNCTION;
  1386. }
  1387. RtlZeroMemory(PathName, PathNameLengthInBytes);
  1388. RtlCopyBytes(PathName, JustTheNetRootName, NetRootNameLengthInBytes);
  1389. RtlCopyBytes( (PathName + NetRootNameLengthInWChars),
  1390. SrvOpen->pAlreadyPrefixedName->Buffer,
  1391. SrvOpen->pAlreadyPrefixedName->Length );
  1392. PathName[( ( (PathNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0';
  1393. DavSetFileInformationRequest->PathName = PathName;
  1394. DavDbgTrace(DAV_TRACE_DETAIL,
  1395. ("%ld: MRxDAVFormatUserModeSetFileInformationRequest: PathName: %ws\n",
  1396. PsGetCurrentThreadId(), PathName));
  1397. //
  1398. // Set the LogonID stored in the Dav V_NET_ROOT. This value is used in the
  1399. // user mode.
  1400. //
  1401. DavVNetRoot = (PWEBDAV_V_NET_ROOT)SrvOpen->pVNetRoot->Context;
  1402. DavSetFileInformationRequest->LogonID.LowPart = DavVNetRoot->LogonID.LowPart;
  1403. DavSetFileInformationRequest->LogonID.HighPart = DavVNetRoot->LogonID.HighPart;
  1404. SecurityClientContext = &(DavVNetRoot->SecurityClientContext);
  1405. if(!DavVNetRoot->SCAlreadyInitialized)
  1406. {
  1407. DbgPrint("Not impersonated in MRxDAVFormatUserModeSetFileInformationRequest \n");
  1408. DbgBreakPoint();
  1409. }
  1410. //
  1411. // Impersonate the client who initiated the request. If we fail to
  1412. // impersonate, tough luck.
  1413. //
  1414. NtStatus = UMRxImpersonateClient(SecurityClientContext, WorkItemHeader);
  1415. if (!NT_SUCCESS(NtStatus)) {
  1416. DavDbgTrace(DAV_TRACE_ERROR,
  1417. ("%ld: ERROR: MRxDAVFormatUserModeSetFileInformationRequest/"
  1418. "UMRxImpersonateClient. NtStatus = %08lx.\n",
  1419. PsGetCurrentThreadId(), NtStatus));
  1420. }
  1421. ASSERT(RxContext->Info.FileInformationClass == FileBasicInformation);
  1422. //
  1423. // Set the change bits, we will clear them from the FCB in
  1424. // MRxDavSetFileInformation routine this is OK because the FCB is exclusive
  1425. // at this point.
  1426. //
  1427. DavSetFileInformationRequest->FileBasicInformation = *(PFILE_BASIC_INFORMATION)(RxContext->Info.Buffer);
  1428. if (RxContext->pFcb->Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  1429. //
  1430. // Preserve the FILE_ATTRIBUTE_ENCRYPTED flag on the PROPPATCH request
  1431. // sent to DAV server. In fact, no extended file attributes should be
  1432. // changed with a SetFileInformation request.
  1433. //
  1434. DavSetFileInformationRequest->FileBasicInformation.FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1435. }
  1436. //
  1437. // If we are setting a particular time value, we need to make sure that it
  1438. // it not zero. If the user is trying to set a subset of the basic information
  1439. // and the other values (which are not being set by the user but need to be)
  1440. // need to be updated as well, we do them now. The time values to be updated
  1441. // are in the FCB. This situation happens in the copy command.
  1442. //
  1443. DavSetFileInformationRequest->fCreationTimeChanged = DavFcb->fCreationTimeChanged;
  1444. if (DavSetFileInformationRequest->fCreationTimeChanged) {
  1445. if (DavSetFileInformationRequest->FileBasicInformation.CreationTime.QuadPart == 0) {
  1446. DavSetFileInformationRequest->FileBasicInformation.CreationTime.QuadPart = thisFcb->CreationTime.QuadPart;
  1447. }
  1448. }
  1449. DavSetFileInformationRequest->fLastAccessTimeChanged = DavFcb->fLastAccessTimeChanged;
  1450. if (DavSetFileInformationRequest->fLastAccessTimeChanged) {
  1451. if (DavSetFileInformationRequest->FileBasicInformation.LastAccessTime.QuadPart == 0) {
  1452. DavSetFileInformationRequest->FileBasicInformation.LastAccessTime.QuadPart = thisFcb->LastAccessTime.QuadPart;
  1453. }
  1454. }
  1455. DavSetFileInformationRequest->fLastModifiedTimeChanged = DavFcb->fLastModifiedTimeChanged;
  1456. if (DavSetFileInformationRequest->fLastModifiedTimeChanged) {
  1457. if (DavSetFileInformationRequest->FileBasicInformation.LastWriteTime.QuadPart == 0) {
  1458. DavSetFileInformationRequest->FileBasicInformation.LastWriteTime.QuadPart = thisFcb->LastWriteTime.QuadPart;
  1459. }
  1460. }
  1461. //
  1462. // If we are setting both the Creation and LastWrite time values, we need to
  1463. // make sure that the CreationTime <= LastWriteTime.
  1464. //
  1465. if (DavSetFileInformationRequest->fCreationTimeChanged && DavSetFileInformationRequest->fLastModifiedTimeChanged) {
  1466. if (DavSetFileInformationRequest->FileBasicInformation.CreationTime.QuadPart >
  1467. DavSetFileInformationRequest->FileBasicInformation.LastWriteTime.QuadPart) {
  1468. DavSetFileInformationRequest->FileBasicInformation.CreationTime.QuadPart =
  1469. DavSetFileInformationRequest->FileBasicInformation.LastWriteTime.QuadPart;
  1470. }
  1471. }
  1472. DavSetFileInformationRequest->fFileAttributesChanged = DavFcb->fFileAttributesChanged;
  1473. //
  1474. // If an OpaqueLockToken is associated with this SrvOpen (which means that
  1475. // the file was LOCKed on the server) then we need to add this token to
  1476. // the PROPPATCH request we send to the server to SetFileInformation.
  1477. //
  1478. if (davSrvOpen->OpaqueLockToken != NULL) {
  1479. ULONG LockTokenLengthInBytes = 0;
  1480. ASSERT(davSrvOpen->LockTokenEntry != NULL);
  1481. LockTokenLengthInBytes = (1 + wcslen(davSrvOpen->OpaqueLockToken)) * sizeof(WCHAR);
  1482. DavSetFileInformationRequest->OpaqueLockToken = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  1483. LockTokenLengthInBytes);
  1484. if (DavSetFileInformationRequest->OpaqueLockToken == NULL) {
  1485. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1486. DavDbgTrace(DAV_TRACE_ERROR,
  1487. ("ld: ERROR: MRxDAVFormatUserModeSetFileInformationRequest/"
  1488. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  1489. PsGetCurrentThreadId(), NtStatus));
  1490. goto EXIT_THE_FUNCTION;
  1491. }
  1492. RtlZeroMemory(DavSetFileInformationRequest->OpaqueLockToken, LockTokenLengthInBytes);
  1493. RtlCopyBytes(DavSetFileInformationRequest->OpaqueLockToken,
  1494. davSrvOpen->OpaqueLockToken,
  1495. (wcslen(davSrvOpen->OpaqueLockToken) * sizeof(WCHAR)));
  1496. }
  1497. EXIT_THE_FUNCTION:
  1498. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  1499. ("%ld: Leaving MRxDAVFormatUserModeSetFileInformationRequest with "
  1500. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1501. return(NtStatus);
  1502. }
  1503. BOOL
  1504. MRxDAVPrecompleteUserModeSetFileInformationRequest(
  1505. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  1506. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  1507. ULONG WorkItemLength,
  1508. BOOL OperationCancelled
  1509. )
  1510. /*++
  1511. Routine Description:
  1512. The precompletion routine for the SetFileInformation request.
  1513. Arguments:
  1514. RxContext - The RDBSS context.
  1515. AsyncEngineContext - The reflctor's context.
  1516. WorkItem - The work item buffer.
  1517. WorkItemLength - The length of the work item buffer.
  1518. OperationCancelled - TRUE if this operation was cancelled by the user.
  1519. Return Value:
  1520. TRUE - UMRxAsyncEngineCalldownIrpCompletion is called by the function
  1521. UMRxCompleteUserModeRequest after we return.
  1522. --*/
  1523. {
  1524. NTSTATUS NtStatus;
  1525. PDAV_USERMODE_SETFILEINFORMATION_REQUEST DavSetFileInformationRequest = NULL;
  1526. PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  1527. PAGED_CODE();
  1528. DavSetFileInformationRequest = &(DavWorkItem->SetFileInformationRequest);
  1529. //
  1530. // If this operation was cancelled, then we don't need to do anything
  1531. // special in the SetFileInformation case.
  1532. //
  1533. if (OperationCancelled) {
  1534. DavDbgTrace(DAV_TRACE_ERROR,
  1535. ("%ld: MRxDAVPrecompleteUserModeSetFileInformationRequest: Operation Cancelled. "
  1536. "AsyncEngineContext = %08lx, RxContext = %08lx.\n",
  1537. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  1538. }
  1539. //
  1540. // We need to free up the heaps, we allocated in the format routine.
  1541. //
  1542. if (DavSetFileInformationRequest->ServerName != NULL) {
  1543. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  1544. (PBYTE)DavSetFileInformationRequest->ServerName);
  1545. if (NtStatus != STATUS_SUCCESS) {
  1546. DavDbgTrace(DAV_TRACE_ERROR,
  1547. ("%ld: ERROR: MRxDAVPrecompleteUserModeSetFileInformationRequest/"
  1548. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  1549. PsGetCurrentThreadId(), NtStatus));
  1550. goto EXIT_THE_FUNCTION;
  1551. }
  1552. }
  1553. if (DavSetFileInformationRequest->PathName != NULL) {
  1554. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  1555. (PBYTE)DavSetFileInformationRequest->PathName);
  1556. if (NtStatus != STATUS_SUCCESS) {
  1557. DavDbgTrace(DAV_TRACE_ERROR,
  1558. ("%ld: ERROR: MRxDAVPrecompleteUserModeSetFileInformationRequest/"
  1559. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  1560. PsGetCurrentThreadId(), NtStatus));
  1561. goto EXIT_THE_FUNCTION;
  1562. }
  1563. }
  1564. if (DavSetFileInformationRequest->OpaqueLockToken != NULL) {
  1565. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  1566. (PBYTE)DavSetFileInformationRequest->OpaqueLockToken);
  1567. if (NtStatus != STATUS_SUCCESS) {
  1568. DavDbgTrace(DAV_TRACE_ERROR,
  1569. ("%ld: ERROR: MRxDAVPrecompleteUserModeSetFileInformationRequest/"
  1570. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  1571. PsGetCurrentThreadId(), NtStatus));
  1572. goto EXIT_THE_FUNCTION;
  1573. }
  1574. }
  1575. NtStatus = AsyncEngineContext->Status;
  1576. if (NtStatus != STATUS_SUCCESS) {
  1577. DavDbgTrace(DAV_TRACE_ERROR,
  1578. ("%ld: ERROR: MRxDAVPrecompleteUserModeSetFileInformationRequest:"
  1579. "NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  1580. }
  1581. EXIT_THE_FUNCTION:
  1582. return(TRUE);
  1583. }
  1584. NTSTATUS
  1585. MRxDAVQueryVolumeInformationContinuation(
  1586. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  1587. )
  1588. /*++
  1589. Routine Description:
  1590. This is the continuation routine for query volume information operation.
  1591. Arguments:
  1592. AsyncEngineContext - The Reflectors context.
  1593. RxContext - The RDBSS context.
  1594. Return Value:
  1595. RXSTATUS - The return status for the operation.
  1596. --*/
  1597. {
  1598. NTSTATUS NtStatus;
  1599. PAGED_CODE();
  1600. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  1601. ("%ld: Entering MRxDAVQueryVolumeInformationContinuation!!!!\n",
  1602. PsGetCurrentThreadId()));
  1603. DavDbgTrace(DAV_TRACE_CONTEXT,
  1604. ("%ld: MRxDAVQueryVolumeInformationContinuation: "
  1605. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  1606. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  1607. NtStatus = UMRxSubmitAsyncEngUserModeRequest(
  1608. UMRX_ASYNCENGINE_ARGUMENTS,
  1609. MRxDAVFormatUserModeQueryVolumeInformationRequest,
  1610. MRxDAVPrecompleteUserModeQueryVolumeInformationRequest
  1611. );
  1612. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  1613. ("%ld: Leaving MRxDAVQueryVolumeInformationContinuation with NtStatus "
  1614. "= %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1615. return NtStatus;
  1616. }
  1617. NTSTATUS
  1618. MRxDAVFormatUserModeQueryVolumeInformationRequest(
  1619. IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  1620. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  1621. IN ULONG WorkItemLength,
  1622. OUT PULONG_PTR ReturnedLength
  1623. )
  1624. /*++
  1625. Routine Description:
  1626. This routine formats the QueryVolumeInformation request being sent to the user mode
  1627. for processing.
  1628. Arguments:
  1629. RxContext - The RDBSS context.
  1630. AsyncEngineContext - The reflctor's context.
  1631. WorkItem - The work item buffer.
  1632. WorkItemLength - The length of the work item buffer.
  1633. ReturnedLength -
  1634. Return Value:
  1635. STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES.
  1636. --*/
  1637. {
  1638. NTSTATUS NtStatus = STATUS_SUCCESS;
  1639. PMRX_SRV_CALL SrvCall = NULL;
  1640. PWEBDAV_SRV_CALL DavSrvCall = NULL;
  1641. PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  1642. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  1643. PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
  1644. PMRX_NET_ROOT NetRoot = NULL;
  1645. PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
  1646. PWCHAR ServerName = NULL, ShareName = NULL, JustTheShareName = NULL;
  1647. ULONG ServerNameLengthInBytes, ShareNameLengthInBytes;
  1648. PDAV_USERMODE_QUERYVOLUMEINFORMATION_REQUEST QueryVolumeInformationRequest = NULL;
  1649. PWEBDAV_FOBX DavFobx = NULL;
  1650. PSECURITY_CLIENT_CONTEXT SecurityClientContext = NULL;
  1651. RxCaptureFobx;
  1652. PAGED_CODE();
  1653. DavDbgTrace(DAV_TRACE_DETAIL,
  1654. ("%ld: Entering MRxDAVFormatUserModeQueryVolumeInformationRequest.\n",
  1655. PsGetCurrentThreadId()));
  1656. DavDbgTrace(DAV_TRACE_CONTEXT,
  1657. ("%ld: MRxDAVFormatUserModeQueryVolumeInformationRequest: "
  1658. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  1659. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  1660. IF_DEBUG {
  1661. ASSERT (capFobx != NULL);
  1662. ASSERT (capFobx->pSrvOpen == RxContext->pRelevantSrvOpen);
  1663. }
  1664. DavWorkItem->WorkItemType = UserModeQueryVolumeInformation;
  1665. QueryVolumeInformationRequest = &(DavWorkItem->QueryVolumeInformationRequest);
  1666. DavFobx = MRxDAVGetFobxExtension(capFobx);
  1667. ASSERT(DavFobx != NULL);
  1668. NetRoot = SrvOpen->pFcb->pNetRoot;
  1669. DavVNetRoot = (PWEBDAV_V_NET_ROOT)SrvOpen->pVNetRoot->Context;
  1670. ASSERT(DavVNetRoot != NULL);
  1671. DavDbgTrace(DAV_TRACE_DETAIL,
  1672. ("%ld: MRxDAVFormatUserModeQueryVolumeInformationRequest: SrvCallName = %wZ, "
  1673. "SrvCallNameLength = %d\n", PsGetCurrentThreadId(),
  1674. NetRoot->pSrvCall->pSrvCallName, NetRoot->pSrvCall->pSrvCallName->Length));
  1675. DavDbgTrace(DAV_TRACE_DETAIL,
  1676. ("%ld: MRxDAVFormatUserModeQueryVolumeInformationRequest: ShareName = %wZ, "
  1677. "ShareNameLength = %d\n", PsGetCurrentThreadId(),
  1678. NetRoot->pNetRootName, NetRoot->pNetRootName->Length));
  1679. DavDbgTrace(DAV_TRACE_DETAIL,
  1680. ("%ld: MRxDAVFormatUserModeQueryVolumeInformationRequest: PathName = %wZ, "
  1681. "PathNameLength = %d\n", PsGetCurrentThreadId(),
  1682. SrvOpen->pAlreadyPrefixedName, SrvOpen->pAlreadyPrefixedName->Length));
  1683. SrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;
  1684. DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall);
  1685. //
  1686. // Copy the ServerName.
  1687. //
  1688. ServerNameLengthInBytes = ( SrvCall->pSrvCallName->Length + sizeof(WCHAR) );
  1689. ServerName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext,
  1690. ServerNameLengthInBytes);
  1691. if (ServerName == NULL) {
  1692. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1693. DavDbgTrace(DAV_TRACE_ERROR,
  1694. ("%ld: ERROR: MRxDAVFormatUserModeQueryVolumeInformationRequest/"
  1695. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  1696. PsGetCurrentThreadId(), NtStatus));
  1697. goto EXIT_THE_FUNCTION;
  1698. }
  1699. RtlCopyBytes(ServerName,
  1700. SrvCall->pSrvCallName->Buffer,
  1701. SrvCall->pSrvCallName->Length);
  1702. ServerName[( ( (ServerNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0';
  1703. QueryVolumeInformationRequest->ServerName = ServerName;
  1704. DavDbgTrace(DAV_TRACE_DETAIL,
  1705. ("%ld: MRxDAVFormatUserModeQueryVolumeInformationRequest: ServerName: "
  1706. "%ws\n", PsGetCurrentThreadId(), ServerName));
  1707. //
  1708. // Copy the ServerID.
  1709. //
  1710. QueryVolumeInformationRequest->ServerID = DavSrvCall->ServerID;
  1711. //
  1712. // The ShareName (pShareName) includes the ServerName. Hence to get the
  1713. // ShareNameLengthInBytes, we do the following.
  1714. //
  1715. ShareNameLengthInBytes = (NetRoot->pNetRootName->Length - NetRoot->pSrvCall->pSrvCallName->Length);
  1716. ShareName = &(NetRoot->pNetRootName->Buffer[1]);
  1717. JustTheShareName = wcschr(ShareName, L'\\');
  1718. // allocate for NULL
  1719. ShareName = (PWCHAR)UMRxAllocateSecondaryBuffer(AsyncEngineContext, ShareNameLengthInBytes+sizeof(WCHAR));
  1720. if (ShareName == NULL) {
  1721. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1722. DavDbgTrace(DAV_TRACE_ERROR,
  1723. ("%ld: ERROR: MRxDAVFormatUserModeQueryVolumeInformationRequest/"
  1724. "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n",
  1725. PsGetCurrentThreadId(), NtStatus));
  1726. goto EXIT_THE_FUNCTION;
  1727. }
  1728. QueryVolumeInformationRequest->ShareName = (PWCHAR)ShareName;
  1729. RtlZeroMemory(QueryVolumeInformationRequest->ShareName, ShareNameLengthInBytes+sizeof(WCHAR));
  1730. //
  1731. // Copy the ShareName.
  1732. //
  1733. RtlCopyMemory(ShareName, JustTheShareName, ShareNameLengthInBytes);
  1734. DavDbgTrace(DAV_TRACE_DETAIL,
  1735. ("%ld: MRxDAVFormatUserModeQueryVolumeInformationRequest. PathName ="
  1736. " %ws\n", PsGetCurrentThreadId(), ShareName));
  1737. //
  1738. // Set the LogonID stored in the Dav V_NET_ROOT. This value is used in the
  1739. // user mode.
  1740. //
  1741. QueryVolumeInformationRequest->LogonID.LowPart = DavVNetRoot->LogonID.LowPart;
  1742. QueryVolumeInformationRequest->LogonID.HighPart = DavVNetRoot->LogonID.HighPart;
  1743. DavDbgTrace(DAV_TRACE_DETAIL,
  1744. ("%ld: MRxDAVFormatUserModeQueryVolumeInformationRequest. DavVNetRoot"
  1745. " = %08lx\n", PsGetCurrentThreadId(), DavVNetRoot));
  1746. DavDbgTrace(DAV_TRACE_DETAIL,
  1747. ("%ld: MRxDAVFormatUserModeQueryVolumeInformationRequest. LogonID.LowPart"
  1748. " = %08lx\n", PsGetCurrentThreadId(), DavVNetRoot->LogonID.LowPart));
  1749. DavDbgTrace(DAV_TRACE_DETAIL,
  1750. ("%ld: MRxDAVFormatUserModeQueryVolumeInformationRequest. LogonID.HighPart"
  1751. " = %08lx\n", PsGetCurrentThreadId(), DavVNetRoot->LogonID.HighPart));
  1752. SecurityClientContext = &(DavVNetRoot->SecurityClientContext);
  1753. if(!DavVNetRoot->SCAlreadyInitialized)
  1754. {
  1755. DbgPrint("Not impersonated in MRxDAVFormatUserModeQueryVolumeInformationRequest \n");
  1756. DbgBreakPoint();
  1757. }
  1758. //
  1759. // Impersonate the client who initiated the request. If we fail to
  1760. // impersonate, tough luck.
  1761. //
  1762. NtStatus = UMRxImpersonateClient(SecurityClientContext, WorkItemHeader);
  1763. if (!NT_SUCCESS(NtStatus)) {
  1764. DavDbgTrace(DAV_TRACE_ERROR,
  1765. ("%ld: ERROR: MRxDAVFormatUserModeQueryDirectoryRequest/"
  1766. "UMRxImpersonateClient. NtStatus = %08lx.\n",
  1767. PsGetCurrentThreadId(), NtStatus));
  1768. }
  1769. EXIT_THE_FUNCTION:
  1770. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  1771. ("%ld: Leaving MRxDAVFormatUserModeQueryVolumeInformationRequest with "
  1772. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1773. return(NtStatus);
  1774. }
  1775. BOOL
  1776. MRxDAVPrecompleteUserModeQueryVolumeInformationRequest(
  1777. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  1778. PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  1779. ULONG WorkItemLength,
  1780. BOOL OperationCancelled
  1781. )
  1782. /*++
  1783. Routine Description:
  1784. The precompletion routine for the Query Volume Information request.
  1785. Arguments:
  1786. RxContext - The RDBSS context.
  1787. AsyncEngineContext - The reflctor's context.
  1788. WorkItem - The work item buffer.
  1789. WorkItemLength - The length of the work item buffer.
  1790. OperationCancelled - TRUE if this operation was cancelled by the user.
  1791. Return Value:
  1792. TRUE - UMRxAsyncEngineCalldownIrpCompletion is called by the function
  1793. UMRxCompleteUserModeRequest after we return.
  1794. --*/
  1795. {
  1796. NTSTATUS NtStatus = STATUS_SUCCESS;
  1797. PDAV_USERMODE_QUERYVOLUMEINFORMATION_REQUEST QueryVolumeInformationRequest;
  1798. PDAV_USERMODE_QUERYVOLUMEINFORMATION_RESPONSE QueryVolumeInformationResponse;
  1799. PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
  1800. PAGED_CODE();
  1801. DavDbgTrace(DAV_TRACE_ENTRYEXIT,
  1802. ("%ld: Entering MRxDAVPrecompleteUserModeQueryVolumeInformationRequest.\n",
  1803. PsGetCurrentThreadId()));
  1804. DavDbgTrace(DAV_TRACE_CONTEXT,
  1805. ("%ld: MRxDAVPrecompleteUserModeQueryVolumeInformationRequest: "
  1806. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  1807. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  1808. QueryVolumeInformationRequest = &(DavWorkItem->QueryVolumeInformationRequest);
  1809. QueryVolumeInformationResponse = &(DavWorkItem->QueryVolumeInformationResponse);
  1810. //
  1811. // If the operation was cancelled then we don't need to do the following.
  1812. //
  1813. if (!OperationCancelled) {
  1814. //
  1815. // Get the response items only if we succeeded in the user mode and if
  1816. // we got the properties of all the files in the directory.
  1817. //
  1818. if (AsyncEngineContext->Status == STATUS_SUCCESS) {
  1819. if (RxContext->Info.FsInformationClass == FileFsSizeInformation) {
  1820. PFILE_FS_SIZE_INFORMATION FileFsSizeInfo = (PFILE_FS_SIZE_INFORMATION)RxContext->Info.Buffer;
  1821. FileFsSizeInfo->BytesPerSector = DEFAULT_BYTES_PER_SECTOR;
  1822. FileFsSizeInfo->SectorsPerAllocationUnit = DEFAULT_SECTORS_PER_ALLOCATION_UNIT;
  1823. *(LONGLONG *)&FileFsSizeInfo->TotalAllocationUnits =
  1824. *(LONGLONG *)&QueryVolumeInformationResponse->TotalSpace / (DEFAULT_BYTES_PER_SECTOR * DEFAULT_SECTORS_PER_ALLOCATION_UNIT);
  1825. *(LONGLONG *)&FileFsSizeInfo->AvailableAllocationUnits =
  1826. *(LONGLONG *)&QueryVolumeInformationResponse->AvailableSpace / (DEFAULT_BYTES_PER_SECTOR * DEFAULT_SECTORS_PER_ALLOCATION_UNIT);
  1827. } else {
  1828. PFILE_FS_FULL_SIZE_INFORMATION FileFsFullSizeInfo = (PFILE_FS_FULL_SIZE_INFORMATION)RxContext->Info.Buffer;
  1829. ASSERT(RxContext->Info.FsInformationClass == FileFsFullSizeInformation);
  1830. FileFsFullSizeInfo->BytesPerSector = DEFAULT_BYTES_PER_SECTOR;
  1831. FileFsFullSizeInfo->SectorsPerAllocationUnit = DEFAULT_SECTORS_PER_ALLOCATION_UNIT;
  1832. *(LONGLONG *)&FileFsFullSizeInfo->TotalAllocationUnits =
  1833. *(LONGLONG *)&QueryVolumeInformationResponse->TotalSpace / (DEFAULT_BYTES_PER_SECTOR * DEFAULT_SECTORS_PER_ALLOCATION_UNIT);
  1834. *(LONGLONG *)&FileFsFullSizeInfo->ActualAvailableAllocationUnits =
  1835. *(LONGLONG *)&QueryVolumeInformationResponse->AvailableSpace / (DEFAULT_BYTES_PER_SECTOR * DEFAULT_SECTORS_PER_ALLOCATION_UNIT);
  1836. FileFsFullSizeInfo->CallerAvailableAllocationUnits.LowPart = FileFsFullSizeInfo->ActualAvailableAllocationUnits.LowPart;
  1837. FileFsFullSizeInfo->CallerAvailableAllocationUnits.HighPart = FileFsFullSizeInfo->ActualAvailableAllocationUnits.HighPart;
  1838. }
  1839. }
  1840. } else {
  1841. DavDbgTrace(DAV_TRACE_ERROR,
  1842. ("%ld: MRxDAVPrecompleteUserModeQueryVolumeInformationRequest: Operation Cancelled. "
  1843. "AsyncEngineContext = %08lx, RxContext = %08lx.\n",
  1844. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  1845. }
  1846. //
  1847. // We need to free up the heaps, we allocated in the format routine.
  1848. //
  1849. if (QueryVolumeInformationRequest->ServerName != NULL) {
  1850. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  1851. (PBYTE)QueryVolumeInformationRequest->ServerName);
  1852. if (NtStatus != STATUS_SUCCESS) {
  1853. DavDbgTrace(DAV_TRACE_ERROR,
  1854. ("%ld: ERROR: MRxDAVPrecompleteUserModeQueryVolumeInformationRequest/"
  1855. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  1856. PsGetCurrentThreadId(), NtStatus));
  1857. goto EXIT_THE_FUNCTION;
  1858. }
  1859. }
  1860. if (QueryVolumeInformationRequest->ShareName != NULL) {
  1861. NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
  1862. (PBYTE)QueryVolumeInformationRequest->ShareName);
  1863. if (NtStatus != STATUS_SUCCESS) {
  1864. DavDbgTrace(DAV_TRACE_ERROR,
  1865. ("%ld: ERROR: MRxDAVPrecompleteUserModeQueryVolumeInformationRequest/"
  1866. "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
  1867. PsGetCurrentThreadId(), NtStatus));
  1868. goto EXIT_THE_FUNCTION;
  1869. }
  1870. }
  1871. EXIT_THE_FUNCTION:
  1872. AsyncEngineContext->Status = NtStatus;
  1873. return(TRUE);
  1874. }
  1875. BOOL
  1876. DavIsValidDate(
  1877. PLARGE_INTEGER pFileTime
  1878. )
  1879. /*++
  1880. Routine Description:
  1881. This routine checks whether the date corresponding to the filetime is valid
  1882. Arguments:
  1883. pFileTime - Time to be validated
  1884. Return Value:
  1885. TRUE or FALSE.
  1886. --*/
  1887. {
  1888. TIME_FIELDS TimeFields;
  1889. LARGE_INTEGER NtTime;
  1890. PAGED_CODE();
  1891. NtTime = *pFileTime;
  1892. ExSystemTimeToLocalTime( &NtTime, &NtTime );
  1893. RtlTimeToTimeFields( &NtTime, &TimeFields );
  1894. //
  1895. // Check the range of the date found in the time field record
  1896. //
  1897. if ((TimeFields.Year < 1980) || (TimeFields.Year > (1980 + 127))) {
  1898. return FALSE;
  1899. }
  1900. return TRUE;
  1901. }
  1902. NTSTATUS
  1903. MRxDAVIsValidDirectory(
  1904. IN PRX_CONTEXT RxContext,
  1905. IN PUNICODE_STRING DirectoryName
  1906. )
  1907. /*++
  1908. Routine Description:
  1909. This routine checks a remote directory. Actually in webdav all we do is make
  1910. sure this is coming from our service which is indicated by the webdav
  1911. signature string in the EAs. This gurantees us that our service has checked
  1912. the path before we came here.
  1913. Arguments:
  1914. RxContext - The RDBSS context.
  1915. DirectoryName - The directory needs to be checked.
  1916. Return Value:
  1917. RXSTATUS - The return status for the operation.
  1918. --*/
  1919. {
  1920. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  1921. PFILE_FULL_EA_INFORMATION Ea = NULL;
  1922. if (RxContext->Create.EaLength) {
  1923. Ea = (PFILE_FULL_EA_INFORMATION)RxContext->Create.EaBuffer;
  1924. for ( ; ; ) {
  1925. if ( !strcmp(Ea->EaName, EA_NAME_WEBDAV_SIGNATURE) ) {
  1926. ntStatus = STATUS_SUCCESS;
  1927. break;
  1928. } else {
  1929. if (!Ea->NextEntryOffset) {
  1930. break;
  1931. }
  1932. (ULONG_PTR) Ea += Ea->NextEntryOffset;
  1933. }
  1934. }
  1935. }
  1936. return ntStatus;
  1937. }