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.

1244 lines
44 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. read.c
  5. Abstract:
  6. This module implements the DAV miniredir call down routines pertaining to
  7. "read" of file system objects.
  8. Author:
  9. Balan Sethu Raman [SethuR]
  10. Rohan Kumar [RohanK] 04-April-1999
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "webdav.h"
  16. //
  17. // Mentioned below are the prototypes of functions tht are used only within
  18. // this module (file). These functions should not be exposed outside.
  19. //
  20. NTSTATUS
  21. MRxDAVReadContinuation(
  22. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(PAGE, MRxDAVRead)
  26. #pragma alloc_text(PAGE, MRxDAVReadContinuation)
  27. #pragma alloc_text(PAGE, MRxDAVFastIoRead)
  28. #pragma alloc_text(PAGE, DavReadWriteFileEx)
  29. #endif
  30. //
  31. // Implementation of functions begins here.
  32. //
  33. NTSTATUS
  34. MRxDAVRead(
  35. IN PRX_CONTEXT RxContext
  36. )
  37. /*++
  38. Routine Description:
  39. This routine handles network read requests.
  40. Arguments:
  41. RxContext - the RDBSS context
  42. Return Value:
  43. RXSTATUS - The return status for the operation
  44. --*/
  45. {
  46. NTSTATUS NtStatus = STATUS_SUCCESS;
  47. PAGED_CODE();
  48. DavDbgTrace(DAV_TRACE_DETAIL,
  49. ("%ld: Entering MRxDAVRead!!!!\n", PsGetCurrentThreadId()));
  50. DavDbgTrace(DAV_TRACE_CONTEXT,
  51. ("%ld: MRxDAVRead: RxContext: %08lx\n",
  52. PsGetCurrentThreadId(), RxContext));
  53. NtStatus = UMRxAsyncEngOuterWrapper(RxContext,
  54. SIZEOF_DAV_SPECIFIC_CONTEXT,
  55. MRxDAVFormatTheDAVContext,
  56. DAV_MINIRDR_ENTRY_FROM_READ,
  57. MRxDAVReadContinuation,
  58. "MRxDAVRead");
  59. DavDbgTrace(DAV_TRACE_DETAIL,
  60. ("%ld: Leaving MRxDAVRead with NtStatus = %08lx.\n",
  61. PsGetCurrentThreadId(), NtStatus));
  62. return(NtStatus);
  63. }
  64. NTSTATUS
  65. MRxDAVReadContinuation(
  66. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  67. )
  68. /*++
  69. Routine Description:
  70. This is the continuation routine for read operation.
  71. Arguments:
  72. AsyncEngineContext - The exchange to be conducted.
  73. RxContext - The RDBSS context.
  74. Return Value:
  75. RXSTATUS - The return status for the operation
  76. --*/
  77. {
  78. NTSTATUS NtStatus = STATUS_SUCCESS;
  79. PWEBDAV_CONTEXT DavContext = NULL;
  80. PLOWIO_CONTEXT LowIoContext = NULL;
  81. LARGE_INTEGER ByteOffset = {0,0}, AlignedOffset = {0,0};
  82. ULONG ByteCount = 0, ByteOffsetMisAlignment = 0, LengthRead = 0;
  83. ULONG TotalLengthActuallyRead = 0, BytesToCopy = 0;
  84. PIRP TopIrp = NULL;
  85. BOOLEAN SynchronousIo = FALSE, PagingIo = FALSE, readLessThanAsked = FALSE;
  86. PWEBDAV_SRV_OPEN davSrvOpen = NULL;
  87. IO_STATUS_BLOCK IoStatusBlock;
  88. PBYTE AllocatedSideBuffer = NULL, UserBuffer = NULL;
  89. PAGED_CODE();
  90. DavDbgTrace(DAV_TRACE_DETAIL,
  91. ("%ld: Entering MRxDAVReadContinuation.\n", PsGetCurrentThreadId()));
  92. DavDbgTrace(DAV_TRACE_CONTEXT,
  93. ("%ld: AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  94. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  95. ASSERT_ASYNCENG_CONTEXT(AsyncEngineContext);
  96. //
  97. // We want to keep the AsyncEngineContext alive while we are doing this read
  98. // operation. The reference is taken away when we leave this function.
  99. //
  100. InterlockedIncrement( &(AsyncEngineContext->NodeReferenceCount) );
  101. DavContext = (PWEBDAV_CONTEXT)AsyncEngineContext;
  102. LowIoContext = &(RxContext->LowIoContext);
  103. ASSERT(LowIoContext != NULL);
  104. ByteOffset.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  105. //
  106. // If the bytecount is zero then we can return right away. We don't need to
  107. // do any further processing.
  108. //
  109. ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  110. UserBuffer = RxLowIoGetBufferAddress(RxContext);
  111. PagingIo = BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO);
  112. SynchronousIo = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
  113. davSrvOpen = MRxDAVGetSrvOpenExtension(RxContext->pRelevantSrvOpen);
  114. ASSERT(davSrvOpen->UnderlyingHandle != NULL);
  115. ASSERT(davSrvOpen->UnderlyingFileObject != NULL);
  116. ASSERT(davSrvOpen->UnderlyingDeviceObject != NULL);
  117. if ( davSrvOpen->UnderlyingHandle == NULL ||
  118. davSrvOpen->UnderlyingFileObject == NULL ||
  119. davSrvOpen->UnderlyingDeviceObject == NULL ) {
  120. NtStatus = STATUS_INVALID_PARAMETER;
  121. DavDbgTrace(DAV_TRACE_ERROR,
  122. ("%ld: MRxDAVReadContinuation. Invalid davSrvOpen\n",
  123. PsGetCurrentThreadId()));
  124. goto EXIT_THE_FUNCTION;
  125. }
  126. DavDbgTrace(DAV_TRACE_DETAIL,
  127. ("%ld: MRxDAVReadContinuation. FileName = %wZ, PagingIo = %d, SynchronousIo = %d"
  128. ", ByteOffset.HighPart = %d, ByteOffset.LowPart = %d, ByteCount = %d\n",
  129. PsGetCurrentThreadId(), RxContext->pRelevantSrvOpen->pAlreadyPrefixedName,
  130. PagingIo, SynchronousIo, ByteOffset.HighPart, ByteOffset.LowPart,
  131. ByteCount));
  132. if (PagingIo) {
  133. ASSERT(RxContext->CurrentIrp->MdlAddress != NULL);
  134. if (RxContext->CurrentIrp->MdlAddress == NULL) {
  135. DbgPrint("%ld: MRxDAVReadContinuation: MdlAddress == NULL\n", PsGetCurrentThreadId());
  136. DbgBreakPoint();
  137. }
  138. BytesToCopy = ( (ByteCount >> PAGE_SHIFT) << PAGE_SHIFT );
  139. DavDbgTrace(DAV_TRACE_DETAIL,
  140. ("%ld: MRxDAVReadContinuation(0). ByteCount = %d, BytesToCopy = %d\n",
  141. PsGetCurrentThreadId(), ByteCount, BytesToCopy));
  142. if (BytesToCopy > 0) {
  143. LengthRead = DavReadWriteFileEx(DAV_MJ_READ,
  144. FALSE,
  145. TRUE,
  146. RxContext->CurrentIrp->MdlAddress,
  147. davSrvOpen->UnderlyingDeviceObject,
  148. davSrvOpen->UnderlyingFileObject,
  149. ByteOffset.QuadPart,
  150. MmGetMdlBaseVa(RxContext->CurrentIrp->MdlAddress),
  151. BytesToCopy,
  152. &(IoStatusBlock));
  153. NtStatus = IoStatusBlock.Status;
  154. if (NtStatus != STATUS_SUCCESS) {
  155. DavDbgTrace(DAV_TRACE_ERROR,
  156. ("%ld: MRxDAVReadContinuation/DavReadWriteFileEx(0). "
  157. "NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  158. goto EXIT_THE_FUNCTION;
  159. }
  160. //
  161. // Add the actual bytes read to the TotalLengthActuallyRead.
  162. //
  163. TotalLengthActuallyRead += LengthRead;
  164. //
  165. // If LengthRead < BytesToCopy, it implies that the filesize of the
  166. // underlying file is less than the data being read. In such a case,
  167. // we return right away since we have already read whatever we could.
  168. //
  169. if (LengthRead < BytesToCopy) {
  170. DavDbgTrace(DAV_TRACE_DETAIL,
  171. ("%ld: MRxDAVReadContinuation. LengthRead < BytesToCopy\n",
  172. PsGetCurrentThreadId()));
  173. goto EXIT_THE_FUNCTION;
  174. }
  175. }
  176. //
  177. // If we have already written out the required number of bytes (which
  178. // means BytesToCopy == ByteCount), then we are done and can exit now.
  179. //
  180. if (BytesToCopy == ByteCount) {
  181. DavDbgTrace(DAV_TRACE_DETAIL,
  182. ("%ld: MRxDAVReadContinuation. BytesToCopy == ByteCount(0)\n",
  183. PsGetCurrentThreadId()));
  184. goto EXIT_THE_FUNCTION;
  185. }
  186. //
  187. // Decrement the ByteCount by the number of bytes that have been copied.
  188. //
  189. ByteCount -= BytesToCopy;
  190. ASSERT(ByteCount < PAGE_SIZE);
  191. //
  192. // Increment the ByteOffset with the number of bytes that have been copied.
  193. // Since this is PagingIo, the start address was page-aligned and we
  194. // have read integral number of pages so ByteOffset+BytesToCopy should
  195. // be page aligned as well.
  196. //
  197. ByteOffset.QuadPart += BytesToCopy;
  198. //
  199. // Increment the UserBuffer pointer which currently points to the begenning
  200. // of the buffer which the user supplied by the number of bytes which have
  201. // been copied.
  202. //
  203. UserBuffer += BytesToCopy;
  204. //
  205. // We have read all the bytes that are multiple of pages. We now need
  206. // to read the remaining bytes needed from the last page. From here,
  207. // we go to Case 3 below.
  208. //
  209. DavDbgTrace(DAV_TRACE_DETAIL,
  210. ("%ld: MRxDAVReadContinuation. Remaining ByteCount = %d\n",
  211. PsGetCurrentThreadId(), ByteCount));
  212. }
  213. //
  214. // We allocate a page size buffer to be used for helping read the data
  215. // which is not aligned at page boundaries.
  216. //
  217. AllocatedSideBuffer = RxAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, DAV_READWRITE_POOLTAG);
  218. if (AllocatedSideBuffer == NULL) {
  219. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  220. DavDbgTrace(DAV_TRACE_ERROR,
  221. ("%ld: MRxDAVReadContinuation/RxAllocatePoolWithTag\n",
  222. PsGetCurrentThreadId()));
  223. goto EXIT_THE_FUNCTION;
  224. }
  225. //
  226. // When we issue a read down to the underlying file system, we need to make
  227. // sure that the offset is page aligned and the bytecount is a multiple of
  228. // PAGE_SIZE. This is because we created the local handle with the
  229. // NO_INTERMEDIATE_BUFFERING option. Since there is no cache map for this
  230. // handle, all the data is read from the disk and hence the alignment issue.
  231. //
  232. //
  233. // Case 1: ByteOffset is not page aligned. In this case we read the page
  234. // which contains the ByteOffset and copy the data from the ByteOffset to
  235. // the end of the page.
  236. //
  237. //
  238. // The "and" operation below does the following. If the ByteOffset is 6377
  239. // and the PAGE_SIZE is 4096, then the MisAlignment is 2281.
  240. //
  241. ByteOffsetMisAlignment = ( ByteOffset.LowPart & (PAGE_SIZE - 1) );
  242. if (ByteOffsetMisAlignment != 0) {
  243. DavDbgTrace(DAV_TRACE_DETAIL,
  244. ("%ld: MRxDAVReadContinuation. Entered Case 1\n",
  245. PsGetCurrentThreadId()));
  246. AlignedOffset = ByteOffset;
  247. //
  248. // The byte offset is not aligned. We need to read the page containing
  249. // the offset now.
  250. //
  251. //
  252. // If the PAGE_SIZE is 4096 (0x1000) then (PAGE_SIZE - 1) is 0xFFF.
  253. // ~(PAGE_SIZE - 1) is 0x000. The bit operation below masks the lower 3
  254. // bytes of the aligned offset to make it page aligned.
  255. //
  256. AlignedOffset.LowPart &= ~(PAGE_SIZE - 1);
  257. RtlZeroMemory(AllocatedSideBuffer, PAGE_SIZE);
  258. LengthRead = DavReadWriteFileEx(DAV_MJ_READ,
  259. TRUE,
  260. FALSE,
  261. NULL,
  262. davSrvOpen->UnderlyingDeviceObject,
  263. davSrvOpen->UnderlyingFileObject,
  264. AlignedOffset.QuadPart,
  265. AllocatedSideBuffer,
  266. PAGE_SIZE,
  267. &(IoStatusBlock));
  268. NtStatus = IoStatusBlock.Status;
  269. if (NtStatus != STATUS_SUCCESS) {
  270. DavDbgTrace(DAV_TRACE_ERROR,
  271. ("%ld: MRxDAVReadContinuation/DavReadWriteFileEx(1). "
  272. "NtStatus = %d\n", PsGetCurrentThreadId(), NtStatus));
  273. goto EXIT_THE_FUNCTION;
  274. }
  275. //
  276. // If the length we read is less than the offset at which we have been
  277. // asked to read ( (LengthRead - ByteOffsetMisAlignment) <= 0 ) then
  278. // we return STATUS_END_OF_FILE. This is because we have been asked
  279. // to read beyond the current filesize.
  280. //
  281. if ( (LengthRead - ByteOffsetMisAlignment) <= 0 ) {
  282. NtStatus = STATUS_END_OF_FILE;
  283. DavDbgTrace(DAV_TRACE_DETAIL,
  284. ("%ld: MRxDAVReadContinuation. (LengthRead - ByteOffsetMisAlignment) <= 0\n",
  285. PsGetCurrentThreadId()));
  286. goto EXIT_THE_FUNCTION;
  287. }
  288. //
  289. // Copy the right number of bytes into the buffer.
  290. //
  291. BytesToCopy = min( ByteCount, (PAGE_SIZE - ByteOffsetMisAlignment) );
  292. //
  293. // If the data actually read is less than what BytesToCopy is from our
  294. // calculations above, it means that the amount of data requested is
  295. // more than the filesize. We only copy the right amount of data.
  296. //
  297. if ( BytesToCopy > (LengthRead - ByteOffsetMisAlignment) ) {
  298. BytesToCopy = (LengthRead - ByteOffsetMisAlignment);
  299. readLessThanAsked = TRUE;
  300. }
  301. //
  302. // Copy the bytes read into the user buffer starting at the correct offset.
  303. //
  304. RtlCopyMemory(UserBuffer,
  305. (AllocatedSideBuffer + ByteOffsetMisAlignment),
  306. BytesToCopy);
  307. //
  308. // Add the actual bytes read to the TotalLengthActuallyRead.
  309. //
  310. TotalLengthActuallyRead += BytesToCopy;
  311. //
  312. // If readLessThanAsked is TRUE, it implies that we have no more data
  313. // to read so we leave.
  314. //
  315. if (readLessThanAsked) {
  316. DavDbgTrace(DAV_TRACE_DETAIL,
  317. ("%ld: MRxDAVReadContinuation. readLessThanAsked(1)\n",
  318. PsGetCurrentThreadId()));
  319. goto EXIT_THE_FUNCTION;
  320. }
  321. //
  322. // If we have already written out the required number of bytes (which
  323. // means BytesToCopy == ByteCount), then we are done and can exit now.
  324. //
  325. if (BytesToCopy == ByteCount) {
  326. DavDbgTrace(DAV_TRACE_DETAIL,
  327. ("%ld: MRxDAVReadContinuation. BytesToCopy == ByteCount(1)\n",
  328. PsGetCurrentThreadId()));
  329. goto EXIT_THE_FUNCTION;
  330. }
  331. //
  332. // Decrement the ByteCount by the number of bytes that have been copied.
  333. //
  334. ByteCount -= BytesToCopy;
  335. //
  336. // Increment the ByteOffset with the number of bytes that have been copied.
  337. // If the original ByteCount was > (PAGE_SIZE - ByteOffsetMisAlignment) then
  338. // the ByteOffset is now page aligned.
  339. //
  340. ByteOffset.QuadPart += BytesToCopy;
  341. //
  342. // Increment the UserBuffer pointer which currently points to the begenning
  343. // of the buffer which the user supplied by the number of bytes which have
  344. // been copied.
  345. //
  346. UserBuffer += BytesToCopy;
  347. }
  348. //
  349. // Case 2: At this stage we have copied the bytes from the unaligned offset
  350. // (if it the ByteOffset was unaligned) to the next page bouandary. Now we
  351. // copy as many pages as we can.
  352. //
  353. //
  354. // If 4100 bytes are remaining, the operation below sets BytesToCopy to
  355. // 4096 and BytesLeftToCopy to 4.
  356. //
  357. BytesToCopy = ( (ByteCount >> PAGE_SHIFT) << PAGE_SHIFT );
  358. DavDbgTrace(DAV_TRACE_DETAIL,
  359. ("%ld: MRxDAVReadContinuation. BytesToCopy = %d\n",
  360. PsGetCurrentThreadId(), BytesToCopy));
  361. //
  362. // If we have any bytes (which are multiple of pages) to copy, we copy them
  363. // now.
  364. //
  365. if (BytesToCopy != 0) {
  366. DavDbgTrace(DAV_TRACE_DETAIL,
  367. ("%ld: MRxDAVReadContinuation. Entered Case 2\n",
  368. PsGetCurrentThreadId()));
  369. //
  370. // If the UserBuffer is DWORD aligned then we copy the data directly
  371. // the UserBuffer. If not then we read one page at a time and copy it
  372. // into the UserBuffer.
  373. //
  374. if ( ( (ULONG_PTR)UserBuffer & 0x3 ) == 0 ) {
  375. //
  376. // The UserBuffer is DWORD aligned.
  377. //
  378. DavDbgTrace(DAV_TRACE_DETAIL,
  379. ("%ld: MRxDAVReadContinuation. UserBuffer is DWORD Aligned\n",
  380. PsGetCurrentThreadId()));
  381. //
  382. // The offset is now page aligned. Zero out the number of bytes which
  383. // will be read into the UserBuffer.
  384. //
  385. RtlZeroMemory(UserBuffer, BytesToCopy);
  386. //
  387. // BytesToCopy is a multiple of pages.
  388. //
  389. LengthRead = DavReadWriteFileEx(DAV_MJ_READ,
  390. FALSE,
  391. FALSE,
  392. NULL,
  393. davSrvOpen->UnderlyingDeviceObject,
  394. davSrvOpen->UnderlyingFileObject,
  395. ByteOffset.QuadPart,
  396. UserBuffer,
  397. BytesToCopy,
  398. &(IoStatusBlock));
  399. NtStatus = IoStatusBlock.Status;
  400. if (NtStatus != STATUS_SUCCESS) {
  401. //
  402. // If NtStatus is STATUS_END_OF_FILE and TotalLengthActuallyRead
  403. // is > 0, it implies that the user asked for data from within
  404. // the file to beyond EOF. The EOF is page aligned. We just return
  405. // the data that we read till the EOF.
  406. //
  407. if ( (NtStatus == STATUS_END_OF_FILE) && (TotalLengthActuallyRead > 0) ) {
  408. NtStatus = STATUS_SUCCESS;
  409. DavDbgTrace(DAV_TRACE_DETAIL,
  410. ("%ld: MRxDAVReadContinuation(1). EOF && TotalLengthActuallyRead\n",
  411. PsGetCurrentThreadId()));
  412. goto EXIT_THE_FUNCTION;
  413. }
  414. DavDbgTrace(DAV_TRACE_ERROR,
  415. ("%ld: MRxDAVReadContinuation/DavReadWriteFileEx(2). "
  416. "NtStatus = %d\n", PsGetCurrentThreadId(), NtStatus));
  417. goto EXIT_THE_FUNCTION;
  418. }
  419. //
  420. // If the amount of data we read is less than what we asked for then
  421. // we only return the data that got read.
  422. //
  423. if (LengthRead < BytesToCopy) {
  424. BytesToCopy = LengthRead;
  425. readLessThanAsked = TRUE;
  426. }
  427. //
  428. // Add the actual bytes read to the TotalLengthActuallyRead.
  429. //
  430. TotalLengthActuallyRead += BytesToCopy;
  431. //
  432. // If readLessThanAsked is TRUE, it implies that we have no more data
  433. // to read so we leave.
  434. //
  435. if (readLessThanAsked) {
  436. DavDbgTrace(DAV_TRACE_DETAIL,
  437. ("%ld: MRxDAVReadContinuation. readLessThanAsked(2)\n",
  438. PsGetCurrentThreadId()));
  439. goto EXIT_THE_FUNCTION;
  440. }
  441. //
  442. // If we have already written out the required number of bytes (which
  443. // means BytesToCopy == ByteCount), then we are done and can exit now.
  444. //
  445. if (BytesToCopy == ByteCount) {
  446. DavDbgTrace(DAV_TRACE_DETAIL,
  447. ("%ld: MRxDAVReadContinuation. BytesToCopy == ByteCount(2)\n",
  448. PsGetCurrentThreadId()));
  449. goto EXIT_THE_FUNCTION;
  450. }
  451. //
  452. // Decrement the ByteCount by the number of bytes that have been copied.
  453. //
  454. ByteCount -= BytesToCopy;
  455. //
  456. // Increment the ByteOffset with the number of bytes that have been copied.
  457. // If the original ByteCount was > (PAGE_SIZE - ByteOffsetMisAlignment) then
  458. // the ByteOffset is now page aligned.
  459. //
  460. ByteOffset.QuadPart += BytesToCopy;
  461. //
  462. // Increment the UserBuffer pointer which currently points to the begenning
  463. // of the buffer which the user supplied by the number of bytes which have
  464. // been copied.
  465. //
  466. UserBuffer += BytesToCopy;
  467. } else {
  468. ULONG BytesToCopyThisIteration = 0;
  469. DavDbgTrace(DAV_TRACE_DETAIL,
  470. ("%ld: MRxDAVReadContinuation. UserBuffer is NOT DWORD Aligned\n",
  471. PsGetCurrentThreadId()));
  472. //
  473. // The UserBuffer is not DWORD aligned, but the Offset is now
  474. // Page aligned. We loop and copy one page at a time. The BytesToCopy
  475. // value below is a multiple of pages.
  476. //
  477. while (BytesToCopy > 0) {
  478. BytesToCopyThisIteration = ( (BytesToCopy < PAGE_SIZE) ? BytesToCopy : PAGE_SIZE );
  479. //
  480. // Copy the memory from the UserBuffer to the AllocatedSideBuffer.
  481. //
  482. RtlZeroMemory(AllocatedSideBuffer, PAGE_SIZE);
  483. LengthRead = DavReadWriteFileEx(DAV_MJ_READ,
  484. TRUE,
  485. FALSE,
  486. NULL,
  487. davSrvOpen->UnderlyingDeviceObject,
  488. davSrvOpen->UnderlyingFileObject,
  489. ByteOffset.QuadPart,
  490. AllocatedSideBuffer,
  491. BytesToCopyThisIteration,
  492. &(IoStatusBlock));
  493. NtStatus = IoStatusBlock.Status;
  494. if (NtStatus != STATUS_SUCCESS) {
  495. //
  496. // If NtStatus is STATUS_END_OF_FILE and TotalLengthActuallyRead
  497. // is > 0, it implies that the user asked for data from within
  498. // the file to beyond EOF. The EOF is page aligned. We just
  499. // return the data that we read till the EOF.
  500. //
  501. if ( (NtStatus == STATUS_END_OF_FILE) && (TotalLengthActuallyRead > 0) ) {
  502. NtStatus = STATUS_SUCCESS;
  503. DavDbgTrace(DAV_TRACE_DETAIL,
  504. ("%ld: MRxDAVReadContinuation(2). EOF && TotalLengthActuallyRead\n",
  505. PsGetCurrentThreadId()));
  506. goto EXIT_THE_FUNCTION;
  507. }
  508. DavDbgTrace(DAV_TRACE_ERROR,
  509. ("%ld: MRxDAVReadContinuation/DavReadWriteFileEx(3). "
  510. "NtStatus = %d\n", PsGetCurrentThreadId(), NtStatus));
  511. goto EXIT_THE_FUNCTION;
  512. }
  513. //
  514. // If the amount of data we read is less than what we asked for then
  515. // we only return the data that got read.
  516. //
  517. if (LengthRead < BytesToCopyThisIteration) {
  518. BytesToCopyThisIteration = LengthRead;
  519. readLessThanAsked = TRUE;
  520. }
  521. //
  522. // Copy the number of bytes read into the UserBuffer.
  523. //
  524. RtlCopyMemory(UserBuffer, AllocatedSideBuffer, BytesToCopyThisIteration);
  525. //
  526. // Add the actual bytes read to the TotalLengthActuallyRead.
  527. //
  528. TotalLengthActuallyRead += BytesToCopyThisIteration;
  529. //
  530. // If readLessThanAsked is TRUE, it implies that we have no more
  531. // data to read so we leave.
  532. //
  533. if (readLessThanAsked) {
  534. DavDbgTrace(DAV_TRACE_DETAIL,
  535. ("%ld: MRxDAVReadContinuation. readLessThanAsked(3)\n",
  536. PsGetCurrentThreadId()));
  537. goto EXIT_THE_FUNCTION;
  538. }
  539. //
  540. // Decrement the ByteCount by the number of bytes that have been copied.
  541. //
  542. ByteCount -= LengthRead;
  543. //
  544. // Increment the ByteOffset with the number of bytes that have been copied.
  545. // If the original ByteCount was > (PAGE_SIZE - ByteOffsetMisAlignment) then
  546. // the ByteOffset is now page aligned.
  547. //
  548. ByteOffset.QuadPart += LengthRead;
  549. //
  550. // Increment the UserBuffer pointer which currently points to the begenning
  551. // of the buffer which the user supplied by the number of bytes which have
  552. // been copied.
  553. //
  554. UserBuffer += LengthRead;
  555. //
  556. // Subtract the LengthWritten from the number of bytes to write.
  557. //
  558. BytesToCopy -= LengthRead;
  559. }
  560. //
  561. // If we have already written out the required number of bytes
  562. // (which means ByteCount == 0), then we are done and can exit now.
  563. //
  564. if (ByteCount == 0) {
  565. DavDbgTrace(DAV_TRACE_DETAIL,
  566. ("%ld: MRxDAVReadContinuation. Leaving!!! ByteCount = 0\n",
  567. PsGetCurrentThreadId()));
  568. goto EXIT_THE_FUNCTION;
  569. }
  570. }
  571. }
  572. //
  573. // Case 3. Now we copy the trailing bytes which are not page aligned. This
  574. // is the last step. If the inital (ByteOffset + ByteCount) ended being
  575. // page aligned then ByteCount would be zero now.
  576. //
  577. if (ByteCount != 0) {
  578. DavDbgTrace(DAV_TRACE_DETAIL,
  579. ("%ld: MRxDAVReadContinuation. Entered Case 3\n",
  580. PsGetCurrentThreadId()));
  581. DavDbgTrace(DAV_TRACE_DETAIL,
  582. ("%ld: MRxDAVReadContinuation. ByteCount = %d\n",
  583. PsGetCurrentThreadId(), ByteCount));
  584. ASSERT(ByteCount < PAGE_SIZE);
  585. RtlZeroMemory(AllocatedSideBuffer, PAGE_SIZE);
  586. //
  587. // Though we are issuing a read for PAGE_SIZE bytes, we might get less
  588. // less number of bytes if the EOF is reached.
  589. //
  590. LengthRead = DavReadWriteFileEx(DAV_MJ_READ,
  591. TRUE,
  592. FALSE,
  593. NULL,
  594. davSrvOpen->UnderlyingDeviceObject,
  595. davSrvOpen->UnderlyingFileObject,
  596. ByteOffset.QuadPart,
  597. AllocatedSideBuffer,
  598. PAGE_SIZE,
  599. &(IoStatusBlock));
  600. NtStatus = IoStatusBlock.Status;
  601. if (NtStatus != STATUS_SUCCESS) {
  602. //
  603. // If NtStatus is STATUS_END_OF_FILE and TotalLengthActuallyRead
  604. // is > 0, it implies that the user asked for data from within
  605. // the file to beyond EOF. The EOF is page aligned. We just return
  606. // the data that we read till the EOF.
  607. //
  608. if ( (NtStatus == STATUS_END_OF_FILE) && (TotalLengthActuallyRead > 0) ) {
  609. NtStatus = STATUS_SUCCESS;
  610. DavDbgTrace(DAV_TRACE_DETAIL,
  611. ("%ld: MRxDAVReadContinuation(3). EOF && TotalLengthActuallyRead\n",
  612. PsGetCurrentThreadId()));
  613. goto EXIT_THE_FUNCTION;
  614. }
  615. DavDbgTrace(DAV_TRACE_ERROR,
  616. ("%ld: MRxDAVReadContinuation/DavReadWriteFileEx(4). "
  617. "NtStatus = %d\n", PsGetCurrentThreadId(), NtStatus));
  618. goto EXIT_THE_FUNCTION;
  619. }
  620. //
  621. // If the amount of data read is less than what the user asked for then
  622. // we only return the data that is available.
  623. //
  624. if (LengthRead < ByteCount) {
  625. BytesToCopy = LengthRead;
  626. readLessThanAsked = TRUE;
  627. DavDbgTrace(DAV_TRACE_DETAIL,
  628. ("%ld: MRxDAVReadContinuation. readLessThanAsked(4)\n",
  629. PsGetCurrentThreadId()));
  630. } else {
  631. BytesToCopy = ByteCount;
  632. }
  633. RtlCopyMemory(UserBuffer, AllocatedSideBuffer, BytesToCopy);
  634. //
  635. // Add the actual bytes read to the TotalLengthActuallyRead.
  636. //
  637. TotalLengthActuallyRead += BytesToCopy;
  638. }
  639. EXIT_THE_FUNCTION:
  640. //
  641. // We allocate a page size buffer for the read and the write operations. We
  642. // need to free it now.
  643. //
  644. if (AllocatedSideBuffer) {
  645. RxFreePool(AllocatedSideBuffer);
  646. }
  647. //
  648. // We need to remove the reference we took at the begenning of this routine.
  649. //
  650. UMRxResumeAsyncEngineContext(RxContext);
  651. DavDbgTrace(DAV_TRACE_DETAIL,
  652. ("%ld: Leaving MRxDAVReadContinuation. NtStatus = %08lx, "
  653. "TotalLengthActuallyRead = %d\n",
  654. PsGetCurrentThreadId(), NtStatus, TotalLengthActuallyRead));
  655. AsyncEngineContext->Status = NtStatus;
  656. //
  657. // We need to set these values in the RxContext. There is code in RDBSS
  658. // which takes care of putting these values in the IRP.
  659. //
  660. RxContext->StoredStatus = NtStatus;
  661. RxContext->InformationToReturn = TotalLengthActuallyRead;
  662. return NtStatus;
  663. }
  664. BOOLEAN
  665. MRxDAVFastIoRead(
  666. IN PFILE_OBJECT FileObject,
  667. IN PLARGE_INTEGER FileOffset,
  668. IN ULONG Length,
  669. IN BOOLEAN Wait,
  670. IN ULONG LockKey,
  671. OUT PVOID Buffer,
  672. OUT PIO_STATUS_BLOCK IoStatus,
  673. IN PDEVICE_OBJECT DeviceObject
  674. )
  675. /*++
  676. Routine Description:
  677. This is the routine that handles fast I/O for read operation.
  678. Arguments:
  679. Return Value:
  680. TRUE (succeeded) or FALSE.
  681. --*/
  682. {
  683. BOOLEAN ReturnVal = FALSE;
  684. PAGED_CODE();
  685. DavDbgTrace(DAV_TRACE_DETAIL,
  686. ("%ld: Entered MRxDAVFastIoRead.\n", PsGetCurrentThreadId()));
  687. IoStatus->Status = STATUS_NOT_IMPLEMENTED;
  688. IoStatus->Information = 0;
  689. return (ReturnVal);
  690. }
  691. ULONG
  692. DavReadWriteFileEx(
  693. IN USHORT Operation,
  694. IN BOOL NonPagedBuffer,
  695. IN BOOL UseOriginalIrpsMDL,
  696. IN PMDL OriginalIrpsMdl,
  697. IN PDEVICE_OBJECT DeviceObject,
  698. IN PFILE_OBJECT FileObject,
  699. IN ULONGLONG FileOffset,
  700. IN OUT PVOID DataBuffer,
  701. IN ULONG SizeInBytes,
  702. OUT PIO_STATUS_BLOCK IoStatusBlock
  703. )
  704. /*++
  705. Routine Description:
  706. This is the routine reads or writes (Operation) SizeInBytes bytes of data of
  707. the file (FileObject) and copies (in case of read) it in the DataBuffer. In
  708. case of write the data from DataBuffer is written onto the file. The result
  709. of the operation is set in the IoStatusBlock.
  710. Arguments:
  711. Operation - Whether this is a Read or a Write operation.
  712. NonPagedBuffer - TRUE if the DataBuffer is from NonPagedPool which we
  713. allocated in the read and write continuation routines to
  714. make sure that the writes and reads that we pass down to
  715. the underlying filesystem are page aligned.
  716. FileObject - The file object of the file in question.
  717. FileOffset - The offset at which the data is read or written.
  718. DataBuffer - The data buffer in which the data is copied in case of a read
  719. or the data is written to the file from the data buffer in
  720. the write case.
  721. SizeInBytes - Size in bytes of the DataBuffer.
  722. IoStatusBlock - The IO_STATUS_BLOCK which contains the return status.
  723. Return Value:
  724. The number of bytes read or written.
  725. --*/
  726. {
  727. NTSTATUS NtStatus = STATUS_SUCCESS;
  728. ULONG ReadWriteLength = 0, MdlLength = 0;
  729. LARGE_INTEGER ByteOffset = {0,0};
  730. ULONG MajorFunction;
  731. PIRP Irp = NULL, TopIrp = NULL;
  732. PIO_STACK_LOCATION IrpSp = NULL;
  733. WEBDAV_READ_WRITE_IRP_COMPLETION_CONTEXT DavIrpCompletionContext;
  734. LOCK_OPERATION ProbeOperation = 0;
  735. BOOL didProbeAndLock = FALSE;
  736. PAGED_CODE();
  737. DavDbgTrace(DAV_TRACE_DETAIL,
  738. ("%ld: DavReadWriteFileEx. Operation = %d, NonPagedBuffer = %d, "
  739. "FileObject = %08lx, FileOffset = %d",
  740. PsGetCurrentThreadId(), Operation,
  741. NonPagedBuffer, FileObject, FileOffset));
  742. DavDbgTrace(DAV_TRACE_DETAIL,
  743. ("%ld: DavReadWriteFileEx. SizeInBytes = %d\n",
  744. PsGetCurrentThreadId(), SizeInBytes));
  745. IoStatusBlock->Information = 0;
  746. if ( (DeviceObject->Flags & DO_BUFFERED_IO) ) {
  747. //
  748. // We cannot handle Buffered I/O Devices.
  749. //
  750. DavDbgTrace(DAV_TRACE_ERROR,
  751. ("%ld: DavReadWriteFileEx. DeviceObject->Flags & DO_BUFFERED_IO\n",
  752. PsGetCurrentThreadId()));
  753. NtStatus = STATUS_INVALID_DEVICE_REQUEST;
  754. ReadWriteLength = -1;
  755. goto EXIT_THE_FUNCTION;
  756. }
  757. //
  758. // If we want to write the data OUT of the memory ON to the disk, we should
  759. // be probing with IoReadAccess. If we are reading data FROM the disk INTO
  760. // the memory, I should probe it with IoWriteAccess (since you the data you
  761. // read could be written to).
  762. //
  763. if (Operation == DAV_MJ_READ) {
  764. MajorFunction = IRP_MJ_READ;
  765. ProbeOperation = IoWriteAccess;
  766. } else {
  767. ASSERT(Operation == DAV_MJ_WRITE);
  768. MajorFunction = IRP_MJ_WRITE;
  769. ProbeOperation = IoReadAccess;
  770. }
  771. //
  772. // Set the Offset at which we are going to read or write.
  773. //
  774. ByteOffset.QuadPart = FileOffset;
  775. //
  776. // Allocate the new IRP that we will send down to the underlying file system.
  777. //
  778. Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  779. if (Irp == NULL) {
  780. DavDbgTrace(DAV_TRACE_ERROR,
  781. ("%ld: DavReadWriteFileEx/IoAllocateIrp\n",
  782. PsGetCurrentThreadId()));
  783. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  784. ReadWriteLength = -1;
  785. goto EXIT_THE_FUNCTION;
  786. }
  787. //
  788. // Set current thread for IoSetHardErrorOrVerifyDevice.
  789. //
  790. Irp->Tail.Overlay.Thread = PsGetCurrentThread();
  791. //
  792. // Get a pointer to the stack location of the first driver which will be
  793. // invoked. This is where the function codes and the parameters are set.
  794. //
  795. IrpSp = IoGetNextIrpStackLocation(Irp);
  796. IrpSp->MajorFunction = (UCHAR)MajorFunction;
  797. IrpSp->FileObject = FileObject;
  798. //
  799. // Set the completion routine to be called everytime.
  800. //
  801. IoSetCompletionRoutine(Irp,
  802. DavReadWriteIrpCompletionRoutine,
  803. &(DavIrpCompletionContext),
  804. TRUE,
  805. TRUE,
  806. TRUE);
  807. ASSERT( &(IrpSp->Parameters.Write.Key) == &(IrpSp->Parameters.Read.Key) );
  808. ASSERT( &(IrpSp->Parameters.Write.Length) == &(IrpSp->Parameters.Read.Length) );
  809. ASSERT( &(IrpSp->Parameters.Write.ByteOffset) == &(IrpSp->Parameters.Read.ByteOffset) );
  810. //
  811. // Set the length to be read/written to the number of bytes supplied by the
  812. // caller of the function.
  813. //
  814. IrpSp->Parameters.Read.Length = MdlLength = SizeInBytes;
  815. //
  816. // Set the offset to the value suppiled by the caller of the function.
  817. //
  818. IrpSp->Parameters.Read.ByteOffset = ByteOffset;
  819. IrpSp->Parameters.Read.Key = 0;
  820. Irp->RequestorMode = KernelMode;
  821. //
  822. // Set the UserBuffer of the Irp to the DataBuffer supplied by the caller.
  823. //
  824. Irp->UserBuffer = DataBuffer;
  825. //
  826. // Also the SizeInBytes which is set to the MdlLength above is always a
  827. // multiple of PAGE_SIZE.
  828. //
  829. // MdlLength = (ULONG)ROUND_TO_PAGES(MdlLength);
  830. //
  831. // Allocate the MDL for this Irp.
  832. //
  833. Irp->MdlAddress = IoAllocateMdl(Irp->UserBuffer, MdlLength, FALSE, FALSE, NULL);
  834. if (Irp->MdlAddress == NULL) {
  835. DavDbgTrace(DAV_TRACE_ERROR,
  836. ("%ld: DavReadWriteFileEx/IoAllocateMdl\n",
  837. PsGetCurrentThreadId()));
  838. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  839. ReadWriteLength = -1;
  840. goto EXIT_THE_FUNCTION;
  841. }
  842. //
  843. // We always do IRP_NOCACHE since the create of the local file was done with
  844. // NO_INTERMEDIATE_BUFFERING.
  845. //
  846. Irp->Flags |= IRP_NOCACHE;
  847. //
  848. // If we got a PagingIo, we build a partial MDL using the one that come down
  849. // in the original (PagingIo) IRP and send it down. We do this since the MDL
  850. // would have been probed and locked already and we don't need to do it
  851. // again.
  852. //
  853. if (UseOriginalIrpsMDL) {
  854. ASSERT(OriginalIrpsMdl != NULL);
  855. IoBuildPartialMdl(OriginalIrpsMdl, Irp->MdlAddress, Irp->UserBuffer, MdlLength);
  856. } else {
  857. //
  858. // If the DataBuffer that was supplied (which we set to the UserBuffer in
  859. // the Irp above) is the one we allocated from the nonpaged pool, then we
  860. // build the MDL from non-paged pool. We don't need to call ProbeAndLock
  861. // since we ourselves allocated it from Non-Paged Pool in the read and
  862. // write continuation routines. If this is not the buffer that we allocated
  863. // then we call MmProbeAndLockPages. We need to Probe because we allocated
  864. // the MDL above and it needs to be filled in with the correct address values
  865. // of where the data is.
  866. //
  867. if (NonPagedBuffer) {
  868. MmBuildMdlForNonPagedPool(Irp->MdlAddress);
  869. } else {
  870. try {
  871. MmProbeAndLockPages(Irp->MdlAddress, KernelMode, ProbeOperation);
  872. didProbeAndLock = TRUE;
  873. } except(EXCEPTION_EXECUTE_HANDLER) {
  874. NtStatus = GetExceptionCode();
  875. DavDbgTrace(DAV_TRACE_ERROR,
  876. ("%ld: DavReadWriteFileEx/MmProbeAndLockPages. NtStatus"
  877. " = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  878. IoFreeMdl(Irp->MdlAddress);
  879. Irp->MdlAddress = NULL;
  880. ReadWriteLength = -1;
  881. goto EXIT_THE_FUNCTION;
  882. }
  883. }
  884. }
  885. //
  886. // Initialize the event on which we will wait after we call IoCallDriver.
  887. // This event will be signalled in the Completion routine which will be
  888. // called by the underlying file system after it completes the operation.
  889. //
  890. KeInitializeEvent(&(DavIrpCompletionContext.DavReadWriteEvent),
  891. NotificationEvent,
  892. FALSE);
  893. //
  894. // Now is the time to call the underlying file system with the Irp that we
  895. // just created.
  896. //
  897. try {
  898. //
  899. // Save the TopLevel Irp.
  900. //
  901. TopIrp = IoGetTopLevelIrp();
  902. //
  903. // Tell the underlying guy he's all clear.
  904. //
  905. IoSetTopLevelIrp(NULL);
  906. //
  907. // Finally, call the underlying file system to process the request.
  908. //
  909. NtStatus = IoCallDriver(DeviceObject, Irp);
  910. } finally {
  911. //
  912. // Restore my context for unwind.
  913. //
  914. IoSetTopLevelIrp(TopIrp);
  915. }
  916. if (NtStatus == STATUS_PENDING) {
  917. //
  918. // If STATUS_PENDING was returned by the underlying file system then we
  919. // wait here till the operation gets completed.
  920. //
  921. KeWaitForSingleObject(&(DavIrpCompletionContext.DavReadWriteEvent),
  922. Executive,
  923. KernelMode,
  924. FALSE,
  925. NULL);
  926. NtStatus = Irp->IoStatus.Status;
  927. }
  928. if (NtStatus == STATUS_SUCCESS) {
  929. //
  930. // If the IoCallDriver was successful, then Irp->IoStatus.Information
  931. // contains the number of bytes read or written.
  932. //
  933. ReadWriteLength = (ULONG)Irp->IoStatus.Information;
  934. IoStatusBlock->Information = ReadWriteLength;
  935. } else if (NtStatus == STATUS_END_OF_FILE) {
  936. ReadWriteLength = 0;
  937. } else {
  938. ReadWriteLength = -1;
  939. DavDbgTrace(DAV_TRACE_ERROR,
  940. ("%ld: DavReadWriteFileEx/IoCallDriver. NtStatus = %08lx\n",
  941. PsGetCurrentThreadId(), NtStatus));
  942. }
  943. EXIT_THE_FUNCTION:
  944. //
  945. // Free the Irp that we allocated above.
  946. //
  947. if (Irp) {
  948. //
  949. // Free the MDL only if we allocated it in the first place.
  950. //
  951. if (Irp->MdlAddress) {
  952. //
  953. // If it was not from NonPagedPool, we would have locked it. So, we
  954. // need to unlock before freeing.
  955. //
  956. if (didProbeAndLock) {
  957. MmUnlockPages(Irp->MdlAddress);
  958. }
  959. IoFreeMdl(Irp->MdlAddress);
  960. }
  961. IoFreeIrp(Irp);
  962. }
  963. IoStatusBlock->Status = NtStatus;
  964. DavDbgTrace(DAV_TRACE_DETAIL,
  965. ("%ld: DavReadWriteFileEx. ReadWriteLength = %d\n",
  966. PsGetCurrentThreadId(), ReadWriteLength));
  967. return ReadWriteLength;
  968. }
  969. NTSTATUS
  970. DavReadWriteIrpCompletionRoutine(
  971. IN PDEVICE_OBJECT DeviceObject,
  972. IN PIRP CalldownIrp,
  973. IN PVOID Context
  974. )
  975. /*++
  976. Routine Description:
  977. This routine is called when the read/write IRP that was sent to the
  978. underlying file system is completed.
  979. Arguments:
  980. DeviceObject - The WebDav Device object.
  981. CalldownIrp - The IRP that was created and sent to the underlying file
  982. system.
  983. Context - The context that was set in the IoSetCompletionRoutine function.
  984. Return Value:
  985. STATUS_MORE_PROCESSING_REQUIRED
  986. --*/
  987. {
  988. PWEBDAV_READ_WRITE_IRP_COMPLETION_CONTEXT DavIrpCompletionContext = NULL;
  989. DavIrpCompletionContext = (PWEBDAV_READ_WRITE_IRP_COMPLETION_CONTEXT)Context;
  990. //
  991. // This is not Pageable Code.
  992. //
  993. //
  994. // If the IoCallDriver routine returned pending then it will be set in the
  995. // IRP's PendingReturned field. In this case we need to set the event on
  996. // which the thread which issued IoCallDriver will be waiting.
  997. //
  998. if (CalldownIrp->PendingReturned) {
  999. KeSetEvent( &(DavIrpCompletionContext->DavReadWriteEvent), 0 , FALSE );
  1000. }
  1001. return(STATUS_MORE_PROCESSING_REQUIRED);
  1002. }