Source code of Windows XP (NT5)
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.

1536 lines
50 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. write.c
  5. Abstract:
  6. This module contains the code to implement the NtWriteFile system service.
  7. Author:
  8. Darryl E. Havens (darrylh) 14-Apr-1989
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "iomgr.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, NtWriteFile)
  16. #pragma alloc_text(PAGE, NtWriteFile64)
  17. #pragma alloc_text(PAGE, NtWriteFileGather)
  18. #endif
  19. NTSTATUS
  20. NtWriteFile(
  21. IN HANDLE FileHandle,
  22. IN HANDLE Event OPTIONAL,
  23. IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
  24. IN PVOID ApcContext OPTIONAL,
  25. OUT PIO_STATUS_BLOCK IoStatusBlock,
  26. IN PVOID Buffer,
  27. IN ULONG Length,
  28. IN PLARGE_INTEGER ByteOffset OPTIONAL,
  29. IN PULONG Key OPTIONAL
  30. )
  31. /*++
  32. Routine Description:
  33. This service writes Length bytes of data from the caller's Buffer to the
  34. file associated with FileHandle starting at StartingBlock|ByteOffset.
  35. The actual number of bytes written to the file will be returned in the
  36. second longword of the IoStatusBlock.
  37. If the writer has the file open for APPEND access, then the data will be
  38. written to the current EOF mark. The StartingBlock and ByteOffset are
  39. ignored if the caller has APPEND access.
  40. Arguments:
  41. FileHandle - Supplies a handle to the file to be written.
  42. Event - Optionally supplies an event to be set to the Signaled state when
  43. the write operation is complete.
  44. ApcRoutine - Optionally supplies an APC routine to be executed when the
  45. write operation is complete.
  46. ApcContext - Supplies a context parameter to be passed to the APC routine
  47. when it is invoked, if an APC routine was specified.
  48. IoStatusBlock - Supplies the address of the caller's I/O status block.
  49. Buffer - Supplies the address of the buffer containing data to be written
  50. to the file.
  51. Length - Length, in bytes, of the data to be written to the file.
  52. ByteOffset - Specifies the starting byte offset within the file to begin
  53. the write operation. If not specified and the file is open for
  54. synchronous I/O, then the current file position is used. If the
  55. file is not opened for synchronous I/O and the parameter is not
  56. specified, then it is in error.
  57. Key - Optionally specifies a key to be used if there are locks associated
  58. with the file.
  59. Return Value:
  60. The status returned is success if the write operation was properly queued
  61. to the I/O system. Once the write completes the status of the operation
  62. can be determined by examining the Status field of the I/O status block.
  63. --*/
  64. {
  65. PIRP irp;
  66. NTSTATUS status;
  67. PFILE_OBJECT fileObject;
  68. PDEVICE_OBJECT deviceObject;
  69. PFAST_IO_DISPATCH fastIoDispatch;
  70. KPROCESSOR_MODE requestorMode;
  71. PMDL mdl;
  72. PIO_STACK_LOCATION irpSp;
  73. ACCESS_MASK grantedAccess;
  74. ACCESS_MASK desiredAccess = (ACCESS_MASK)0;
  75. OBJECT_HANDLE_INFORMATION handleInformation;
  76. NTSTATUS exceptionCode;
  77. BOOLEAN synchronousIo;
  78. PKEVENT eventObject = (PKEVENT) NULL;
  79. ULONG keyValue = 0;
  80. LARGE_INTEGER fileOffset = {0,0};
  81. PULONG majorFunction;
  82. PETHREAD CurrentThread;
  83. PAGED_CODE();
  84. //
  85. // Get the previous mode; i.e., the mode of the caller.
  86. //
  87. CurrentThread = PsGetCurrentThread ();
  88. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  89. //
  90. // Reference the file object so the target device can be found and the
  91. // access rights mask can be used in the following checks for callers in
  92. // user mode. Note that if the handle does not refer to a file object,
  93. // then it will fail.
  94. //
  95. status = ObReferenceFileObjectForWrite( FileHandle,
  96. requestorMode,
  97. (PVOID *) &fileObject,
  98. &handleInformation);
  99. if (!NT_SUCCESS( status )) {
  100. return status;
  101. }
  102. grantedAccess = handleInformation.GrantedAccess;
  103. //
  104. // Get the address of the target device object.
  105. //
  106. deviceObject = IoGetRelatedDeviceObject( fileObject );
  107. //
  108. // Check to see if the requestor mode was user. If so, perform a bunch
  109. // of extra checks.
  110. //
  111. if (requestorMode != KernelMode) {
  112. //
  113. // The caller's access mode is not kernel so probe each of the arguments
  114. // and capture them as necessary. If any failures occur, the condition
  115. // handler will be invoked to handle them. It will simply cleanup and
  116. // return an access violation status code back to the system service
  117. // dispatcher.
  118. //
  119. //
  120. // Attempt to probe the caller's parameters within the exception
  121. // handler block.
  122. //
  123. try {
  124. //
  125. // The IoStatusBlock parameter must be writeable by the caller.
  126. //
  127. ProbeForWriteIoStatusEx( IoStatusBlock , ApcRoutine);
  128. //
  129. // The caller's data buffer must be readable from the caller's
  130. // mode. This check ensures that this is the case. Since the
  131. // buffer address is captured, the caller cannot change it,
  132. // even though he/she can change the protection from another
  133. // thread. This error will be caught by the probe/lock or
  134. // buffer copy operations later.
  135. //
  136. ProbeForRead( Buffer, Length, sizeof( UCHAR ) );
  137. //
  138. // If this file has an I/O completion port associated w/it, then
  139. // ensure that the caller did not supply an APC routine, as the
  140. // two are mutually exclusive methods for I/O completion
  141. // notification.
  142. //
  143. if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) {
  144. ObDereferenceObject( fileObject );
  145. return STATUS_INVALID_PARAMETER;
  146. }
  147. //
  148. // Check that the ByteOffset parameter is readable from the
  149. // caller's mode, if one was specified, and capture it.
  150. //
  151. if (ARGUMENT_PRESENT( ByteOffset )) {
  152. ProbeForReadSmallStructure( ByteOffset,
  153. sizeof( LARGE_INTEGER ),
  154. sizeof( ULONG ) );
  155. fileOffset = *ByteOffset;
  156. }
  157. //
  158. // Check to see whether the caller has opened the file without
  159. // intermediate buffering. If so, perform the following Buffer
  160. // and ByteOffset parameter checks differently.
  161. //
  162. if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
  163. //
  164. // The file was opened without intermediate buffering enabled.
  165. // Check that the Buffer is properly aligned, and that the
  166. // length is an integral number of the block size.
  167. //
  168. if ((deviceObject->SectorSize &&
  169. (Length & (deviceObject->SectorSize - 1))) ||
  170. (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) {
  171. //
  172. // Check for sector sizes that are not a power of two.
  173. //
  174. if ((deviceObject->SectorSize &&
  175. Length % deviceObject->SectorSize) ||
  176. (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) {
  177. ObDereferenceObject( fileObject );
  178. return STATUS_INVALID_PARAMETER;
  179. }
  180. }
  181. //
  182. // If a ByteOffset parameter was specified, ensure that it is
  183. // is of the proper type.
  184. //
  185. if (ARGUMENT_PRESENT( ByteOffset )) {
  186. if (fileOffset.LowPart == FILE_WRITE_TO_END_OF_FILE &&
  187. fileOffset.HighPart == -1) {
  188. NOTHING;
  189. } else if (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
  190. fileOffset.HighPart == -1 &&
  191. (fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  192. NOTHING;
  193. } else if (deviceObject->SectorSize &&
  194. (fileOffset.LowPart & (deviceObject->SectorSize - 1))) {
  195. ObDereferenceObject( fileObject );
  196. return STATUS_INVALID_PARAMETER;
  197. }
  198. }
  199. }
  200. //
  201. // Finally, ensure that if there is a key parameter specified it
  202. // is readable by the caller.
  203. //
  204. if (ARGUMENT_PRESENT( Key )) {
  205. keyValue = ProbeAndReadUlong( Key );
  206. }
  207. } except(IopExceptionFilter( GetExceptionInformation(), &exceptionCode )) {
  208. //
  209. // An exception was incurred while attempting to probe the
  210. // caller's parameters. Simply cleanup, dereference the file
  211. // object, and return with the appropriate status code.
  212. //
  213. ObDereferenceObject( fileObject );
  214. return exceptionCode;
  215. }
  216. } else {
  217. //
  218. // The caller's mode is kernel. Get the appropriate parameters to
  219. // their expected locations without making all of the checks.
  220. //
  221. if (ARGUMENT_PRESENT( ByteOffset )) {
  222. fileOffset = *ByteOffset;
  223. }
  224. if (ARGUMENT_PRESENT( Key )) {
  225. keyValue = *Key;
  226. }
  227. #if DBG
  228. if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
  229. //
  230. // The file was opened without intermediate buffering enabled.
  231. // Check that the Buffer is properly aligned, and that the
  232. // length is an integral number of the block size.
  233. //
  234. if ((deviceObject->SectorSize &&
  235. (Length & (deviceObject->SectorSize - 1))) ||
  236. (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) {
  237. //
  238. // Check for sector sizes that are not a power of two.
  239. //
  240. if ((deviceObject->SectorSize &&
  241. Length % deviceObject->SectorSize) ||
  242. (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) {
  243. ObDereferenceObject( fileObject );
  244. ASSERT( FALSE );
  245. return STATUS_INVALID_PARAMETER;
  246. }
  247. }
  248. //
  249. // If a ByteOffset parameter was specified, ensure that it is
  250. // is of the proper type.
  251. //
  252. if (ARGUMENT_PRESENT( ByteOffset )) {
  253. if (fileOffset.LowPart == FILE_WRITE_TO_END_OF_FILE &&
  254. fileOffset.HighPart == -1) {
  255. NOTHING;
  256. } else if (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
  257. fileOffset.HighPart == -1 &&
  258. (fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  259. NOTHING;
  260. } else if (deviceObject->SectorSize &&
  261. (fileOffset.LowPart & (deviceObject->SectorSize - 1))) {
  262. ObDereferenceObject( fileObject );
  263. ASSERT( FALSE );
  264. return STATUS_INVALID_PARAMETER;
  265. }
  266. }
  267. }
  268. #endif // DBG
  269. }
  270. //
  271. // If the caller has only append access to the file, ignore the input
  272. // parameters and set the ByteOffset to indicate that this write is
  273. // to the end of the file. Otherwise, ensure that the parameters are
  274. // valid.
  275. //
  276. if (SeComputeGrantedAccesses( grantedAccess, FILE_APPEND_DATA | FILE_WRITE_DATA ) == FILE_APPEND_DATA) {
  277. //
  278. // This is an append operation to the end of a file. Set the
  279. // ByteOffset parameter to give drivers a consistent view of
  280. // this type of call.
  281. //
  282. fileOffset.LowPart = FILE_WRITE_TO_END_OF_FILE;
  283. fileOffset.HighPart = -1;
  284. }
  285. //
  286. // Get the address of the event object and set the event to the Not-
  287. // Signaled state, if an event was specified. Note here too, that if
  288. // the handle does not refer to an event, then the reference will fail.
  289. //
  290. if (ARGUMENT_PRESENT( Event )) {
  291. status = ObReferenceObjectByHandle( Event,
  292. EVENT_MODIFY_STATE,
  293. ExEventObjectType,
  294. requestorMode,
  295. (PVOID *) &eventObject,
  296. NULL );
  297. if (!NT_SUCCESS( status )) {
  298. ObDereferenceObject( fileObject );
  299. return status;
  300. } else {
  301. KeClearEvent( eventObject );
  302. }
  303. }
  304. //
  305. // Get the address of the fast io dispatch structure.
  306. //
  307. fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
  308. //
  309. // Make a special check here to determine whether this is a synchronous
  310. // I/O operation. If it is, then wait here until the file is owned by
  311. // the current thread. If the wait terminates with an alerted status,
  312. // then cleanup and return the alerted status. This allows the caller
  313. // specify FILE_SYNCHRONOUS_IO_ALERT as a synchronous I/O option.
  314. //
  315. // If everything works, then check to see whether a ByteOffset parameter
  316. // was supplied. If not, or if it was and it is set to the "use file
  317. // pointer position", then initialize the file offset to be whatever
  318. // the current byte offset into the file is according to the file pointer
  319. // context information in the file object.
  320. //
  321. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  322. BOOLEAN interrupted;
  323. if (!IopAcquireFastLock( fileObject )) {
  324. status = IopAcquireFileObjectLock( fileObject,
  325. requestorMode,
  326. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  327. &interrupted );
  328. if (interrupted) {
  329. if (eventObject) {
  330. ObDereferenceObject( eventObject );
  331. }
  332. ObDereferenceObject( fileObject );
  333. return status;
  334. }
  335. }
  336. synchronousIo = TRUE;
  337. if ((!ARGUMENT_PRESENT( ByteOffset ) && !fileOffset.LowPart ) ||
  338. (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
  339. fileOffset.HighPart == -1 )) {
  340. fileOffset = fileObject->CurrentByteOffset;
  341. }
  342. //
  343. // Turbo write support. If the file is currently cached on this
  344. // file object, then call the Cache Manager directly via FsRtl
  345. // and try to successfully complete the request here. Note if
  346. // FastIoWrite returns FALSE or we get an I/O error, we simply
  347. // fall through and go the "long way" and create an Irp.
  348. //
  349. if (fileObject->PrivateCacheMap) {
  350. IO_STATUS_BLOCK localIoStatus;
  351. ASSERT(fastIoDispatch && fastIoDispatch->FastIoWrite);
  352. //
  353. // Negative file offsets are illegal.
  354. //
  355. if (fileOffset.HighPart < 0 &&
  356. (fileOffset.HighPart != -1 ||
  357. fileOffset.LowPart != FILE_WRITE_TO_END_OF_FILE)) {
  358. if (eventObject) {
  359. ObDereferenceObject( eventObject );
  360. }
  361. IopReleaseFileObjectLock( fileObject );
  362. ObDereferenceObject( fileObject );
  363. return STATUS_INVALID_PARAMETER;
  364. }
  365. if (fastIoDispatch->FastIoWrite( fileObject,
  366. &fileOffset,
  367. Length,
  368. TRUE,
  369. keyValue,
  370. Buffer,
  371. &localIoStatus,
  372. deviceObject )
  373. &&
  374. (localIoStatus.Status == STATUS_SUCCESS)) {
  375. IopUpdateWriteOperationCount( );
  376. IopUpdateWriteTransferCount( (ULONG)localIoStatus.Information );
  377. //
  378. // Carefully return the I/O status.
  379. try {
  380. *IoStatusBlock = localIoStatus;
  381. } except( EXCEPTION_EXECUTE_HANDLER ) {
  382. localIoStatus.Status = GetExceptionCode();
  383. localIoStatus.Information = 0;
  384. }
  385. //
  386. // If an event was specified, set it.
  387. //
  388. if (ARGUMENT_PRESENT( Event )) {
  389. KeSetEvent( eventObject, 0, FALSE );
  390. ObDereferenceObject( eventObject );
  391. }
  392. //
  393. // Note that the file object event need not be set to the
  394. // Signaled state, as it is already set.
  395. //
  396. //
  397. // Cleanup and return.
  398. //
  399. IopReleaseFileObjectLock( fileObject );
  400. ObDereferenceObject( fileObject );
  401. return localIoStatus.Status;
  402. }
  403. }
  404. } else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) {
  405. //
  406. // The file is not open for synchronous I/O operations, but the
  407. // caller did not specify a ByteOffset parameter. This is an error
  408. // situation, so cleanup and return with the appropriate status.
  409. //
  410. if (eventObject) {
  411. ObDereferenceObject( eventObject );
  412. }
  413. ObDereferenceObject( fileObject );
  414. return STATUS_INVALID_PARAMETER;
  415. } else {
  416. //
  417. // This is not a synchronous I/O operation.
  418. //
  419. synchronousIo = FALSE;
  420. }
  421. //
  422. // Negative file offsets are illegal.
  423. //
  424. if (fileOffset.HighPart < 0 &&
  425. (fileOffset.HighPart != -1 ||
  426. fileOffset.LowPart != FILE_WRITE_TO_END_OF_FILE)) {
  427. if (eventObject) {
  428. ObDereferenceObject( eventObject );
  429. }
  430. if (synchronousIo) {
  431. IopReleaseFileObjectLock( fileObject );
  432. }
  433. ObDereferenceObject( fileObject );
  434. return STATUS_INVALID_PARAMETER;
  435. }
  436. //
  437. // Set the file object to the Not-Signaled state.
  438. //
  439. KeClearEvent( &fileObject->Event );
  440. //
  441. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  442. // The allocation is performed with an exception handler in case the
  443. // caller does not have enough quota to allocate the packet.
  444. //
  445. irp = IopAllocateIrp( deviceObject->StackSize, TRUE );
  446. if (!irp) {
  447. //
  448. // An IRP could not be allocated. Cleanup and return an appropriate
  449. // error status code.
  450. //
  451. IopAllocateIrpCleanup( fileObject, eventObject );
  452. return STATUS_INSUFFICIENT_RESOURCES;
  453. }
  454. irp->Tail.Overlay.OriginalFileObject = fileObject;
  455. irp->Tail.Overlay.Thread = CurrentThread;
  456. irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
  457. irp->RequestorMode = requestorMode;
  458. irp->PendingReturned = FALSE;
  459. irp->Cancel = FALSE;
  460. irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
  461. //
  462. // Fill in the service independent parameters in the IRP.
  463. //
  464. irp->UserEvent = eventObject;
  465. irp->UserIosb = IoStatusBlock;
  466. irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
  467. irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
  468. //
  469. // Get a pointer to the stack location for the first driver. This will be
  470. // used to pass the original function codes and parameters. Note that
  471. // setting the major function code here also sets:
  472. //
  473. // MinorFunction = 0;
  474. // Flags = 0;
  475. // Control = 0;
  476. //
  477. irpSp = IoGetNextIrpStackLocation( irp );
  478. majorFunction = (PULONG) irpSp;
  479. *majorFunction = IRP_MJ_WRITE;
  480. irpSp->FileObject = fileObject;
  481. if (fileObject->Flags & FO_WRITE_THROUGH) {
  482. irpSp->Flags = SL_WRITE_THROUGH;
  483. }
  484. //
  485. // Now determine whether this device expects to have data buffered to it
  486. // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO
  487. // flag in the device object. If the flag is set, then a system buffer is
  488. // allocated and the caller's data is copied into it. Otherwise, a Memory
  489. // Descriptor List (MDL) is allocated and the caller's buffer is locked
  490. // down using it.
  491. //
  492. irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
  493. irp->MdlAddress = (PMDL) NULL;
  494. if (deviceObject->Flags & DO_BUFFERED_IO) {
  495. //
  496. // The device does not support direct I/O. Allocate a system buffer,
  497. // and copy the caller's data into it. This is done using an
  498. // exception handler that will perform cleanup if the operation
  499. // fails. Note that this is only done if the operation has a non-zero
  500. // length.
  501. //
  502. if (Length) {
  503. try {
  504. //
  505. // Allocate the intermediary system buffer from nonpaged pool,
  506. // charge quota for it, and copy the caller's data into it.
  507. //
  508. irp->AssociatedIrp.SystemBuffer =
  509. ExAllocatePoolWithQuota( NonPagedPoolCacheAligned, Length );
  510. RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, Buffer, Length );
  511. } except(EXCEPTION_EXECUTE_HANDLER) {
  512. //
  513. // An exception was incurred while either probing the caller's
  514. // buffer, allocating the system buffer, or copying the data
  515. // from the caller's buffer to the system buffer. Determine
  516. // what actually happened, clean everything up, and return an
  517. // appropriate error status code.
  518. //
  519. IopExceptionCleanup( fileObject,
  520. irp,
  521. eventObject,
  522. (PKEVENT) NULL );
  523. return GetExceptionCode();
  524. }
  525. //
  526. // Set the IRP_BUFFERED_IO flag in the IRP so that I/O completion
  527. // will know that this is not a direct I/O operation. Also set the
  528. // IRP_DEALLOCATE_BUFFER flag so it will deallocate the buffer.
  529. //
  530. irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  531. } else {
  532. //
  533. // This is a zero-length write. Simply indicate that this is
  534. // buffered I/O, and pass along the request. The buffer will
  535. // not be set to deallocate so the completion path does not
  536. // have to special-case the length.
  537. //
  538. irp->Flags = IRP_BUFFERED_IO;
  539. }
  540. } else if (deviceObject->Flags & DO_DIRECT_IO) {
  541. //
  542. // This is a direct I/O operation. Allocate an MDL and invoke the
  543. // memory management routine to lock the buffer into memory. This
  544. // is done using an exception handler that will perform cleanup if
  545. // the operation fails. Note that no MDL is allocated, nor is any
  546. // memory probed or locked if the length of the request was zero.
  547. //
  548. mdl = (PMDL) NULL;
  549. irp->Flags = 0;
  550. if (Length) {
  551. try {
  552. //
  553. // Allocate an MDL, charging quota for it, and hang it off of
  554. // the IRP. Probe and lock the pages associated with the
  555. // caller's buffer for read access and fill in the MDL with
  556. // the PFNs of those pages.
  557. //
  558. mdl = IoAllocateMdl( Buffer, Length, FALSE, TRUE, irp );
  559. if (mdl == NULL) {
  560. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  561. }
  562. MmProbeAndLockPages( mdl, requestorMode, IoReadAccess );
  563. } except(EXCEPTION_EXECUTE_HANDLER) {
  564. //
  565. // An exception was incurred while either allocating the MDL
  566. // or while attempting to probe and lock the caller's buffer.
  567. // Determine what actually happened, clean everything up, and
  568. // return an appropriate error status code.
  569. //
  570. IopExceptionCleanup( fileObject,
  571. irp,
  572. eventObject,
  573. (PKEVENT) NULL );
  574. return GetExceptionCode();
  575. }
  576. }
  577. } else {
  578. //
  579. // Pass the address of the caller's buffer to the device driver. It
  580. // is now up to the driver to do everything.
  581. //
  582. irp->Flags = 0;
  583. irp->UserBuffer = Buffer;
  584. }
  585. //
  586. // If this write operation is to be performed without any caching, set the
  587. // appropriate flag in the IRP so no caching is performed.
  588. //
  589. if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
  590. irp->Flags |= IRP_NOCACHE | IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION;
  591. } else {
  592. irp->Flags |= IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION;
  593. }
  594. //
  595. // Copy the caller's parameters to the service-specific portion of the
  596. // IRP.
  597. //
  598. irpSp->Parameters.Write.Length = Length;
  599. irpSp->Parameters.Write.Key = keyValue;
  600. irpSp->Parameters.Write.ByteOffset = fileOffset;
  601. //
  602. // Queue the packet, call the driver, and synchronize appopriately with
  603. // I/O completion.
  604. //
  605. status = IopSynchronousServiceTail( deviceObject,
  606. irp,
  607. fileObject,
  608. TRUE,
  609. requestorMode,
  610. synchronousIo,
  611. WriteTransfer );
  612. return status;
  613. }
  614. NTSTATUS
  615. NtWriteFileGather(
  616. IN HANDLE FileHandle,
  617. IN HANDLE Event OPTIONAL,
  618. IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
  619. IN PVOID ApcContext OPTIONAL,
  620. OUT PIO_STATUS_BLOCK IoStatusBlock,
  621. IN PFILE_SEGMENT_ELEMENT SegmentArray,
  622. IN ULONG Length,
  623. IN PLARGE_INTEGER ByteOffset OPTIONAL,
  624. IN PULONG Key OPTIONAL
  625. )
  626. /*++
  627. Routine Description:
  628. This service writes Length bytes of data from the caller's segment
  629. buffers to the file associated with FileHandle starting at
  630. StartingBlock|ByteOffset. The actual number of bytes written to the file
  631. will be returned in the second longword of the IoStatusBlock.
  632. If the writer has the file open for APPEND access, then the data will be
  633. written to the current EOF mark. The StartingBlock and ByteOffset are
  634. ignored if the caller has APPEND access.
  635. Arguments:
  636. FileHandle - Supplies a handle to the file to be written.
  637. Event - Optionally supplies an event to be set to the Signaled state when
  638. the write operation is complete.
  639. ApcRoutine - Optionally supplies an APC routine to be executed when the
  640. write operation is complete.
  641. ApcContext - Supplies a context parameter to be passed to the APC routine
  642. when it is invoked, if an APC routine was specified.
  643. IoStatusBlock - Supplies the address of the caller's I/O status block.
  644. SegmentArray - An array of buffer segment pointers that specify
  645. where the data should be read from.
  646. Length - Length, in bytes, of the data to be written to the file.
  647. ByteOffset - Specifies the starting byte offset within the file to begin
  648. the write operation. If not specified and the file is open for
  649. synchronous I/O, then the current file position is used. If the
  650. file is not opened for synchronous I/O and the parameter is not
  651. specified, then it is in error.
  652. Key - Optionally specifies a key to be used if there are locks associated
  653. with the file.
  654. Return Value:
  655. The status returned is success if the write operation was properly queued
  656. to the I/O system. Once the write completes the status of the operation
  657. can be determined by examining the Status field of the I/O status block.
  658. Notes:
  659. This interface is only supported for no buffering and asynchronous I/O.
  660. --*/
  661. {
  662. PIRP irp;
  663. NTSTATUS status;
  664. PFILE_OBJECT fileObject;
  665. PDEVICE_OBJECT deviceObject;
  666. PFAST_IO_DISPATCH fastIoDispatch;
  667. PFILE_SEGMENT_ELEMENT capturedArray = NULL;
  668. KPROCESSOR_MODE requestorMode;
  669. PMDL mdl;
  670. PIO_STACK_LOCATION irpSp;
  671. ACCESS_MASK grantedAccess;
  672. OBJECT_HANDLE_INFORMATION handleInformation;
  673. NTSTATUS exceptionCode;
  674. PKEVENT eventObject = (PKEVENT) NULL;
  675. ULONG elementCount;
  676. ULONG keyValue = 0;
  677. LARGE_INTEGER fileOffset = {0,0};
  678. PULONG majorFunction;
  679. ULONG i;
  680. BOOLEAN synchronousIo;
  681. PETHREAD CurrentThread;
  682. PAGED_CODE();
  683. //
  684. // Get the previous mode; i.e., the mode of the caller.
  685. //
  686. CurrentThread = PsGetCurrentThread ();
  687. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  688. //
  689. // Reference the file object so the target device can be found and the
  690. // access rights mask can be used in the following checks for callers in
  691. // user mode. Note that if the handle does not refer to a file object,
  692. // then it will fail.
  693. //
  694. status = ObReferenceObjectByHandle( FileHandle,
  695. 0L,
  696. IoFileObjectType,
  697. requestorMode,
  698. (PVOID *) &fileObject,
  699. &handleInformation);
  700. if (!NT_SUCCESS( status )) {
  701. return status;
  702. }
  703. grantedAccess = handleInformation.GrantedAccess;
  704. //
  705. // Get the address of the target device object.
  706. //
  707. deviceObject = IoGetRelatedDeviceObject( fileObject );
  708. //
  709. // Verify this is a valid gather write request. In particular it must
  710. // be non cached, asynchronous, use completion ports, non buffer I/O
  711. // device and directed at a file system device.
  712. //
  713. if (!(fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) ||
  714. (fileObject->Flags & FO_SYNCHRONOUS_IO) ||
  715. deviceObject->Flags & DO_BUFFERED_IO ||
  716. (deviceObject->DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM &&
  717. deviceObject->DeviceType != FILE_DEVICE_DFS &&
  718. deviceObject->DeviceType != FILE_DEVICE_TAPE_FILE_SYSTEM &&
  719. deviceObject->DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM &&
  720. deviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
  721. deviceObject->DeviceType != FILE_DEVICE_FILE_SYSTEM &&
  722. deviceObject->DeviceType != FILE_DEVICE_DFS_VOLUME)) {
  723. ObDereferenceObject( fileObject );
  724. return STATUS_INVALID_PARAMETER;
  725. }
  726. elementCount = BYTES_TO_PAGES( Length );
  727. //
  728. // Check to see if the requestor mode was user. If so, perform a bunch
  729. // of extra checks.
  730. //
  731. if (requestorMode != KernelMode) {
  732. //
  733. // The caller's access mode is not kernel so probe each of the arguments
  734. // and capture them as necessary. If any failures occur, the condition
  735. // handler will be invoked to handle them. It will simply cleanup and
  736. // return an access violation status code back to the system service
  737. // dispatcher.
  738. //
  739. //
  740. // Check to ensure that the caller has either WRITE_DATA or APPEND_DATA
  741. // access to the file. If not, cleanup and return an access denied
  742. // error status value. Note that if this is a pipe then the APPEND_DATA
  743. // access check may not be made since this access code is overlaid with
  744. // CREATE_PIPE_INSTANCE access.
  745. //
  746. if (!SeComputeGrantedAccesses( grantedAccess, (!(fileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) | FILE_WRITE_DATA )) {
  747. ObDereferenceObject( fileObject );
  748. return STATUS_ACCESS_DENIED;
  749. }
  750. //
  751. // Attempt to probe the caller's parameters within the exception
  752. // handler block.
  753. //
  754. try {
  755. //
  756. // The IoStatusBlock parameter must be writeable by the caller.
  757. //
  758. ProbeForWriteIoStatusEx( IoStatusBlock , ApcRoutine);
  759. //
  760. // The SegmentArray paramter must be accessible.
  761. //
  762. #ifdef _X86_
  763. ProbeForRead( SegmentArray,
  764. elementCount * sizeof( FILE_SEGMENT_ELEMENT ),
  765. sizeof( ULONG )
  766. );
  767. #elif defined(_WIN64)
  768. //
  769. // If we are a wow64 process, follow the X86 rules
  770. //
  771. if (PsGetCurrentProcess()->Wow64Process) {
  772. ProbeForRead( SegmentArray,
  773. elementCount * sizeof( FILE_SEGMENT_ELEMENT ),
  774. sizeof( ULONG )
  775. );
  776. } else {
  777. ProbeForRead( SegmentArray,
  778. elementCount * sizeof( FILE_SEGMENT_ELEMENT ),
  779. TYPE_ALIGNMENT( FILE_SEGMENT_ELEMENT )
  780. );
  781. }
  782. #else
  783. ProbeForRead( SegmentArray,
  784. elementCount * sizeof( FILE_SEGMENT_ELEMENT ),
  785. TYPE_ALIGNMENT( FILE_SEGMENT_ELEMENT )
  786. );
  787. #endif
  788. if (Length != 0) {
  789. //
  790. // Capture the segment array so it cannot be changed after
  791. // it has been looked at.
  792. //
  793. capturedArray = ExAllocatePoolWithQuota( PagedPool,
  794. elementCount * sizeof( FILE_SEGMENT_ELEMENT )
  795. );
  796. RtlCopyMemory( capturedArray,
  797. SegmentArray,
  798. elementCount * sizeof( FILE_SEGMENT_ELEMENT )
  799. );
  800. SegmentArray = capturedArray;
  801. //
  802. // Verify that all the addresses are page aligned.
  803. //
  804. for (i = 0; i < elementCount; i++) {
  805. if ( SegmentArray[i].Alignment & (PAGE_SIZE - 1)) {
  806. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  807. }
  808. }
  809. }
  810. //
  811. // If this file has an I/O completion port associated w/it, then
  812. // ensure that the caller did not supply an APC routine, as the
  813. // two are mutually exclusive methods for I/O completion
  814. // notification.
  815. //
  816. if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) {
  817. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  818. }
  819. //
  820. // Check that the ByteOffset parameter is readable from the
  821. // caller's mode, if one was specified, and capture it.
  822. //
  823. if (ARGUMENT_PRESENT( ByteOffset )) {
  824. ProbeForReadSmallStructure( ByteOffset,
  825. sizeof( LARGE_INTEGER ),
  826. sizeof( ULONG ) );
  827. fileOffset = *ByteOffset;
  828. }
  829. //
  830. // Check to see whether the caller has opened the file without
  831. // intermediate buffering. If so, perform the following ByteOffset
  832. // parameter check differently.
  833. //
  834. if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
  835. //
  836. // The file was opened without intermediate buffering enabled.
  837. // Check that the Buffer is properly aligned, and that the
  838. // length is an integral number of 512-byte blocks.
  839. //
  840. if ((deviceObject->SectorSize &&
  841. (Length & (deviceObject->SectorSize - 1)))) {
  842. //
  843. // Check for sector sizes that are not a power of two.
  844. //
  845. if ((deviceObject->SectorSize &&
  846. Length % deviceObject->SectorSize) ) {
  847. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  848. }
  849. }
  850. //
  851. // If a ByteOffset parameter was specified, ensure that it is
  852. // is of the proper type.
  853. //
  854. if (ARGUMENT_PRESENT( ByteOffset )) {
  855. if (fileOffset.LowPart == FILE_WRITE_TO_END_OF_FILE &&
  856. fileOffset.HighPart == -1) {
  857. NOTHING;
  858. } else if (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
  859. fileOffset.HighPart == -1 &&
  860. (fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  861. NOTHING;
  862. } else if (deviceObject->SectorSize &&
  863. (fileOffset.LowPart & (deviceObject->SectorSize - 1))) {
  864. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  865. }
  866. }
  867. }
  868. //
  869. // Finally, ensure that if there is a key parameter specified it
  870. // is readable by the caller.
  871. //
  872. if (ARGUMENT_PRESENT( Key )) {
  873. keyValue = ProbeAndReadUlong( Key );
  874. }
  875. } except(IopExceptionFilter( GetExceptionInformation(), &exceptionCode )) {
  876. //
  877. // An exception was incurred while attempting to probe the
  878. // caller's parameters. Simply cleanup, dereference the file
  879. // object, and return with the appropriate status code.
  880. //
  881. ObDereferenceObject( fileObject );
  882. if (capturedArray != NULL) {
  883. ExFreePool( capturedArray );
  884. }
  885. return exceptionCode;
  886. }
  887. } else {
  888. //
  889. // The caller's mode is kernel. Get the appropriate parameters to
  890. // their expected locations without making all of the checks.
  891. //
  892. if (ARGUMENT_PRESENT( ByteOffset )) {
  893. fileOffset = *ByteOffset;
  894. }
  895. if (ARGUMENT_PRESENT( Key )) {
  896. keyValue = *Key;
  897. }
  898. #if DBG
  899. if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
  900. //
  901. // The file was opened without intermediate buffering enabled.
  902. // Check that the the length is an integral number of the block
  903. // size.
  904. //
  905. if ((deviceObject->SectorSize &&
  906. (Length & (deviceObject->SectorSize - 1)))) {
  907. //
  908. // Check for sector sizes that are not a power of two.
  909. //
  910. if ((deviceObject->SectorSize &&
  911. Length % deviceObject->SectorSize)) {
  912. ObDereferenceObject( fileObject );
  913. ASSERT( FALSE );
  914. return STATUS_INVALID_PARAMETER;
  915. }
  916. }
  917. //
  918. // If a ByteOffset parameter was specified, ensure that it is
  919. // is of the proper type.
  920. //
  921. if (ARGUMENT_PRESENT( ByteOffset )) {
  922. if (fileOffset.LowPart == FILE_WRITE_TO_END_OF_FILE &&
  923. fileOffset.HighPart == -1) {
  924. NOTHING;
  925. } else if (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
  926. fileOffset.HighPart == -1 &&
  927. (fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  928. NOTHING;
  929. } else if (deviceObject->SectorSize &&
  930. (fileOffset.LowPart & (deviceObject->SectorSize - 1))) {
  931. ObDereferenceObject( fileObject );
  932. ASSERT( FALSE );
  933. return STATUS_INVALID_PARAMETER;
  934. }
  935. }
  936. }
  937. if (Length != 0) {
  938. //
  939. // Verify that all the addresses are page aligned.
  940. //
  941. for (i = 0; i < elementCount; i++) {
  942. if ( SegmentArray[i].Alignment & (PAGE_SIZE - 1)) {
  943. ObDereferenceObject( fileObject );
  944. ASSERT(FALSE);
  945. return STATUS_INVALID_PARAMETER;
  946. }
  947. }
  948. }
  949. #endif // DBG
  950. }
  951. //
  952. // If the caller has only append access to the file, ignore the input
  953. // parameters and set the ByteOffset to indicate that this write is
  954. // to the end of the file. Otherwise, ensure that the parameters are
  955. // valid.
  956. //
  957. if (SeComputeGrantedAccesses( grantedAccess, FILE_APPEND_DATA | FILE_WRITE_DATA ) == FILE_APPEND_DATA) {
  958. //
  959. // This is an append operation to the end of a file. Set the
  960. // ByteOffset parameter to give drivers a consistent view of
  961. // this type of call.
  962. //
  963. fileOffset.LowPart = FILE_WRITE_TO_END_OF_FILE;
  964. fileOffset.HighPart = -1;
  965. }
  966. //
  967. // Get the address of the event object and set the event to the Not-
  968. // Signaled state, if an event was specified. Note here too, that if
  969. // the handle does not refer to an event, then the reference will fail.
  970. //
  971. if (ARGUMENT_PRESENT( Event )) {
  972. status = ObReferenceObjectByHandle( Event,
  973. EVENT_MODIFY_STATE,
  974. ExEventObjectType,
  975. requestorMode,
  976. (PVOID *) &eventObject,
  977. NULL );
  978. if (!NT_SUCCESS( status )) {
  979. ObDereferenceObject( fileObject );
  980. if (capturedArray != NULL) {
  981. ExFreePool( capturedArray );
  982. }
  983. return status;
  984. } else {
  985. KeClearEvent( eventObject );
  986. }
  987. }
  988. //
  989. // Get the address of the fast io dispatch structure.
  990. //
  991. fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
  992. //
  993. // Make a special check here to determine whether this is a synchronous
  994. // I/O operation. If it is, then wait here until the file is owned by
  995. // the current thread. If the wait terminates with an alerted status,
  996. // then cleanup and return the alerted status. This allows the caller
  997. // specify FILE_SYNCHRONOUS_IO_ALERT as a synchronous I/O option.
  998. //
  999. // If everything works, then check to see whether a ByteOffset parameter
  1000. // was supplied. If not, or if it was and it is set to the "use file
  1001. // pointer position", then initialize the file offset to be whatever
  1002. // the current byte offset into the file is according to the file pointer
  1003. // context information in the file object.
  1004. //
  1005. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  1006. BOOLEAN interrupted;
  1007. if (!IopAcquireFastLock( fileObject )) {
  1008. status = IopAcquireFileObjectLock( fileObject,
  1009. requestorMode,
  1010. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  1011. &interrupted );
  1012. if (interrupted) {
  1013. if (eventObject) {
  1014. ObDereferenceObject( eventObject );
  1015. }
  1016. ObDereferenceObject( fileObject );
  1017. if (capturedArray != NULL) {
  1018. ExFreePool( capturedArray );
  1019. }
  1020. return status;
  1021. }
  1022. }
  1023. synchronousIo = TRUE;
  1024. if ((!ARGUMENT_PRESENT( ByteOffset ) && !fileOffset.LowPart ) ||
  1025. (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
  1026. fileOffset.HighPart == -1 )) {
  1027. fileOffset = fileObject->CurrentByteOffset;
  1028. }
  1029. } else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) {
  1030. //
  1031. // The file is not open for synchronous I/O operations, but the
  1032. // caller did not specify a ByteOffset parameter. This is an error
  1033. // situation, so cleanup and return with the appropriate status.
  1034. //
  1035. if (eventObject) {
  1036. ObDereferenceObject( eventObject );
  1037. }
  1038. ObDereferenceObject( fileObject );
  1039. if (capturedArray != NULL) {
  1040. ExFreePool( capturedArray );
  1041. }
  1042. return STATUS_INVALID_PARAMETER;
  1043. } else {
  1044. //
  1045. // This is not a synchronous I/O operation.
  1046. //
  1047. synchronousIo = FALSE;
  1048. }
  1049. //
  1050. // Negative file offsets are illegal.
  1051. //
  1052. if (fileOffset.HighPart < 0 &&
  1053. (fileOffset.HighPart != -1 ||
  1054. fileOffset.LowPart != FILE_WRITE_TO_END_OF_FILE)) {
  1055. if (eventObject) {
  1056. ObDereferenceObject( eventObject );
  1057. }
  1058. if (synchronousIo) {
  1059. IopReleaseFileObjectLock( fileObject );
  1060. }
  1061. ObDereferenceObject( fileObject );
  1062. if (capturedArray != NULL) {
  1063. ExFreePool( capturedArray );
  1064. }
  1065. return STATUS_INVALID_PARAMETER;
  1066. }
  1067. //
  1068. // Set the file object to the Not-Signaled state.
  1069. //
  1070. KeClearEvent( &fileObject->Event );
  1071. //
  1072. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  1073. // The allocation is performed with an exception handler in case the
  1074. // caller does not have enough quota to allocate the packet.
  1075. //
  1076. irp = IopAllocateIrp( deviceObject->StackSize, TRUE );
  1077. if (!irp) {
  1078. //
  1079. // An IRP could not be allocated. Cleanup and return an appropriate
  1080. // error status code.
  1081. //
  1082. IopAllocateIrpCleanup( fileObject, eventObject );
  1083. if (capturedArray != NULL) {
  1084. ExFreePool( capturedArray );
  1085. }
  1086. return STATUS_INSUFFICIENT_RESOURCES;
  1087. }
  1088. irp->Tail.Overlay.OriginalFileObject = fileObject;
  1089. irp->Tail.Overlay.Thread = CurrentThread;
  1090. irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
  1091. irp->RequestorMode = requestorMode;
  1092. irp->PendingReturned = FALSE;
  1093. irp->Cancel = FALSE;
  1094. irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
  1095. //
  1096. // Fill in the service independent parameters in the IRP.
  1097. //
  1098. irp->UserEvent = eventObject;
  1099. irp->UserIosb = IoStatusBlock;
  1100. irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
  1101. irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
  1102. //
  1103. // Get a pointer to the stack location for the first driver. This will be
  1104. // used to pass the original function codes and parameters. Note that
  1105. // setting the major function code here also sets:
  1106. //
  1107. // MinorFunction = 0;
  1108. // Flags = 0;
  1109. // Control = 0;
  1110. //
  1111. irpSp = IoGetNextIrpStackLocation( irp );
  1112. majorFunction = (PULONG) irpSp;
  1113. *majorFunction = IRP_MJ_WRITE;
  1114. irpSp->FileObject = fileObject;
  1115. if (fileObject->Flags & FO_WRITE_THROUGH) {
  1116. irpSp->Flags = SL_WRITE_THROUGH;
  1117. }
  1118. //
  1119. // Now determine whether this device expects to have data buffered to it
  1120. // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO
  1121. // flag in the device object. If the flag is set, then a system buffer is
  1122. // allocated and the caller's data is copied into it. Otherwise, a Memory
  1123. // Descriptor List (MDL) is allocated and the caller's buffer is locked
  1124. // down using it.
  1125. //
  1126. irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
  1127. irp->MdlAddress = (PMDL) NULL;
  1128. //
  1129. // This is a direct I/O operation. Allocate an MDL and invoke the
  1130. // memory management routine to lock the buffer into memory. This
  1131. // is done using an exception handler that will perform cleanup if
  1132. // the operation fails. Note that no MDL is allocated, nor is any
  1133. // memory probed or locked if the length of the request was zero.
  1134. //
  1135. mdl = (PMDL) NULL;
  1136. irp->Flags = 0;
  1137. if (Length) {
  1138. try {
  1139. //
  1140. // Allocate an MDL, charging quota for it, and hang it off of
  1141. // the IRP. Probe and lock the pages associated with the
  1142. // caller's buffer for write access and fill in the MDL with
  1143. // the PFNs of those pages.
  1144. //
  1145. mdl = IoAllocateMdl( (PVOID)(ULONG_PTR) SegmentArray[0].Buffer, Length, FALSE, TRUE, irp );
  1146. if (mdl == NULL) {
  1147. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1148. }
  1149. //
  1150. // The address of the first file segment is used as a base
  1151. // address.
  1152. //
  1153. MmProbeAndLockSelectedPages( mdl,
  1154. SegmentArray,
  1155. requestorMode,
  1156. IoReadAccess );
  1157. irp->UserBuffer = (PVOID)(ULONG_PTR) SegmentArray[0].Buffer;
  1158. } except(EXCEPTION_EXECUTE_HANDLER) {
  1159. //
  1160. // An exception was incurred while either allocating the MDL
  1161. // or while attempting to probe and lock the caller's buffer.
  1162. // Determine what actually happened, clean everything up, and
  1163. // return an appropriate error status code.
  1164. //
  1165. IopExceptionCleanup( fileObject,
  1166. irp,
  1167. eventObject,
  1168. (PKEVENT) NULL );
  1169. if (capturedArray != NULL) {
  1170. ExFreePool( capturedArray );
  1171. }
  1172. return GetExceptionCode();
  1173. }
  1174. }
  1175. //
  1176. // We are done with the captured buffer.
  1177. //
  1178. if (capturedArray != NULL) {
  1179. ExFreePool( capturedArray );
  1180. }
  1181. //
  1182. // If this write operation is to be performed without any caching, set the
  1183. // appropriate flag in the IRP so no caching is performed.
  1184. //
  1185. if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
  1186. irp->Flags |= IRP_NOCACHE | IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION;
  1187. } else {
  1188. irp->Flags |= IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION;
  1189. }
  1190. //
  1191. // Copy the caller's parameters to the service-specific portion of the
  1192. // IRP.
  1193. //
  1194. irpSp->Parameters.Write.Length = Length;
  1195. irpSp->Parameters.Write.Key = keyValue;
  1196. irpSp->Parameters.Write.ByteOffset = fileOffset;
  1197. //
  1198. // Queue the packet, call the driver, and synchronize appopriately with
  1199. // I/O completion.
  1200. //
  1201. status = IopSynchronousServiceTail( deviceObject,
  1202. irp,
  1203. fileObject,
  1204. TRUE,
  1205. requestorMode,
  1206. synchronousIo,
  1207. WriteTransfer );
  1208. return status;
  1209. }