test: write.c Source File

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 }