Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

write.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989-1993 Microsoft Corporation 00004 00005 Module Name: 00006 00007 write.c 00008 00009 Abstract: 00010 00011 This module contains the code to implement the NtWriteFile system service. 00012 00013 Author: 00014 00015 Darryl E. Havens (darrylh) 14-Apr-1989 00016 00017 Environment: 00018 00019 Kernel mode 00020 00021 Revision History: 00022 00023 00024 --*/ 00025 00026 #include "iop.h" 00027 00028 #ifdef ALLOC_PRAGMA 00029 #pragma alloc_text(PAGE, NtWriteFile) 00030 #pragma alloc_text(PAGE, NtWriteFile64) 00031 #pragma alloc_text(PAGE, NtWriteFileGather) 00032 #endif 00033 00034 NTSTATUS 00035 NtWriteFile( 00036 IN HANDLE FileHandle, 00037 IN HANDLE Event OPTIONAL, 00038 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 00039 IN PVOID ApcContext OPTIONAL, 00040 OUT PIO_STATUS_BLOCK IoStatusBlock, 00041 IN PVOID Buffer, 00042 IN ULONG Length, 00043 IN PLARGE_INTEGER ByteOffset OPTIONAL, 00044 IN PULONG Key OPTIONAL 00045 ) 00046 00047 /*++ 00048 00049 Routine Description: 00050 00051 This service writes Length bytes of data from the caller's Buffer to the 00052 file associated with FileHandle starting at StartingBlock|ByteOffset. 00053 The actual number of bytes written to the file will be returned in the 00054 second longword of the IoStatusBlock. 00055 00056 If the writer has the file open for APPEND access, then the data will be 00057 written to the current EOF mark. The StartingBlock and ByteOffset are 00058 ignored if the caller has APPEND access. 00059 00060 Arguments: 00061 00062 FileHandle - Supplies a handle to the file to be written. 00063 00064 Event - Optionally supplies an event to be set to the Signaled state when 00065 the write operation is complete. 00066 00067 ApcRoutine - Optionally supplies an APC routine to be executed when the 00068 write operation is complete. 00069 00070 ApcContext - Supplies a context parameter to be passed to the APC routine 00071 when it is invoked, if an APC routine was specified. 00072 00073 IoStatusBlock - Supplies the address of the caller's I/O status block. 00074 00075 Buffer - Supplies the address of the buffer containing data to be written 00076 to the file. 00077 00078 Length - Length, in bytes, of the data to be written to the file. 00079 00080 ByteOffset - Specifies the starting byte offset within the file to begin 00081 the write operation. If not specified and the file is open for 00082 synchronous I/O, then the current file position is used. If the 00083 file is not opened for synchronous I/O and the parameter is not 00084 specified, then it is in error. 00085 00086 Key - Optionally specifies a key to be used if there are locks associated 00087 with the file. 00088 00089 Return Value: 00090 00091 The status returned is success if the write operation was properly queued 00092 to the I/O system. Once the write completes the status of the operation 00093 can be determined by examining the Status field of the I/O status block. 00094 00095 --*/ 00096 00097 { 00098 PIRP irp; 00099 NTSTATUS status; 00100 PFILE_OBJECT fileObject; 00101 PDEVICE_OBJECT deviceObject; 00102 PFAST_IO_DISPATCH fastIoDispatch; 00103 KPROCESSOR_MODE requestorMode; 00104 PMDL mdl; 00105 PIO_STACK_LOCATION irpSp; 00106 ACCESS_MASK grantedAccess; 00107 OBJECT_HANDLE_INFORMATION handleInformation; 00108 NTSTATUS exceptionCode; 00109 BOOLEAN synchronousIo; 00110 PKEVENT eventObject = (PKEVENT) NULL; 00111 ULONG keyValue = 0; 00112 LARGE_INTEGER fileOffset = {0,0}; 00113 PULONG majorFunction; 00114 00115 PAGED_CODE(); 00116 00117 // 00118 // Get the previous mode; i.e., the mode of the caller. 00119 // 00120 00121 requestorMode = KeGetPreviousMode(); 00122 00123 // 00124 // Reference the file object so the target device can be found and the 00125 // access rights mask can be used in the following checks for callers in 00126 // user mode. Note that if the handle does not refer to a file object, 00127 // then it will fail. 00128 // 00129 00130 status = ObReferenceObjectByHandle( FileHandle, 00131 0L, 00132 IoFileObjectType, 00133 requestorMode, 00134 (PVOID *) &fileObject, 00135 &handleInformation); 00136 if (!NT_SUCCESS( status )) { 00137 return status; 00138 } 00139 00140 grantedAccess = handleInformation.GrantedAccess; 00141 00142 // 00143 // Get the address of the target device object. 00144 // 00145 00146 deviceObject = IoGetRelatedDeviceObject( fileObject ); 00147 00148 // 00149 // Check to see if the requestor mode was user. If so, perform a bunch 00150 // of extra checks. 00151 // 00152 00153 if (requestorMode != KernelMode) { 00154 00155 // 00156 // The caller's access mode is not kernel so probe each of the arguments 00157 // and capture them as necessary. If any failures occur, the condition 00158 // handler will be invoked to handle them. It will simply cleanup and 00159 // return an access violation status code back to the system service 00160 // dispatcher. 00161 // 00162 00163 // 00164 // Check to ensure that the caller has either WRITE_DATA or APPEND_DATA 00165 // access to the file. If not, cleanup and return an access denied 00166 // error status value. Note that if this is a pipe then the APPEND_DATA 00167 // access check may not be made since this access code is overlaid with 00168 // CREATE_PIPE_INSTANCE access. 00169 // 00170 00171 if (!SeComputeGrantedAccesses( grantedAccess, (!(fileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) | FILE_WRITE_DATA )) { 00172 ObDereferenceObject( fileObject ); 00173 return STATUS_ACCESS_DENIED; 00174 } 00175 00176 // 00177 // Attempt to probe the caller's parameters within the exception 00178 // handler block. 00179 // 00180 00181 try { 00182 00183 // 00184 // The IoStatusBlock parameter must be writeable by the caller. 00185 // 00186 00187 ProbeForWriteIoStatusEx( IoStatusBlock , ApcRoutine); 00188 00189 // 00190 // The caller's data buffer must be readable from the caller's 00191 // mode. This check ensures that this is the case. Since the 00192 // buffer address is captured, the caller cannot change it, 00193 // even though he/she can change the protection from another 00194 // thread. This error will be caught by the probe/lock or 00195 // buffer copy operations later. 00196 // 00197 00198 ProbeForRead( Buffer, Length, sizeof( UCHAR ) ); 00199 00200 // 00201 // If this file has an I/O completion port associated w/it, then 00202 // ensure that the caller did not supply an APC routine, as the 00203 // two are mutually exclusive methods for I/O completion 00204 // notification. 00205 // 00206 00207 if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) { 00208 ObDereferenceObject( fileObject ); 00209 return STATUS_INVALID_PARAMETER; 00210 } 00211 00212 // 00213 // Check that the ByteOffset parameter is readable from the 00214 // caller's mode, if one was specified, and capture it. 00215 // 00216 00217 if (ARGUMENT_PRESENT( ByteOffset )) { 00218 ProbeForRead( ByteOffset, 00219 sizeof( LARGE_INTEGER ), 00220 sizeof( ULONG ) ); 00221 fileOffset = *ByteOffset; 00222 } 00223 00224 // 00225 // Check to see whether the caller has opened the file without 00226 // intermediate buffering. If so, perform the following Buffer 00227 // and ByteOffset parameter checks differently. 00228 // 00229 00230 if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) { 00231 00232 // 00233 // The file was opened without intermediate buffering enabled. 00234 // Check that the Buffer is properly aligned, and that the 00235 // length is an integral number of the block size. 00236 // 00237 00238 if ((deviceObject->SectorSize && 00239 (Length & (deviceObject->SectorSize - 1))) || 00240 (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) { 00241 00242 // 00243 // Check for sector sizes that are not a power of two. 00244 // 00245 00246 if ((deviceObject->SectorSize && 00247 Length % deviceObject->SectorSize) || 00248 (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) { 00249 ObDereferenceObject( fileObject ); 00250 return STATUS_INVALID_PARAMETER; 00251 } 00252 } 00253 00254 // 00255 // If a ByteOffset parameter was specified, ensure that it is 00256 // is of the proper type. 00257 // 00258 00259 if (ARGUMENT_PRESENT( ByteOffset )) { 00260 if (fileOffset.LowPart == FILE_WRITE_TO_END_OF_FILE && 00261 fileOffset.HighPart == -1) { 00262 NOTHING; 00263 } else if (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && 00264 fileOffset.HighPart == -1 && 00265 (fileObject->Flags & FO_SYNCHRONOUS_IO)) { 00266 NOTHING; 00267 } else if (deviceObject->SectorSize && 00268 (fileOffset.LowPart & (deviceObject->SectorSize - 1))) { 00269 ObDereferenceObject( fileObject ); 00270 return STATUS_INVALID_PARAMETER; 00271 } 00272 } 00273 } 00274 00275 // 00276 // Finally, ensure that if there is a key parameter specified it 00277 // is readable by the caller. 00278 // 00279 00280 if (ARGUMENT_PRESENT( Key )) { 00281 keyValue = ProbeAndReadUlong( Key ); 00282 } 00283 00284 } except(IopExceptionFilter( GetExceptionInformation(), &exceptionCode )) { 00285 00286 // 00287 // An exception was incurred while attempting to probe the 00288 // caller's parameters. Simply cleanup, dereference the file 00289 // object, and return with the appropriate status code. 00290 // 00291 00292 ObDereferenceObject( fileObject ); 00293 return exceptionCode; 00294 00295 } 00296 00297 } else { 00298 00299 // 00300 // The caller's mode is kernel. Get the appropriate parameters to 00301 // their expected locations without making all of the checks. 00302 // 00303 00304 if (ARGUMENT_PRESENT( ByteOffset )) { 00305 fileOffset = *ByteOffset; 00306 } 00307 00308 if (ARGUMENT_PRESENT( Key )) { 00309 keyValue = *Key; 00310 } 00311 #if DBG 00312 if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) { 00313 00314 // 00315 // The file was opened without intermediate buffering enabled. 00316 // Check that the Buffer is properly aligned, and that the 00317 // length is an integral number of the block size. 00318 // 00319 00320 if ((deviceObject->SectorSize && 00321 (Length & (deviceObject->SectorSize - 1))) || 00322 (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) { 00323 00324 // 00325 // Check for sector sizes that are not a power of two. 00326 // 00327 00328 if ((deviceObject->SectorSize && 00329 Length % deviceObject->SectorSize) || 00330 (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) { 00331 ObDereferenceObject( fileObject ); 00332 ASSERT( FALSE ); 00333 return STATUS_INVALID_PARAMETER; 00334 } 00335 } 00336 00337 // 00338 // If a ByteOffset parameter was specified, ensure that it is 00339 // is of the proper type. 00340 // 00341 00342 if (ARGUMENT_PRESENT( ByteOffset )) { 00343 if (fileOffset.LowPart == FILE_WRITE_TO_END_OF_FILE && 00344 fileOffset.HighPart == -1) { 00345 NOTHING; 00346 } else if (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && 00347 fileOffset.HighPart == -1 && 00348 (fileObject->Flags & FO_SYNCHRONOUS_IO)) { 00349 NOTHING; 00350 } else if (deviceObject->SectorSize && 00351 (fileOffset.LowPart & (deviceObject->SectorSize - 1))) { 00352 ObDereferenceObject( fileObject ); 00353 ASSERT( FALSE ); 00354 return STATUS_INVALID_PARAMETER; 00355 } 00356 } 00357 } 00358 #endif // DBG 00359 00360 } 00361 00362 // 00363 // If the caller has only append access to the file, ignore the input 00364 // parameters and set the ByteOffset to indicate that this write is 00365 // to the end of the file. Otherwise, ensure that the parameters are 00366 // valid. 00367 // 00368 00369 if (SeComputeGrantedAccesses( grantedAccess, FILE_APPEND_DATA | FILE_WRITE_DATA ) == FILE_APPEND_DATA) { 00370 00371 // 00372 // This is an append operation to the end of a file. Set the 00373 // ByteOffset parameter to give drivers a consistent view of 00374 // this type of call. 00375 // 00376 00377 fileOffset.LowPart = FILE_WRITE_TO_END_OF_FILE; 00378 fileOffset.HighPart = -1; 00379 } 00380 00381 // 00382 // Get the address of the event object and set the event to the Not- 00383 // Signaled state, if an event was specified. Note here too, that if 00384 // the handle does not refer to an event, then the reference will fail. 00385 // 00386 00387 if (ARGUMENT_PRESENT( Event )) { 00388 status = ObReferenceObjectByHandle( Event, 00389 EVENT_MODIFY_STATE, 00390 ExEventObjectType, 00391 requestorMode, 00392 (PVOID *) &eventObject, 00393 NULL ); 00394 if (!NT_SUCCESS( status )) { 00395 ObDereferenceObject( fileObject ); 00396 return status; 00397 } else { 00398 KeClearEvent( eventObject ); 00399 } 00400 } 00401 00402 // 00403 // Get the address of the fast io dispatch structure. 00404 // 00405 00406 fastIoDispatch = deviceObject->DriverObject->FastIoDispatch; 00407 00408 // 00409 // Make a special check here to determine whether this is a synchronous 00410 // I/O operation. If it is, then wait here until the file is owned by 00411 // the current thread. If the wait terminates with an alerted status, 00412 // then cleanup and return the alerted status. This allows the caller 00413 // specify FILE_SYNCHRONOUS_IO_ALERT as a synchronous I/O option. 00414 // 00415 // If everything works, then check to see whether a ByteOffset parameter 00416 // was supplied. If not, or if it was and it is set to the "use file 00417 // pointer position", then initialize the file offset to be whatever 00418 // the current byte offset into the file is according to the file pointer 00419 // context information in the file object. 00420 // 00421 00422 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 00423 00424 BOOLEAN interrupted; 00425 00426 if (!IopAcquireFastLock( fileObject )) { 00427 status = IopAcquireFileObjectLock( fileObject, 00428 requestorMode, 00429 (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), 00430 &interrupted ); 00431 if (interrupted) { 00432 if (eventObject) { 00433 ObDereferenceObject( eventObject ); 00434 } 00435 ObDereferenceObject( fileObject ); 00436 return status; 00437 } 00438 } 00439 00440 synchronousIo = TRUE; 00441 00442 if ((!ARGUMENT_PRESENT( ByteOffset ) && !fileOffset.LowPart ) || 00443 (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && 00444 fileOffset.HighPart == -1 )) { 00445 fileOffset = fileObject->CurrentByteOffset; 00446 } 00447 00448 // 00449 // Turbo write support. If the file is currently cached on this 00450 // file object, then call the Cache Manager directly via FsRtl 00451 // and try to successfully complete the request here. Note if 00452 // FastIoWrite returns FALSE or we get an I/O error, we simply 00453 // fall through and go the "long way" and create an Irp. 00454 // 00455 00456 if (fileObject->PrivateCacheMap) { 00457 00458 IO_STATUS_BLOCK localIoStatus; 00459 00460 ASSERT(fastIoDispatch && fastIoDispatch->FastIoWrite); 00461 00462 // 00463 // Negative file offsets are illegal. 00464 // 00465 00466 if (fileOffset.HighPart < 0 && 00467 (fileOffset.HighPart != -1 || 00468 fileOffset.LowPart != FILE_WRITE_TO_END_OF_FILE)) { 00469 00470 if (eventObject) { 00471 ObDereferenceObject( eventObject ); 00472 } 00473 IopReleaseFileObjectLock( fileObject ); 00474 ObDereferenceObject( fileObject ); 00475 return STATUS_INVALID_PARAMETER; 00476 } 00477 00478 if (fastIoDispatch->FastIoWrite( fileObject, 00479 &fileOffset, 00480 Length, 00481 TRUE, 00482 keyValue, 00483 Buffer, 00484 &localIoStatus, 00485 deviceObject ) 00486 00487 && 00488 00489 (localIoStatus.Status == STATUS_SUCCESS)) { 00490 00491 IopUpdateWriteOperationCount( ); 00492 IopUpdateWriteTransferCount( (ULONG)localIoStatus.Information ); 00493 00494 // 00495 // Carefully return the I/O status. 00496 00497 try { 00498 *IoStatusBlock = localIoStatus; 00499 } except( EXCEPTION_EXECUTE_HANDLER ) { 00500 localIoStatus.Status = GetExceptionCode(); 00501 localIoStatus.Information = 0; 00502 } 00503 00504 // 00505 // If an event was specified, set it. 00506 // 00507 00508 if (ARGUMENT_PRESENT( Event )) { 00509 KeSetEvent( eventObject, 0, FALSE ); 00510 ObDereferenceObject( eventObject ); 00511 } 00512 00513 // 00514 // Note that the file object event need not be set to the 00515 // Signaled state, as it is already set. 00516 // 00517 00518 // 00519 // Cleanup and return. 00520 // 00521 00522 IopReleaseFileObjectLock( fileObject ); 00523 ObDereferenceObject( fileObject ); 00524 return localIoStatus.Status; 00525 } 00526 } 00527 00528 } else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) { 00529 00530 // 00531 // The file is not open for synchronous I/O operations, but the 00532 // caller did not specify a ByteOffset parameter. This is an error 00533 // situation, so cleanup and return with the appropriate status. 00534 // 00535 00536 if (eventObject) { 00537 ObDereferenceObject( eventObject ); 00538 } 00539 ObDereferenceObject( fileObject ); 00540 return STATUS_INVALID_PARAMETER; 00541 00542 } else { 00543 00544 // 00545 // This is not a synchronous I/O operation. 00546 // 00547 00548 synchronousIo = FALSE; 00549 } 00550 00551 // 00552 // Negative file offsets are illegal. 00553 // 00554 00555 if (fileOffset.HighPart < 0 && 00556 (fileOffset.HighPart != -1 || 00557 fileOffset.LowPart != FILE_WRITE_TO_END_OF_FILE)) { 00558 00559 if (eventObject) { 00560 ObDereferenceObject( eventObject ); 00561 } 00562 if (synchronousIo) { 00563 IopReleaseFileObjectLock( fileObject ); 00564 } 00565 ObDereferenceObject( fileObject ); 00566 return STATUS_INVALID_PARAMETER; 00567 } 00568 00569 // 00570 // Set the file object to the Not-Signaled state. 00571 // 00572 00573 KeClearEvent( &fileObject->Event ); 00574 00575 // 00576 // Allocate and initialize the I/O Request Packet (IRP) for this operation. 00577 // The allocation is performed with an exception handler in case the 00578 // caller does not have enough quota to allocate the packet. 00579 // 00580 00581 irp = IopAllocateIrp( deviceObject->StackSize, TRUE ); 00582 if (!irp) { 00583 00584 // 00585 // An IRP could not be allocated. Cleanup and return an appropriate 00586 // error status code. 00587 // 00588 00589 IopAllocateIrpCleanup( fileObject, eventObject ); 00590 00591 return STATUS_INSUFFICIENT_RESOURCES; 00592 } 00593 irp->Tail.Overlay.OriginalFileObject = fileObject; 00594 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00595 irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL; 00596 irp->RequestorMode = requestorMode; 00597 irp->PendingReturned = FALSE; 00598 irp->Cancel = FALSE; 00599 irp->CancelRoutine = (PDRIVER_CANCEL) NULL; 00600 00601 // 00602 // Fill in the service independent parameters in the IRP. 00603 // 00604 00605 irp->UserEvent = eventObject; 00606 irp->UserIosb = IoStatusBlock; 00607 irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 00608 irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 00609 00610 // 00611 // Get a pointer to the stack location for the first driver. This will be 00612 // used to pass the original function codes and parameters. Note that 00613 // setting the major function code here also sets: 00614 // 00615 // MinorFunction = 0; 00616 // Flags = 0; 00617 // Control = 0; 00618 // 00619 00620 irpSp = IoGetNextIrpStackLocation( irp ); 00621 majorFunction = (PULONG) irpSp; 00622 *majorFunction = IRP_MJ_WRITE; 00623 irpSp->FileObject = fileObject; 00624 if (fileObject->Flags & FO_WRITE_THROUGH) { 00625 irpSp->Flags = SL_WRITE_THROUGH; 00626 } 00627 00628 // 00629 // Now determine whether this device expects to have data buffered to it 00630 // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO 00631 // flag in the device object. If the flag is set, then a system buffer is 00632 // allocated and the caller's data is copied into it. Otherwise, a Memory 00633 // Descriptor List (MDL) is allocated and the caller's buffer is locked 00634 // down using it. 00635 // 00636 00637 irp->AssociatedIrp.SystemBuffer = (PVOID) NULL; 00638 irp->MdlAddress = (PMDL) NULL; 00639 00640 if (deviceObject->Flags & DO_BUFFERED_IO) { 00641 00642 // 00643 // The device does not support direct I/O. Allocate a system buffer, 00644 // and copy the caller's data into it. This is done using an 00645 // exception handler that will perform cleanup if the operation 00646 // fails. Note that this is only done if the operation has a non-zero 00647 // length. 00648 // 00649 00650 if (Length) { 00651 00652 try { 00653 00654 // 00655 // Allocate the intermediary system buffer from nonpaged pool, 00656 // charge quota for it, and copy the caller's data into it. 00657 // 00658 00659 irp->AssociatedIrp.SystemBuffer = 00660 ExAllocatePoolWithQuota( NonPagedPoolCacheAligned, Length ); 00661 RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, Buffer, Length ); 00662 00663 } except(EXCEPTION_EXECUTE_HANDLER) { 00664 00665 // 00666 // An exception was incurred while either probing the caller's 00667 // buffer, allocating the system buffer, or copying the data 00668 // from the caller's buffer to the system buffer. Determine 00669 // what actually happened, clean everything up, and return an 00670 // appropriate error status code. 00671 // 00672 00673 IopExceptionCleanup( fileObject, 00674 irp, 00675 eventObject, 00676 (PKEVENT) NULL ); 00677 00678 return GetExceptionCode(); 00679 00680 } 00681 00682 // 00683 // Set the IRP_BUFFERED_IO flag in the IRP so that I/O completion 00684 // will know that this is not a direct I/O operation. Also set the 00685 // IRP_DEALLOCATE_BUFFER flag so it will deallocate the buffer. 00686 // 00687 00688 irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; 00689 00690 } else { 00691 00692 // 00693 // This is a zero-length write. Simply indicate that this is 00694 // buffered I/O, and pass along the request. The buffer will 00695 // not be set to deallocate so the completion path does not 00696 // have to special-case the length. 00697 // 00698 00699 irp->Flags = IRP_BUFFERED_IO; 00700 } 00701 00702 } else if (deviceObject->Flags & DO_DIRECT_IO) { 00703 00704 // 00705 // This is a direct I/O operation. Allocate an MDL and invoke the 00706 // memory management routine to lock the buffer into memory. This 00707 // is done using an exception handler that will perform cleanup if 00708 // the operation fails. Note that no MDL is allocated, nor is any 00709 // memory probed or locked if the length of the request was zero. 00710 // 00711 00712 mdl = (PMDL) NULL; 00713 irp->Flags = 0; 00714 00715 if (Length) { 00716 00717 try { 00718 00719 // 00720 // Allocate an MDL, charging quota for it, and hang it off of 00721 // the IRP. Probe and lock the pages associated with the 00722 // caller's buffer for read access and fill in the MDL with 00723 // the PFNs of those pages. 00724 // 00725 00726 mdl = IoAllocateMdl( Buffer, Length, FALSE, TRUE, irp ); 00727 if (mdl == NULL) { 00728 ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); 00729 } 00730 00731 MmProbeAndLockPages( mdl, requestorMode, IoReadAccess ); 00732 00733 } except(EXCEPTION_EXECUTE_HANDLER) { 00734 00735 // 00736 // An exception was incurred while either allocating the MDL 00737 // or while attempting to probe and lock the caller's buffer. 00738 // Determine what actually happened, clean everything up, and 00739 // return an appropriate error status code. 00740 // 00741 00742 IopExceptionCleanup( fileObject, 00743 irp, 00744 eventObject, 00745 (PKEVENT) NULL ); 00746 00747 return GetExceptionCode(); 00748 } 00749 00750 } 00751 00752 } else { 00753 00754 // 00755 // Pass the address of the caller's buffer to the device driver. It 00756 // is now up to the driver to do everything. 00757 // 00758 00759 irp->Flags = 0; 00760 irp->UserBuffer = Buffer; 00761 00762 } 00763 00764 // 00765 // If this write operation is to be performed without any caching, set the 00766 // appropriate flag in the IRP so no caching is performed. 00767 // 00768 00769 if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) { 00770 irp->Flags |= IRP_NOCACHE | IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION; 00771 } else { 00772 irp->Flags |= IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION; 00773 } 00774 00775 // 00776 // Copy the caller's parameters to the service-specific portion of the 00777 // IRP. 00778 // 00779 00780 irpSp->Parameters.Write.Length = Length; 00781 irpSp->Parameters.Write.Key = keyValue; 00782 irpSp->Parameters.Write.ByteOffset = fileOffset; 00783 00784 // 00785 // Queue the packet, call the driver, and synchronize appopriately with 00786 // I/O completion. 00787 // 00788 00789 status = IopSynchronousServiceTail( deviceObject, 00790 irp, 00791 fileObject, 00792 TRUE, 00793 requestorMode, 00794 synchronousIo, 00795 WriteTransfer ); 00796 00797 return status; 00798 } 00799 00800 NTSTATUS 00801 NtWriteFileGather( 00802 IN HANDLE FileHandle, 00803 IN HANDLE Event OPTIONAL, 00804 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 00805 IN PVOID ApcContext OPTIONAL, 00806 OUT PIO_STATUS_BLOCK IoStatusBlock, 00807 IN PFILE_SEGMENT_ELEMENT SegmentArray, 00808 IN ULONG Length, 00809 IN PLARGE_INTEGER ByteOffset OPTIONAL, 00810 IN PULONG Key OPTIONAL 00811 ) 00812 00813 /*++ 00814 00815 Routine Description: 00816 00817 This service writes Length bytes of data from the caller's segment 00818 buffers to the file associated with FileHandle starting at 00819 StartingBlock|ByteOffset. The actual number of bytes written to the file 00820 will be returned in the second longword of the IoStatusBlock. 00821 00822 If the writer has the file open for APPEND access, then the data will be 00823 written to the current EOF mark. The StartingBlock and ByteOffset are 00824 ignored if the caller has APPEND access. 00825 00826 Arguments: 00827 00828 FileHandle - Supplies a handle to the file to be written. 00829 00830 Event - Optionally supplies an event to be set to the Signaled state when 00831 the write operation is complete. 00832 00833 ApcRoutine - Optionally supplies an APC routine to be executed when the 00834 write operation is complete. 00835 00836 ApcContext - Supplies a context parameter to be passed to the APC routine 00837 when it is invoked, if an APC routine was specified. 00838 00839 IoStatusBlock - Supplies the address of the caller's I/O status block. 00840 00841 SegmentArray - An array of buffer segment pointers that specify 00842 where the data should be read from. 00843 00844 Length - Length, in bytes, of the data to be written to the file. 00845 00846 ByteOffset - Specifies the starting byte offset within the file to begin 00847 the write operation. If not specified and the file is open for 00848 synchronous I/O, then the current file position is used. If the 00849 file is not opened for synchronous I/O and the parameter is not 00850 specified, then it is in error. 00851 00852 Key - Optionally specifies a key to be used if there are locks associated 00853 with the file. 00854 00855 Return Value: 00856 00857 The status returned is success if the write operation was properly queued 00858 to the I/O system. Once the write completes the status of the operation 00859 can be determined by examining the Status field of the I/O status block. 00860 00861 Notes: 00862 This interface is only supported for no buffering and asynchronous I/O. 00863 00864 --*/ 00865 00866 { 00867 PIRP irp; 00868 NTSTATUS status; 00869 PFILE_OBJECT fileObject; 00870 PDEVICE_OBJECT deviceObject; 00871 PFAST_IO_DISPATCH fastIoDispatch; 00872 PFILE_SEGMENT_ELEMENT capturedArray = NULL; 00873 KPROCESSOR_MODE requestorMode; 00874 PMDL mdl; 00875 PIO_STACK_LOCATION irpSp; 00876 ACCESS_MASK grantedAccess; 00877 OBJECT_HANDLE_INFORMATION handleInformation; 00878 NTSTATUS exceptionCode; 00879 PKEVENT eventObject = (PKEVENT) NULL; 00880 ULONG elementCount; 00881 ULONG keyValue = 0; 00882 LARGE_INTEGER fileOffset = {0,0}; 00883 PULONG majorFunction; 00884 ULONG i; 00885 BOOLEAN synchronousIo; 00886 00887 PAGED_CODE(); 00888 00889 // 00890 // Get the previous mode; i.e., the mode of the caller. 00891 // 00892 00893 requestorMode = KeGetPreviousMode(); 00894 00895 // 00896 // Reference the file object so the target device can be found and the 00897 // access rights mask can be used in the following checks for callers in 00898 // user mode. Note that if the handle does not refer to a file object, 00899 // then it will fail. 00900 // 00901 00902 status = ObReferenceObjectByHandle( FileHandle, 00903 0L, 00904 IoFileObjectType, 00905 requestorMode, 00906 (PVOID *) &fileObject, 00907 &handleInformation); 00908 if (!NT_SUCCESS( status )) { 00909 return status; 00910 } 00911 00912 grantedAccess = handleInformation.GrantedAccess; 00913 00914 // 00915 // Get the address of the target device object. 00916 // 00917 00918 deviceObject = IoGetRelatedDeviceObject( fileObject ); 00919 00920 // 00921 // Verify this is a valid gather write request. In particular it must 00922 // be non cached, asynchronous, use completion ports, non buffer I/O 00923 // device and directed at a file system device. 00924 // 00925 00926 if (!(fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) || 00927 (fileObject->Flags & FO_SYNCHRONOUS_IO) || 00928 deviceObject->Flags & DO_BUFFERED_IO || 00929 (deviceObject->DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM && 00930 deviceObject->DeviceType != FILE_DEVICE_DFS && 00931 deviceObject->DeviceType != FILE_DEVICE_TAPE_FILE_SYSTEM && 00932 deviceObject->DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM && 00933 deviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM && 00934 deviceObject->DeviceType != FILE_DEVICE_FILE_SYSTEM && 00935 deviceObject->DeviceType != FILE_DEVICE_DFS_VOLUME)) { 00936 00937 ObDereferenceObject( fileObject ); 00938 return STATUS_INVALID_PARAMETER; 00939 } 00940 00941 elementCount = BYTES_TO_PAGES( Length ); 00942 00943 // 00944 // Check to see if the requestor mode was user. If so, perform a bunch 00945 // of extra checks. 00946 // 00947 00948 if (requestorMode != KernelMode) { 00949 00950 // 00951 // The caller's access mode is not kernel so probe each of the arguments 00952 // and capture them as necessary. If any failures occur, the condition 00953 // handler will be invoked to handle them. It will simply cleanup and 00954 // return an access violation status code back to the system service 00955 // dispatcher. 00956 // 00957 00958 // 00959 // Check to ensure that the caller has either WRITE_DATA or APPEND_DATA 00960 // access to the file. If not, cleanup and return an access denied 00961 // error status value. Note that if this is a pipe then the APPEND_DATA 00962 // access check may not be made since this access code is overlaid with 00963 // CREATE_PIPE_INSTANCE access. 00964 // 00965 00966 if (!SeComputeGrantedAccesses( grantedAccess, (!(fileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) | FILE_WRITE_DATA )) { 00967 ObDereferenceObject( fileObject ); 00968 return STATUS_ACCESS_DENIED; 00969 } 00970 00971 // 00972 // Attempt to probe the caller's parameters within the exception 00973 // handler block. 00974 // 00975 00976 try { 00977 00978 // 00979 // The IoStatusBlock parameter must be writeable by the caller. 00980 // 00981 00982 ProbeForWriteIoStatusEx( IoStatusBlock , ApcRoutine); 00983 00984 // 00985 // The SegmentArray paramter must be accessible. 00986 // 00987 00988 #ifdef _X86_ 00989 ProbeForRead( SegmentArray, 00990 elementCount * sizeof( FILE_SEGMENT_ELEMENT ), 00991 sizeof( ULONG ) 00992 ); 00993 #elif defined(_WIN64) 00994 00995 // 00996 // If we are a wow64 process, follow the X86 rules 00997 // 00998 00999 if (PsGetCurrentProcess()->Wow64Process) { 01000 ProbeForRead( SegmentArray, 01001 elementCount * sizeof( FILE_SEGMENT_ELEMENT ), 01002 sizeof( ULONG ) 01003 ); 01004 } else { 01005 ProbeForRead( SegmentArray, 01006 elementCount * sizeof( FILE_SEGMENT_ELEMENT ), 01007 TYPE_ALIGNMENT( FILE_SEGMENT_ELEMENT ) 01008 ); 01009 } 01010 #else 01011 ProbeForRead( SegmentArray, 01012 elementCount * sizeof( FILE_SEGMENT_ELEMENT ), 01013 TYPE_ALIGNMENT( FILE_SEGMENT_ELEMENT ) 01014 ); 01015 #endif 01016 01017 if (Length != 0) { 01018 01019 // 01020 // Capture the segment array so it cannot be changed after 01021 // it has been looked at. 01022 // 01023 01024 capturedArray = ExAllocatePoolWithQuota( PagedPool, 01025 elementCount * sizeof( FILE_SEGMENT_ELEMENT ) 01026 ); 01027 01028 RtlCopyMemory( capturedArray, 01029 SegmentArray, 01030 elementCount * sizeof( FILE_SEGMENT_ELEMENT ) 01031 ); 01032 01033 SegmentArray = capturedArray; 01034 01035 // 01036 // Verify that all the addresses are page aligned. 01037 // 01038 01039 for (i = 0; i < elementCount; i++) { 01040 01041 if ( SegmentArray[i].Alignment & (PAGE_SIZE - 1)) { 01042 ExRaiseStatus(STATUS_INVALID_PARAMETER); 01043 } 01044 } 01045 } 01046 01047 // 01048 // If this file has an I/O completion port associated w/it, then 01049 // ensure that the caller did not supply an APC routine, as the 01050 // two are mutually exclusive methods for I/O completion 01051 // notification. 01052 // 01053 01054 if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) { 01055 01056 ExRaiseStatus(STATUS_INVALID_PARAMETER); 01057 01058 } 01059 01060 // 01061 // Check that the ByteOffset parameter is readable from the 01062 // caller's mode, if one was specified, and capture it. 01063 // 01064 01065 if (ARGUMENT_PRESENT( ByteOffset )) { 01066 ProbeForRead( ByteOffset, 01067 sizeof( LARGE_INTEGER ), 01068 sizeof( ULONG ) ); 01069 fileOffset = *ByteOffset; 01070 } 01071 01072 // 01073 // Check to see whether the caller has opened the file without 01074 // intermediate buffering. If so, perform the following ByteOffset 01075 // parameter check differently. 01076 // 01077 01078 if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) { 01079 01080 // 01081 // The file was opened without intermediate buffering enabled. 01082 // Check that the Buffer is properly aligned, and that the 01083 // length is an integral number of 512-byte blocks. 01084 // 01085 01086 if ((deviceObject->SectorSize && 01087 (Length & (deviceObject->SectorSize - 1)))) { 01088 01089 // 01090 // Check for sector sizes that are not a power of two. 01091 // 01092 01093 if ((deviceObject->SectorSize && 01094 Length % deviceObject->SectorSize) ) { 01095 01096 ExRaiseStatus(STATUS_INVALID_PARAMETER); 01097 } 01098 } 01099 01100 // 01101 // If a ByteOffset parameter was specified, ensure that it is 01102 // is of the proper type. 01103 // 01104 01105 if (ARGUMENT_PRESENT( ByteOffset )) { 01106 if (fileOffset.LowPart == FILE_WRITE_TO_END_OF_FILE && 01107 fileOffset.HighPart == -1) { 01108 NOTHING; 01109 } else if (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && 01110 fileOffset.HighPart == -1 && 01111 (fileObject->Flags & FO_SYNCHRONOUS_IO)) { 01112 NOTHING; 01113 } else if (deviceObject->SectorSize && 01114 (fileOffset.LowPart & (deviceObject->SectorSize - 1))) { 01115 01116 ExRaiseStatus(STATUS_INVALID_PARAMETER); 01117 } 01118 } 01119 } 01120 01121 // 01122 // Finally, ensure that if there is a key parameter specified it 01123 // is readable by the caller. 01124 // 01125 01126 if (ARGUMENT_PRESENT( Key )) { 01127 keyValue = ProbeAndReadUlong( Key ); 01128 } 01129 01130 } except(IopExceptionFilter( GetExceptionInformation(), &exceptionCode )) { 01131 01132 // 01133 // An exception was incurred while attempting to probe the 01134 // caller's parameters. Simply cleanup, dereference the file 01135 // object, and return with the appropriate status code. 01136 // 01137 01138 ObDereferenceObject( fileObject ); 01139 01140 if (capturedArray != NULL) { 01141 ExFreePool( capturedArray ); 01142 } 01143 01144 return exceptionCode; 01145 01146 } 01147 01148 } else { 01149 01150 // 01151 // The caller's mode is kernel. Get the appropriate parameters to 01152 // their expected locations without making all of the checks. 01153 // 01154 01155 if (ARGUMENT_PRESENT( ByteOffset )) { 01156 fileOffset = *ByteOffset; 01157 } 01158 01159 if (ARGUMENT_PRESENT( Key )) { 01160 keyValue = *Key; 01161 } 01162 #if DBG 01163 if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) { 01164 01165 // 01166 // The file was opened without intermediate buffering enabled. 01167 // Check that the the length is an integral number of the block 01168 // size. 01169 // 01170 01171 if ((deviceObject->SectorSize && 01172 (Length & (deviceObject->SectorSize - 1)))) { 01173 01174 // 01175 // Check for sector sizes that are not a power of two. 01176 // 01177 01178 if ((deviceObject->SectorSize && 01179 Length % deviceObject->SectorSize)) { 01180 ObDereferenceObject( fileObject ); 01181 ASSERT( FALSE ); 01182 return STATUS_INVALID_PARAMETER; 01183 } 01184 } 01185 01186 // 01187 // If a ByteOffset parameter was specified, ensure that it is 01188 // is of the proper type. 01189 // 01190 01191 if (ARGUMENT_PRESENT( ByteOffset )) { 01192 if (fileOffset.LowPart == FILE_WRITE_TO_END_OF_FILE && 01193 fileOffset.HighPart == -1) { 01194 NOTHING; 01195 } else if (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && 01196 fileOffset.HighPart == -1 && 01197 (fileObject->Flags & FO_SYNCHRONOUS_IO)) { 01198 NOTHING; 01199 } else if (deviceObject->SectorSize && 01200 (fileOffset.LowPart & (deviceObject->SectorSize - 1))) { 01201 ObDereferenceObject( fileObject ); 01202 ASSERT( FALSE ); 01203 return STATUS_INVALID_PARAMETER; 01204 } 01205 } 01206 } 01207 01208 if (Length != 0) { 01209 01210 // 01211 // Verify that all the addresses are page aligned. 01212 // 01213 01214 for (i = 0; i < elementCount; i++) { 01215 01216 if ( SegmentArray[i].Alignment & (PAGE_SIZE - 1)) { 01217 01218 ObDereferenceObject( fileObject ); 01219 ASSERT(FALSE); 01220 return STATUS_INVALID_PARAMETER; 01221 } 01222 } 01223 } 01224 #endif // DBG 01225 01226 } 01227 01228 // 01229 // If the caller has only append access to the file, ignore the input 01230 // parameters and set the ByteOffset to indicate that this write is 01231 // to the end of the file. Otherwise, ensure that the parameters are 01232 // valid. 01233 // 01234 01235 if (SeComputeGrantedAccesses( grantedAccess, FILE_APPEND_DATA | FILE_WRITE_DATA ) == FILE_APPEND_DATA) { 01236 01237 // 01238 // This is an append operation to the end of a file. Set the 01239 // ByteOffset parameter to give drivers a consistent view of 01240 // this type of call. 01241 // 01242 01243 fileOffset.LowPart = FILE_WRITE_TO_END_OF_FILE; 01244 fileOffset.HighPart = -1; 01245 } 01246 01247 // 01248 // Get the address of the event object and set the event to the Not- 01249 // Signaled state, if an event was specified. Note here too, that if 01250 // the handle does not refer to an event, then the reference will fail. 01251 // 01252 01253 if (ARGUMENT_PRESENT( Event )) { 01254 status = ObReferenceObjectByHandle( Event, 01255 EVENT_MODIFY_STATE, 01256 ExEventObjectType, 01257 requestorMode, 01258 (PVOID *) &eventObject, 01259 NULL ); 01260 if (!NT_SUCCESS( status )) { 01261 ObDereferenceObject( fileObject ); 01262 if (capturedArray != NULL) { 01263 ExFreePool( capturedArray ); 01264 } 01265 return status; 01266 } else { 01267 KeClearEvent( eventObject ); 01268 } 01269 } 01270 01271 // 01272 // Get the address of the fast io dispatch structure. 01273 // 01274 01275 fastIoDispatch = deviceObject->DriverObject->FastIoDispatch; 01276 01277 // 01278 // Make a special check here to determine whether this is a synchronous 01279 // I/O operation. If it is, then wait here until the file is owned by 01280 // the current thread. If the wait terminates with an alerted status, 01281 // then cleanup and return the alerted status. This allows the caller 01282 // specify FILE_SYNCHRONOUS_IO_ALERT as a synchronous I/O option. 01283 // 01284 // If everything works, then check to see whether a ByteOffset parameter 01285 // was supplied. If not, or if it was and it is set to the "use file 01286 // pointer position", then initialize the file offset to be whatever 01287 // the current byte offset into the file is according to the file pointer 01288 // context information in the file object. 01289 // 01290 01291 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 01292 01293 BOOLEAN interrupted; 01294 01295 if (!IopAcquireFastLock( fileObject )) { 01296 status = IopAcquireFileObjectLock( fileObject, 01297 requestorMode, 01298 (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), 01299 &interrupted ); 01300 if (interrupted) { 01301 if (eventObject) { 01302 ObDereferenceObject( eventObject ); 01303 } 01304 ObDereferenceObject( fileObject ); 01305 if (capturedArray != NULL) { 01306 ExFreePool( capturedArray ); 01307 } 01308 return status; 01309 } 01310 } 01311 01312 synchronousIo = TRUE; 01313 01314 if ((!ARGUMENT_PRESENT( ByteOffset ) && !fileOffset.LowPart ) || 01315 (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && 01316 fileOffset.HighPart == -1 )) { 01317 fileOffset = fileObject->CurrentByteOffset; 01318 } 01319 01320 } else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) { 01321 01322 // 01323 // The file is not open for synchronous I/O operations, but the 01324 // caller did not specify a ByteOffset parameter. This is an error 01325 // situation, so cleanup and return with the appropriate status. 01326 // 01327 01328 if (eventObject) { 01329 ObDereferenceObject( eventObject ); 01330 } 01331 ObDereferenceObject( fileObject ); 01332 if (capturedArray != NULL) { 01333 ExFreePool( capturedArray ); 01334 } 01335 return STATUS_INVALID_PARAMETER; 01336 01337 } else { 01338 01339 // 01340 // This is not a synchronous I/O operation. 01341 // 01342 01343 synchronousIo = FALSE; 01344 } 01345 01346 // 01347 // Negative file offsets are illegal. 01348 // 01349 01350 if (fileOffset.HighPart < 0 && 01351 (fileOffset.HighPart != -1 || 01352 fileOffset.LowPart != FILE_WRITE_TO_END_OF_FILE)) { 01353 01354 if (eventObject) { 01355 ObDereferenceObject( eventObject ); 01356 } 01357 if (synchronousIo) { 01358 IopReleaseFileObjectLock( fileObject ); 01359 } 01360 ObDereferenceObject( fileObject ); 01361 if (capturedArray != NULL) { 01362 ExFreePool( capturedArray ); 01363 } 01364 return STATUS_INVALID_PARAMETER; 01365 } 01366 01367 // 01368 // Set the file object to the Not-Signaled state. 01369 // 01370 01371 KeClearEvent( &fileObject->Event ); 01372 01373 // 01374 // Allocate and initialize the I/O Request Packet (IRP) for this operation. 01375 // The allocation is performed with an exception handler in case the 01376 // caller does not have enough quota to allocate the packet. 01377 // 01378 01379 irp = IopAllocateIrp( deviceObject->StackSize, TRUE ); 01380 if (!irp) { 01381 01382 // 01383 // An IRP could not be allocated. Cleanup and return an appropriate 01384 // error status code. 01385 // 01386 01387 IopAllocateIrpCleanup( fileObject, eventObject ); 01388 01389 if (capturedArray != NULL) { 01390 ExFreePool( capturedArray ); 01391 } 01392 return STATUS_INSUFFICIENT_RESOURCES; 01393 } 01394 irp->Tail.Overlay.OriginalFileObject = fileObject; 01395 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 01396 irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL; 01397 irp->RequestorMode = requestorMode; 01398 irp->PendingReturned = FALSE; 01399 irp->Cancel = FALSE; 01400 irp->CancelRoutine = (PDRIVER_CANCEL) NULL; 01401 01402 // 01403 // Fill in the service independent parameters in the IRP. 01404 // 01405 01406 irp->UserEvent = eventObject; 01407 irp->UserIosb = IoStatusBlock; 01408 irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 01409 irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 01410 01411 // 01412 // Get a pointer to the stack location for the first driver. This will be 01413 // used to pass the original function codes and parameters. Note that 01414 // setting the major function code here also sets: 01415 // 01416 // MinorFunction = 0; 01417 // Flags = 0; 01418 // Control = 0; 01419 // 01420 01421 irpSp = IoGetNextIrpStackLocation( irp ); 01422 majorFunction = (PULONG) irpSp; 01423 *majorFunction = IRP_MJ_WRITE; 01424 irpSp->FileObject = fileObject; 01425 if (fileObject->Flags & FO_WRITE_THROUGH) { 01426 irpSp->Flags = SL_WRITE_THROUGH; 01427 } 01428 01429 // 01430 // Now determine whether this device expects to have data buffered to it 01431 // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO 01432 // flag in the device object. If the flag is set, then a system buffer is 01433 // allocated and the caller's data is copied into it. Otherwise, a Memory 01434 // Descriptor List (MDL) is allocated and the caller's buffer is locked 01435 // down using it. 01436 // 01437 01438 irp->AssociatedIrp.SystemBuffer = (PVOID) NULL; 01439 irp->MdlAddress = (PMDL) NULL; 01440 01441 // 01442 // This is a direct I/O operation. Allocate an MDL and invoke the 01443 // memory management routine to lock the buffer into memory. This 01444 // is done using an exception handler that will perform cleanup if 01445 // the operation fails. Note that no MDL is allocated, nor is any 01446 // memory probed or locked if the length of the request was zero. 01447 // 01448 01449 mdl = (PMDL) NULL; 01450 irp->Flags = 0; 01451 01452 if (Length) { 01453 01454 try { 01455 01456 // 01457 // Allocate an MDL, charging quota for it, and hang it off of 01458 // the IRP. Probe and lock the pages associated with the 01459 // caller's buffer for write access and fill in the MDL with 01460 // the PFNs of those pages. 01461 // 01462 01463 mdl = IoAllocateMdl( (PVOID)(ULONG_PTR) SegmentArray[0].Buffer, Length, FALSE, TRUE, irp ); 01464 if (mdl == NULL) { 01465 ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); 01466 } 01467 01468 // 01469 // The address of the first file segment is used as a base 01470 // address. 01471 // 01472 01473 MmProbeAndLockSelectedPages( mdl, 01474 SegmentArray, 01475 requestorMode, 01476 IoReadAccess ); 01477 01478 irp->UserBuffer = (PVOID)(ULONG_PTR) SegmentArray[0].Buffer; 01479 01480 } except(EXCEPTION_EXECUTE_HANDLER) { 01481 01482 // 01483 // An exception was incurred while either allocating the MDL 01484 // or while attempting to probe and lock the caller's buffer. 01485 // Determine what actually happened, clean everything up, and 01486 // return an appropriate error status code. 01487 // 01488 01489 IopExceptionCleanup( fileObject, 01490 irp, 01491 eventObject, 01492 (PKEVENT) NULL ); 01493 01494 if (capturedArray != NULL) { 01495 ExFreePool( capturedArray ); 01496 } 01497 return GetExceptionCode(); 01498 } 01499 01500 } 01501 01502 // 01503 // We are done with the captured buffer. 01504 // 01505 01506 if (capturedArray != NULL) { 01507 ExFreePool( capturedArray ); 01508 } 01509 01510 // 01511 // If this write operation is to be performed without any caching, set the 01512 // appropriate flag in the IRP so no caching is performed. 01513 // 01514 01515 if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) { 01516 irp->Flags |= IRP_NOCACHE | IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION; 01517 } else { 01518 irp->Flags |= IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION; 01519 } 01520 01521 // 01522 // Copy the caller's parameters to the service-specific portion of the 01523 // IRP. 01524 // 01525 01526 irpSp->Parameters.Write.Length = Length; 01527 irpSp->Parameters.Write.Key = keyValue; 01528 irpSp->Parameters.Write.ByteOffset = fileOffset; 01529 01530 // 01531 // Queue the packet, call the driver, and synchronize appopriately with 01532 // I/O completion. 01533 // 01534 01535 status = IopSynchronousServiceTail( deviceObject, 01536 irp, 01537 fileObject, 01538 TRUE, 01539 requestorMode, 01540 synchronousIo, 01541 WriteTransfer ); 01542 01543 return status; 01544 01545 }

Generated on Sat May 15 19:42:27 2004 for test by doxygen 1.3.7