test: qsinfo.c File Reference

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

# qsinfo.c File Reference

`#include "iop.h"`

Go to the source code of this file.

## Defines

#define | FSIO_A FILE_SYNCHRONOUS_IO_ALERT
#define | FSIO_NA FILE_SYNCHRONOUS_IO_NONALERT

## Functions

ULONG | IopGetModeInformation (IN PFILE_OBJECT FileObject)
NTSTATUS | NtQueryInformationFile (IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass)
NTSTATUS | NtSetInformationFile (IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass)

## Define Documentation

#define FSIO_A FILE_SYNCHRONOUS_IO_ALERT

| Definition at line 34 of file qsinfo.c. Referenced by NtSetInformationFile().

#define FSIO_NA FILE_SYNCHRONOUS_IO_NONALERT

| Definition at line 35 of file qsinfo.c. Referenced by NtSetInformationFile().

## Function Documentation

ULONG IopGetModeInformation | ( | IN PFILE_OBJECT | FileObject | ) |

Definition at line 54 of file qsinfo.c.

References FO_ALERTABLE_IO, FO_DELETE_ON_CLOSE, FO_NO_INTERMEDIATE_BUFFERING, FO_SEQUENTIAL_ONLY, FO_SYNCHRONOUS_IO, and FO_WRITE_THROUGH.

Referenced by NtQueryInformationFile().

    00060                    :
    00061
    00062     This encapsulates extracting and translating the mode bits from
    00063     the passed file object, to be returned from a query information call.
    00064
    00065 Arguments:
    00066
    00067     FileObject - Specifies the file object for which to return Mode info.
    00068
    00069 Return Value:
    00070
    00071     The translated mode information is returned.
    00072
    00073 --*/
    00074
    00075 {
    00076     ULONG mode = 0;
    00077
    00078     if (FileObject->Flags & FO_WRITE_THROUGH) {
    00079         mode = FILE_WRITE_THROUGH;
    00080     }
    00081     if (FileObject->Flags & FO_SEQUENTIAL_ONLY) {
    00082         mode |= FILE_SEQUENTIAL_ONLY;
    00083     }
    00084     if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
    00085         mode |= FILE_NO_INTERMEDIATE_BUFFERING;
    00086     }
    00087     if (FileObject->Flags & FO_SYNCHRONOUS_IO) {
    00088         if (FileObject->Flags & FO_ALERTABLE_IO) {
    00089             mode |= FILE_SYNCHRONOUS_IO_ALERT;
    00090         } else {
    00091             mode |= FILE_SYNCHRONOUS_IO_NONALERT;
    00092         }
    00093     }
    00094     if (FileObject->Flags & FO_DELETE_ON_CLOSE) {
    00095         mode |= FILE_DELETE_ON_CLOSE;
    00096     }
    00097     return mode;
    00098 }

NTSTATUS NtQueryInformationFile | ( | IN HANDLE | FileHandle,
|  | OUT PIO_STATUS_BLOCK | IoStatusBlock,
|  | OUT PVOID | FileInformation,
|  | IN ULONG | Length,
|  | IN FILE_INFORMATION_CLASS | FileInformationClass
| ) |

Definition at line 101 of file qsinfo.c.

References _DEVICE_OBJECT::AlignmentRequirement, APC_LEVEL, _IRP::AssociatedIrp, _DEVICE_OBJECT::DriverObject, ExAllocatePool, ExAllocatePoolWithQuota, EXCEPTION_EXECUTE_HANDLER, Executive, ExFreePool(), FALSE, _DRIVER_OBJECT::FastIoDispatch, _FAST_IO_DISPATCH::FastIoQueryBasicInfo, _FAST_IO_DISPATCH::FastIoQueryStandardInfo, _IO_STACK_LOCATION::FileObject, _IRP::Flags, FO_ALERTABLE_IO, FO_DIRECT_DEVICE_OPEN, FO_SYNCHRONOUS_IO, _OBJECT_HANDLE_INFORMATION::GrantedAccess, IoAllocateIrp(), IoCallDriver, IoFileObjectType, IoGetAttachedDevice(), IoGetNextIrpStackLocation, IoGetRelatedDeviceObject(), IopAcquireFastLock, IopAcquireFileObjectLock(), IopAllocateIrpCleanup(), IopCancelAlertedRequest(), IopCompleteRequest(), IopExceptionCleanup(), IopGetModeInformation(), IopQueryOperationAccess, IopQueryOperationLength, IopQuerySetAlignmentRequirement, IopQueueThreadIrp, IopReleaseFileObjectLock, IopUpdateOtherOperationCount(), _IRP::IoStatus, IRP_BUFFERED_IO, IRP_DEALLOCATE_BUFFER, IRP_DEFER_IO_COMPLETION, IRP_INPUT_OPERATION, IRP_MJ_QUERY_INFORMATION, IRP_SYNCHRONOUS_API, KeClearEvent, KeInitializeEvent, KeLowerIrql(), KeRaiseIrql(), KernelMode, KeWaitForSingleObject(), KPROCESSOR_MODE, _IO_STACK_LOCATION::MajorFunction, _IRP::MdlAddress, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), _IRP::Overlay, PAGED_CODE, _IO_STACK_LOCATION::Parameters, PKNORMAL_ROUTINE, ProbeForWrite(), ProbeForWriteIoStatus, PsGetCurrentProcess, PsGetCurrentThread, _IRP::RequestorMode, _DEVICE_OBJECT::StackSize, _IRP::Tail, TRUE, _IRP::UserBuffer, _IRP::UserEvent, and _IRP::UserIosb.

Referenced by CopyRestrictedFile(), LdrVerifyImageMatchesChecksum(), main(), NTFastDOSIO(), RegLoadAsciiFileAsUnicode(), and RegReadBinaryFile().

    00111                    :
    00112
    00113     This service returns the requested information about a specified file.
    00114     The information returned is determined by the FileInformationClass that
    00115     is specified, and it is placed into the caller's FileInformation buffer.
    00116
    00117 Arguments:
    00118
    00119     FileHandle - Supplies a handle to the file about which the requested
    00120         information should be returned.
    00121
    00122     IoStatusBlock - Address of the caller's I/O status block.
    00123
    00124     FileInformation - Supplies a buffer to receive the requested information
    00125         returned about the file.
    00126
    00127     Length - Supplies the length, in bytes, of the FileInformation buffer.
    00128
    00129     FileInformationClass - Specifies the type of information which should be
    00130         returned about the file.
    00131
    00132 Return Value:
    00133
    00134     The status returned is the final completion status of the operation.
    00135
    00136 --*/
    00137
    00138 {
    00139     PIRP irp;
    00140     NTSTATUS status;
    00141     PFILE_OBJECT fileObject;
    00142     PDEVICE_OBJECT deviceObject;
    00143     PFAST_IO_DISPATCH fastIoDispatch;
    00144     PKEVENT event = (PKEVENT) NULL;
    00145     KPROCESSOR_MODE requestorMode;
    00146     PIO_STACK_LOCATION irpSp;
    00147     IO_STATUS_BLOCK localIoStatus;
    00148     OBJECT_HANDLE_INFORMATION handleInformation;
    00149     BOOLEAN synchronousIo;
    00150     BOOLEAN skipDriver;
    00151
    00152     PAGED_CODE();
    00153
    00154     //
    00155     // Get the previous mode;  i.e., the mode of the caller.
    00156     //
    00157
    00158     requestorMode = KeGetPreviousMode();
    00159
    00160     if (requestorMode != KernelMode) {
    00161
    00162         //
    00163         // Ensure that the FileInformationClass parameter is legal for querying
    00164         // information about the file.
    00165         //
    00166
    00167         if ((ULONG) FileInformationClass >= FileMaximumInformation ||
    00168             !IopQueryOperationLength[FileInformationClass]) {
    00169             return STATUS_INVALID_INFO_CLASS;
    00170         }
    00171
    00172         //
    00173         // Ensure that the supplied buffer is large enough to contain the
    00174         // information associated with the specified set operation that is
    00175         // to be performed.
    00176         //
    00177
    00178         if (Length < (ULONG) IopQueryOperationLength[FileInformationClass]) {
    00179             return STATUS_INFO_LENGTH_MISMATCH;
    00180         }
    00181
    00182         //
    00183         // The caller's access mode is not kernel so probe each of the arguments
    00184         // and capture them as necessary.  If any failures occur, the condition
    00185         // handler will be invoked to handle them.  It will simply cleanup and
    00186         // return an access violation status code back to the system service
    00187         // dispatcher.
    00188         //
    00189
    00190         try {
    00191
    00192             //
    00193             // The IoStatusBlock parameter must be writeable by the caller.
    00194             //
    00195
    00196             ProbeForWriteIoStatus( IoStatusBlock );
    00197
    00198             //
    00199             // The FileInformation buffer must be writeable by the caller.
    00200             //
    00201
    00202 #if defined(_X86_)
    00203             ProbeForWrite( FileInformation, Length, sizeof( ULONG ) );
    00204 #elif defined(_WIN64)
    00205
    00206             //
    00207             // If we are a wow64 process, follow the X86 rules
    00208             //
    00209
    00210             if (PsGetCurrentProcess()->Wow64Process) {
    00211                 ProbeForWrite( FileInformation, Length, sizeof( ULONG ) );
    00212             } else {
    00213                 ProbeForWrite( FileInformation,
    00214                                Length,
    00215                                IopQuerySetAlignmentRequirement[FileInformationClass] );
    00216             }
    00217 #else
    00218             ProbeForWrite( FileInformation,
    00219                            Length,
    00220                            IopQuerySetAlignmentRequirement[FileInformationClass] );
    00221 #endif
    00222
    00223         } except(EXCEPTION_EXECUTE_HANDLER) {
    00224
    00225             //
    00226             // An exception was incurred while probing the caller's
    00227             // parameters.  Simply return an appropriate error status
    00228             // code.
    00229             //
    00230
    00231 #if DBG
    00232             if (GetExceptionCode() == STATUS_DATATYPE_MISALIGNMENT) {
    00233                 DbgBreakPoint();
    00234             }
    00235 #endif // DBG
    00236
    00237             return GetExceptionCode();
    00238         }
    00239
    00240 #if DBG
    00241
    00242     } else {
    00243
    00244         //
    00245         // The caller's mode is kernel.  Ensure that at least the information
    00246         // class and lengths are appropriate.
    00247         //
    00248
    00249         if ((ULONG) FileInformationClass >= FileMaximumInformation ||
    00250             !IopQueryOperationLength[FileInformationClass]) {
    00251             return STATUS_INVALID_INFO_CLASS;
    00252         }
    00253
    00254         if (Length < (ULONG) IopQueryOperationLength[FileInformationClass]) {
    00255             return STATUS_INFO_LENGTH_MISMATCH;
    00256         }
    00257
    00258 #endif // DBG
    00259
    00260     }
    00261
    00262     //
    00263     // There were no blatant errors so far, so reference the file object so
    00264     // the target device object can be found.  Note that if the handle does
    00265     // not refer to a file object, or if the caller does not have the required
    00266     // access to the file, then it will fail.
    00267     //
    00268
    00269     status = ObReferenceObjectByHandle( FileHandle,
    00270                                         IopQueryOperationAccess[FileInformationClass],
    00271                                         IoFileObjectType,
    00272                                         requestorMode,
    00273                                         (PVOID *) &fileObject,
    00274                                         &handleInformation);
    00275
    00276     if (!NT_SUCCESS( status )) {
    00277         return status;
    00278     }
    00279
    00280     //
    00281     // Get the address of the target device object.  If this file represents
    00282     // a device that was opened directly, then simply use the device or its
    00283     // attached device(s) directly.  Also get the address of the Fast Io
    00284     // dispatch structure.
    00285     //
    00286
    00287     if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
    00288         deviceObject = IoGetRelatedDeviceObject( fileObject );
    00289     } else {
    00290         deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
    00291     }
    00292     fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
    00293
    00294     //
    00295     // Make a special check here to determine whether this is a synchronous
    00296     // I/O operation.  If it is, then wait here until the file is owned by
    00297     // the current thread.  If this is not a (serialized) synchronous I/O
    00298     // operation, then allocate and initialize the local event.
    00299     //
    00300
    00301     if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
    00302
    00303         BOOLEAN interrupted;
    00304
    00305         if (!IopAcquireFastLock( fileObject )) {
    00306             status = IopAcquireFileObjectLock( fileObject,
    00307                                                requestorMode,
    00308                                                (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
    00309                                                &interrupted );
    00310             if (interrupted) {
    00311                 ObDereferenceObject( fileObject );
    00312                 return status;
    00313             }
    00314         }
    00315
    00316         //
    00317         // Make a special check here to determine whether or not the caller
    00318         // is attempting to query the file position pointer.  If so, then
    00319         // return it immediately and get out.
    00320         //
    00321
    00322         if (FileInformationClass == FilePositionInformation) {
    00323
    00324             //
    00325             // The caller has requested the current file position context
    00326             // information.  This is a relatively frequent call, so it is
    00327             // optimized here to cut through the normal IRP path.
    00328             //
    00329             // Begin by establishing a condition handler and attempting to
    00330             // return both the file position information as well as the I/O
    00331             // status block.  If writing the output buffer fails, then return
    00332             // an appropriate error status code.  If writing the I/O status
    00333             // block fails, then ignore the error.  This is what would
    00334             // normally happen were everything to go through normal special
    00335             // kernel APC processing.
    00336             //
    00337
    00338             BOOLEAN writingBuffer = TRUE;
    00339             PFILE_POSITION_INFORMATION fileInformation = FileInformation;
    00340
    00341             try {
    00342
    00343                 //
    00344                 // Return the current position information.
    00345                 //
    00346
    00347                 fileInformation->CurrentByteOffset = fileObject->CurrentByteOffset;
    00348                 writingBuffer = FALSE;
    00349
    00350                 //
    00351                 // Write the I/O status block.
    00352                 //
    00353
    00354                 IoStatusBlock->Status = STATUS_SUCCESS;
    00355                 IoStatusBlock->Information = sizeof( FILE_POSITION_INFORMATION );
    00356
    00357             } except( EXCEPTION_EXECUTE_HANDLER ) {
    00358
    00359                 //
    00360                 // One of writing the caller's buffer or writing the I/O
    00361                 // status block failed.  Set the final status appropriately.
    00362                 //
    00363
    00364                 if (writingBuffer) {
    00365                     status = GetExceptionCode();
    00366                 }
    00367
    00368             }
    00369
    00370             //
    00371             // Note that the state of the event in the file object has not yet
    00372             // been reset, so it need not be set either.  Therefore, simply
    00373             // cleanup and return.
    00374             //
    00375
    00376             IopReleaseFileObjectLock( fileObject );
    00377             ObDereferenceObject( fileObject );
    00378             return status;
    00379
    00380         //
    00381         // Also do a special check if the caller it doing a query for basic or
    00382         // standard information and if so then try the fast query calls if they
    00383         // exist.
    00384         //
    00385
    00386         } else if (fastIoDispatch &&
    00387                    (((FileInformationClass == FileBasicInformation) &&
    00388                      fastIoDispatch->FastIoQueryBasicInfo) ||
    00389                     ((FileInformationClass == FileStandardInformation) &&
    00390                      fastIoDispatch->FastIoQueryStandardInfo))) {
    00391
    00392             IO_STATUS_BLOCK localIoStatus;
    00393             BOOLEAN queryResult = FALSE;
    00394             BOOLEAN writingStatus = FALSE;
    00395
    00396             //
    00397             // Do the query and setting of the IoStatusBlock inside an exception
    00398             // handler.  Note that if an exception occurs, other than writing
    00399             // the status back, then the IRP route will be taken.  If an error
    00400             // occurs attempting to write the status back to the caller's buffer
    00401             // then it will be ignored, just as it would be on the long path.
    00402             //
    00403
    00404             try {
    00405
    00406                 if (FileInformationClass == FileBasicInformation) {
    00407                     queryResult = fastIoDispatch->FastIoQueryBasicInfo( fileObject,
    00408                                                                         TRUE,
    00409                                                                         FileInformation,
    00410                                                                         &localIoStatus,
    00411                                                                         deviceObject );
    00412                 } else {
    00413                     queryResult = fastIoDispatch->FastIoQueryStandardInfo( fileObject,
    00414                                                                            TRUE,
    00415                                                                            FileInformation,
    00416                                                                            &localIoStatus,
    00417                                                                            deviceObject );
    00418                 }
    00419
    00420                 if (queryResult) {
    00421                     status = localIoStatus.Status;
    00422                     writingStatus = TRUE;
    00423                     *IoStatusBlock = localIoStatus;
    00424                 }
    00425
    00426             } except( EXCEPTION_EXECUTE_HANDLER ) {
    00427
    00428                 //
    00429                 // If the result of the preceeding block is an exception that
    00430                 // occurred after the Fast I/O path itself, then the query
    00431                 // actually succeeded so everything is done already, but the
    00432                 // user's I/O status buffer is not writable.  This case is
    00433                 // ignored to be consistent w/the long path.
    00434                 //
    00435
    00436                 if (!writingStatus) {
    00437                     status = GetExceptionCode();
    00438                 }
    00439             }
    00440
    00441             //
    00442             // If the results of the preceeding statement block is true, then
    00443             // the fast query call succeeeded, so simply cleanup and return.
    00444             //
    00445
    00446             if (queryResult) {
    00447
    00448                 //
    00449                 // Note that once again, the event in the file object has not
    00450                 // yet been set reset, so it need not be set to the Signaled
    00451                 // state, so simply cleanup and return.
    00452                 //
    00453
    00454                 IopReleaseFileObjectLock( fileObject );
    00455                 ObDereferenceObject( fileObject );
    00456                 return status;
    00457             }
    00458         }
    00459         synchronousIo = TRUE;
    00460     } else {
    00461
    00462         //
    00463         // This is a synchronous API being invoked for a file that is opened
    00464         // for asynchronous I/O.  This means that this system service is
    00465         // to synchronize the completion of the operation before returning
    00466         // to the caller.  A local event is used to do this.
    00467         //
    00468
    00469         event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
    00470         if (event == NULL) {
    00471             ObDereferenceObject( fileObject );
    00472             return STATUS_INSUFFICIENT_RESOURCES;
    00473         }
    00474         KeInitializeEvent( event, SynchronizationEvent, FALSE );
    00475         synchronousIo = FALSE;
    00476     }
    00477
    00478     //
    00479     // Set the file object to the Not-Signaled state.
    00480     //
    00481
    00482     KeClearEvent( &fileObject->Event );
    00483
    00484     //
    00485     // Allocate and initialize the I/O Request Packet (IRP) for this operation.
    00486     // The allocation is performed with an exception handler in case the
    00487     // caller does not have enough quota to allocate the packet.
    00488     //
    00489
    00490     irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
    00491     if (!irp) {
    00492
    00493         //
    00494         // An IRP could not be allocated.  Cleanup and return an appropriate
    00495         // error status code.
    00496         //
    00497
    00498         if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
    00499             ExFreePool( event );
    00500         }
    00501
    00502         IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
    00503
    00504         return STATUS_INSUFFICIENT_RESOURCES;
    00505     }
    00506     irp->Tail.Overlay.OriginalFileObject = fileObject;
    00507     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    00508     irp->RequestorMode = requestorMode;
    00509
    00510     //
    00511     // Fill in the service independent parameters in the IRP.
    00512     //
    00513
    00514     if (synchronousIo) {
    00515         irp->UserEvent = (PKEVENT) NULL;
    00516         irp->UserIosb = IoStatusBlock;
    00517     } else {
    00518         irp->UserEvent = event;
    00519         irp->UserIosb = &localIoStatus;
    00520         irp->Flags = IRP_SYNCHRONOUS_API;
    00521     }
    00522     irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
    00523
    00524     //
    00525     // Get a pointer to the stack location for the first driver.  This will be
    00526     // used to pass the original function codes and parameters.
    00527     //
    00528
    00529     irpSp = IoGetNextIrpStackLocation( irp );
    00530     irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
    00531     irpSp->FileObject = fileObject;
    00532
    00533     //
    00534     // Allocate a buffer which should be used to put the information into by
    00535     // the driver.  This will be copied back to the caller's buffer when the
    00536     // service completes.  This is done by setting the flag which says that
    00537     // this is an input operation.
    00538     //
    00539
    00540     irp->UserBuffer = FileInformation;
    00541     irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
    00542     irp->MdlAddress = (PMDL) NULL;
    00543
    00544     try {
    00545
    00546         //
    00547         // Allocate the system buffer using an exception handler so that
    00548         // errors can be caught and handled.
    00549         //
    00550
    00551         irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota( NonPagedPool,
    00552                                                                    Length );
    00553     } except(EXCEPTION_EXECUTE_HANDLER) {
    00554
    00555         //
    00556         // An exception was incurred by attempting to allocate the intermediary
    00557         // system buffer.  Cleanup everything and return an appropriate error
    00558         // status code.
    00559         //
    00560
    00561         IopExceptionCleanup( fileObject,
    00562                              irp,
    00563                              (PKEVENT) NULL,
    00564                              event );
    00565
    00566         return GetExceptionCode();
    00567     }
    00568
    00569     irp->Flags |= IRP_BUFFERED_IO |
    00570                   IRP_DEALLOCATE_BUFFER |
    00571                   IRP_INPUT_OPERATION |
    00572                   IRP_DEFER_IO_COMPLETION;
    00573
    00574     //
    00575     // Copy the caller's parameters to the service-specific portion of the
    00576     // IRP.
    00577     //
    00578
    00579     irpSp->Parameters.QueryFile.Length = Length;
    00580     irpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass;
    00581
    00582     //
    00583     // Insert the packet at the head of the IRP list for the thread.
    00584     //
    00585
    00586     IopQueueThreadIrp( irp );
    00587
    00588     //
    00589     // Update the operation count statistic for the current process for
    00590     // operations other than read and write.
    00591     //
    00592
    00593     IopUpdateOtherOperationCount();
    00594
    00595     //
    00596     // Everything is now set to invoke the device driver with this request.
    00597     // However, it is possible that the information that the caller wants
    00598     // is device independent.  If this is the case, then the request can
    00599     // be satisfied here without having to have all of the drivers implement
    00600     // the same code.  Note that having the IRP is still necessary since
    00601     // the I/O completion code requires it.
    00602     //
    00603
    00604     skipDriver = FALSE;
    00605
    00606     if (FileInformationClass == FileAccessInformation) {
    00607
    00608         PFILE_ACCESS_INFORMATION accessBuffer = irp->AssociatedIrp.SystemBuffer;
    00609
    00610         //
    00611         // Return the access information for this file.
    00612         //
    00613
    00614         accessBuffer->AccessFlags = handleInformation.GrantedAccess;
    00615
    00616         //
    00617         // Complete the I/O operation.
    00618         //
    00619
    00620         irp->IoStatus.Information = sizeof( FILE_ACCESS_INFORMATION );
    00621         skipDriver = TRUE;
    00622
    00623     } else if (FileInformationClass == FileModeInformation) {
    00624
    00625         PFILE_MODE_INFORMATION modeBuffer = irp->AssociatedIrp.SystemBuffer;
    00626
    00627         //
    00628         // Return the mode information for this file.
    00629         //
    00630
    00631         modeBuffer->Mode = IopGetModeInformation( fileObject );
    00632
    00633         //
    00634         // Complete the I/O operation.
    00635         //
    00636
    00637         irp->IoStatus.Information = sizeof( FILE_MODE_INFORMATION );
    00638         skipDriver = TRUE;
    00639
    00640     } else if (FileInformationClass == FileAlignmentInformation) {
    00641
    00642         PFILE_ALIGNMENT_INFORMATION alignmentInformation = irp->AssociatedIrp.SystemBuffer;
    00643
    00644         //
    00645         // Return the alignment information for this file.
    00646         //
    00647
    00648         alignmentInformation->AlignmentRequirement = deviceObject->AlignmentRequirement;
    00649
    00650         //
    00651         // Complete the I/O operation.
    00652         //
    00653
    00654         irp->IoStatus.Information = sizeof( FILE_ALIGNMENT_INFORMATION );
    00655         skipDriver = TRUE;
    00656
    00657     } else if (FileInformationClass == FileAllInformation) {
    00658
    00659         PFILE_ALL_INFORMATION allInformation = irp->AssociatedIrp.SystemBuffer;
    00660
    00661         //
    00662         // The caller has requested all of the information about the file.
    00663         // This request is handled specially because the service will fill
    00664         // in the Access and Mode and Alignment information in the buffer
    00665         // and then pass the buffer to the driver to fill in the remainder.
    00666         //
    00667         // Begin by returning the Access information for the file.
    00668         //
    00669
    00670         allInformation->AccessInformation.AccessFlags =
    00671             handleInformation.GrantedAccess;
    00672
    00673         //
    00674         // Return the mode information for this file.
    00675         //
    00676
    00677         allInformation->ModeInformation.Mode =
    00678             IopGetModeInformation( fileObject );
    00679
    00680         //
    00681         // Return the alignment information for this file.
    00682         //
    00683
    00684         allInformation->AlignmentInformation.AlignmentRequirement =
    00685             deviceObject->AlignmentRequirement;
    00686
    00687         //
    00688         // Finally, set the information field of the IoStatus block in the IRP
    00689         // to account for the amount information already filled in and invoke
    00690         // the driver to fill in the remainder.
    00691         //
    00692
    00693         irp->IoStatus.Information = sizeof( FILE_ACCESS_INFORMATION ) +
    00694                                     sizeof( FILE_MODE_INFORMATION ) +
    00695                                     sizeof( FILE_ALIGNMENT_INFORMATION );
    00696     }
    00697
    00698     if (skipDriver) {
    00699
    00700         //
    00701         // The requested operation has already been performed.  Simply
    00702         // set the final status in the packet and the return state.
    00703         //
    00704
    00705         status = STATUS_SUCCESS;
    00706         irp->IoStatus.Status = STATUS_SUCCESS;
    00707
    00708     } else {
    00709
    00710         //
    00711         // This is not a request that can be [completely] performed here, so
    00712         // invoke the driver at its appropriate dispatch entry with the IRP.
    00713         //
    00714
    00715         status = IoCallDriver( deviceObject, irp );
    00716     }
    00717
    00718     //
    00719     // If this operation was a synchronous I/O operation, check the return
    00720     // status to determine whether or not to wait on the file object.  If
    00721     // the file object is to be waited on, wait for the operation to complete
    00722     // and obtain the final status from the file object itself.
    00723     //
    00724
    00725     if (status == STATUS_PENDING) {
    00726
    00727         if (synchronousIo) {
    00728
    00729             status = KeWaitForSingleObject( &fileObject->Event,
    00730                                             Executive,
    00731                                             requestorMode,
    00732                                             (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
    00733                                             (PLARGE_INTEGER) NULL );
    00734
    00735             if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
    00736
    00737                 //
    00738                 // The wait request has ended either because the thread was
    00739                 // alerted or an APC was queued to this thread, because of
    00740                 // thread rundown or CTRL/C processing.  In either case, try
    00741                 // to bail out of this I/O request carefully so that the IRP
    00742                 // completes before this routine exists so that synchronization
    00743                 // with the file object will remain intact.
    00744                 //
    00745
    00746                 IopCancelAlertedRequest( &fileObject->Event, irp );
    00747
    00748             }
    00749
    00750             status = fileObject->FinalStatus;
    00751
    00752             IopReleaseFileObjectLock( fileObject );
    00753
    00754         } else {
    00755
    00756             //
    00757             // This is a normal synchronous I/O operation, as opposed to a
    00758             // serialized synchronous I/O operation.  For this case, wait for
    00759             // the local event and copy the final status information back to
    00760             // the caller.
    00761             //
    00762
    00763             status = KeWaitForSingleObject( event,
    00764                                             Executive,
    00765                                             requestorMode,
    00766                                             FALSE,
    00767                                             (PLARGE_INTEGER) NULL );
    00768
    00769             if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
    00770
    00771                 //
    00772                 // The wait request has ended either because the thread was
    00773                 // alerted or an APC was queued to this thread, because of
    00774                 // thread rundown or CTRL/C processing.  In either case, try
    00775                 // to bail out of this I/O request carefully so that the IRP
    00776                 // completes before this routine exists or the event will not
    00777                 // be around to set to the Signaled state.
    00778                 //
    00779
    00780                 IopCancelAlertedRequest( event, irp );
    00781
    00782             }
    00783
    00784             status = localIoStatus.Status;
    00785
    00786             try {
    00787
    00788                 *IoStatusBlock = localIoStatus;
    00789
    00790             } except(EXCEPTION_EXECUTE_HANDLER) {
    00791
    00792                 //
    00793                 // An exception occurred attempting to write the caller's I/O
    00794                 // status block.  Simply change the final status of the operation
    00795                 // to the exception code.
    00796                 //
    00797
    00798                 status = GetExceptionCode();
    00799             }
    00800
    00801             ExFreePool( event );
    00802
    00803         }
    00804
    00805     } else {
    00806
    00807         //
    00808         // The I/O operation finished without return a status of pending.
    00809         // This means that the operation has not been through I/O completion,
    00810         // so it must be done here.
    00811         //
    00812
    00813         PKNORMAL_ROUTINE normalRoutine;
    00814         PVOID normalContext;
    00815         KIRQL irql;
    00816
    00817         if (!synchronousIo) {
    00818
    00819             //
    00820             // This is not a synchronous I/O operation, it is a synchronous
    00821             // I/O API to a file opened for asynchronous I/O.  Since this
    00822             // code path need never wait on the allocated and supplied event,
    00823             // get rid of it so that it doesn't have to be set to the
    00824             // Signaled state by the I/O completion code.
    00825             //
    00826
    00827             irp->UserEvent = (PKEVENT) NULL;
    00828             ExFreePool( event );
    00829         }
    00830
    00831         irp->UserIosb = IoStatusBlock;
    00832         KeRaiseIrql( APC_LEVEL, &irql );
    00833         IopCompleteRequest( &irp->Tail.Apc,
    00834                             &normalRoutine,
    00835                             &normalContext,
    00836                             (PVOID *) &fileObject,
    00837                             &normalContext );
    00838         KeLowerIrql( irql );
    00839
    00840         if (synchronousIo) {
    00841             IopReleaseFileObjectLock( fileObject );
    00842         }
    00843     }
    00844
    00845     return status;
    00846 }

NTSTATUS NtSetInformationFile | ( | IN HANDLE | FileHandle,
|  | OUT PIO_STATUS_BLOCK | IoStatusBlock,
|  | IN PVOID | FileInformation,
|  | IN ULONG | Length,
|  | IN FILE_INFORMATION_CLASS | FileInformationClass
| ) |

Definition at line 849 of file qsinfo.c.

References APC_LEVEL, ASSERT, _IRP::AssociatedIrp, ExAllocatePool, ExAllocatePoolWithQuota, ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, Executive, ExFreePool(), ExRaiseStatus(), FALSE, FileName, _IO_STACK_LOCATION::FileObject, _IRP::Flags, FO_ALERTABLE_IO, FO_DIRECT_DEVICE_OPEN, FO_NO_INTERMEDIATE_BUFFERING, FO_SEQUENTIAL_ONLY, FO_SYNCHRONOUS_IO, FO_WRITE_THROUGH, FSIO_A, FSIO_NA, IoAllocateIrp(), IoCallDriver, IoCompletionObjectType, IoFileObjectType, IoGetAttachedDevice(), IoGetNextIrpStackLocation, IoGetRelatedDeviceObject(), IopAcquireFastLock, IopAcquireFileObjectLock(), IopAllocateIrpCleanup(), IopCancelAlertedRequest(), IopCompleteRequest(), IopExceptionCleanup(), IopOpenLinkOrRenameTarget(), IopQuerySetAlignmentRequirement, IopQueueThreadIrp, IopReleaseFileObjectLock, IopSetOperationAccess, IopSetOperationLength, IopTrackLink(), IopUpdateOtherOperationCount(), IopUpdateOtherTransferCount(), _IRP::IoStatus, IRP_BUFFERED_IO, IRP_DEALLOCATE_BUFFER, IRP_DEFER_IO_COMPLETION, IRP_MJ_SET_INFORMATION, IRP_SYNCHRONOUS_API, KeClearEvent, KeInitializeEvent, KeLowerIrql(), KeRaiseIrql(), KernelMode, KeWaitForSingleObject(), _IO_COMPLETION_CONTEXT::Key, KPROCESSOR_MODE, L, _IO_STACK_LOCATION::MajorFunction, _IRP::MdlAddress, NonPagedPool, NT_SUCCESS, NtClose(), NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), _IRP::Overlay, PAGED_CODE, PagedPool, _IO_STACK_LOCATION::Parameters, PKNORMAL_ROUTINE, _IO_COMPLETION_CONTEXT::Port, ProbeForRead, ProbeForWriteIoStatus, PsGetCurrentProcess, PsGetCurrentThread, _IRP::RequestorMode, _DEVICE_OBJECT::SectorSize, _DEVICE_OBJECT::StackSize, _IRP::Tail, TRUE, _IRP::UserEvent, and _IRP::UserIosb.

Referenced by CopyRestrictedFile(), MemPrintWriteThread(), NTFastDOSIO(), RtlSetIoCompletionCallback(), SepClientOpenPipe(), and ZwSetInformationFile().

    00859                    :
    00860
    00861     This service changes the provided information about a specified file.  The
    00862     information that is changed is determined by the FileInformationClass that
    00863     is specified.  The new information is taken from the FileInformation buffer.
    00864
    00865 Arguments:
    00866
    00867     FileHandle - Supplies a handle to the file whose information should be
    00868         changed.
    00869
    00870     IoStatusBlock - Address of the caller's I/O status block.
    00871
    00872     FileInformation - Supplies a buffer containing the information which should
    00873         be changed on the file.
    00874
    00875     Length - Supplies the length, in bytes, of the FileInformation buffer.
    00876
    00877     FileInformationClass - Specifies the type of information which should be
    00878         changed about the file.
    00879
    00880 Return Value:
    00881
    00882     The status returned is the final completion status of the operation.
    00883
    00884 --*/
    00885
    00886 {
    00887     PIRP irp;
    00888     NTSTATUS status;
    00889     PFILE_OBJECT fileObject;
    00890     PDEVICE_OBJECT deviceObject;
    00891     PKEVENT event = (PKEVENT) NULL;
    00892     KPROCESSOR_MODE requestorMode;
    00893     PIO_STACK_LOCATION irpSp;
    00894     IO_STATUS_BLOCK localIoStatus;
    00895     HANDLE targetHandle = (HANDLE) NULL;
    00896     BOOLEAN synchronousIo;
    00897
    00898     PAGED_CODE();
    00899
    00900     //
    00901     // Get the previous mode;  i.e., the mode of the caller.
    00902     //
    00903
    00904     requestorMode = KeGetPreviousMode();
    00905
    00906     if (requestorMode != KernelMode) {
    00907
    00908         //
    00909         // Ensure that the FileInformationClass parameter is legal for setting
    00910         // information about the file.
    00911         //
    00912
    00913         if ((ULONG) FileInformationClass >= FileMaximumInformation ||
    00914             !IopSetOperationLength[FileInformationClass]) {
    00915             return STATUS_INVALID_INFO_CLASS;
    00916         }
    00917
    00918         //
    00919         // Ensure that the supplied buffer is large enough to contain the
    00920         // information associated with the specified set operation that is
    00921         // to be performed.
    00922         //
    00923
    00924         if (Length < (ULONG) IopSetOperationLength[FileInformationClass]) {
    00925             return STATUS_INFO_LENGTH_MISMATCH;
    00926         }
    00927
    00928         //
    00929         // The caller's access mode is user, so probe each of the arguments
    00930         // and capture them as necessary.  If any failures occur, the condition
    00931         // handler will be invoked to handle them.  It will simply cleanup and
    00932         // return an access violation status code back to the system service
    00933         // dispatcher.
    00934         //
    00935
    00936         try {
    00937
    00938             //
    00939             // The IoStatusBlock parameter must be writeable by the caller.
    00940             //
    00941
    00942             ProbeForWriteIoStatus( IoStatusBlock );
    00943
    00944             //
    00945             // The FileInformation buffer must be readable by the caller.
    00946             //
    00947
    00948 #if defined(_X86_)
    00949             ProbeForRead( FileInformation,
    00950                           Length,
    00951                           Length == sizeof( BOOLEAN ) ? sizeof( BOOLEAN ) : sizeof( ULONG ) );
    00952 #elif defined(_WIN64)
    00953             // If we are a wow64 process, follow the X86 rules
    00954             if (PsGetCurrentProcess()->Wow64Process) {
    00955                 ProbeForRead( FileInformation,
    00956                               Length,
    00957                               Length == sizeof( BOOLEAN ) ? sizeof( BOOLEAN ) : sizeof( ULONG ) );
    00958             }
    00959             else {
    00960                 ProbeForRead( FileInformation,
    00961                               Length,
    00962                               IopQuerySetAlignmentRequirement[FileInformationClass] );
    00963             }
    00964 #else
    00965             ProbeForRead( FileInformation,
    00966                           Length,
    00967                           IopQuerySetAlignmentRequirement[FileInformationClass] );
    00968 #endif
    00969
    00970         } except(EXCEPTION_EXECUTE_HANDLER) {
    00971
    00972             //
    00973             // An exception was incurred while probing the caller's parameters.
    00974             // Simply return an appropriate error status code.
    00975             //
    00976
    00977 #if DBG
    00978             if (GetExceptionCode() == STATUS_DATATYPE_MISALIGNMENT) {
    00979                 DbgBreakPoint();
    00980             }
    00981 #endif // DBG
    00982
    00983             return GetExceptionCode();
    00984
    00985         }
    00986
    00987 #if DBG
    00988
    00989     } else {
    00990
    00991         //
    00992         // The caller's mode is kernel.  Ensure that at least the information
    00993         // class and lengths are appropriate.
    00994         //
    00995
    00996         if ((ULONG) FileInformationClass >= FileMaximumInformation ||
    00997             !IopSetOperationLength[FileInformationClass]) {
    00998             return STATUS_INVALID_INFO_CLASS;
    00999         }
    01000
    01001         if (Length < (ULONG) IopSetOperationLength[FileInformationClass]) {
    01002             return STATUS_INFO_LENGTH_MISMATCH;
    01003         }
    01004
    01005 #endif // DBG
    01006
    01007     }
    01008
    01009     //
    01010     // There were no blatant errors so far, so reference the file object so
    01011     // the target device object can be found.  Note that if the handle does
    01012     // not refer to a file object, or if the caller does not have the required
    01013     // access to the file, then it will fail.
    01014     //
    01015
    01016     status = ObReferenceObjectByHandle( FileHandle,
    01017                                         IopSetOperationAccess[FileInformationClass],
    01018                                         IoFileObjectType,
    01019                                         requestorMode,
    01020                                         (PVOID *) &fileObject,
    01021                                         NULL );
    01022     if (!NT_SUCCESS( status )) {
    01023         return status;
    01024     }
    01025
    01026     //
    01027     // Get the address of the target device object.  If this file represents
    01028     // a device that was opened directly, then simply use the device or its
    01029     // attached device(s) directly.
    01030     //
    01031
    01032     if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
    01033         deviceObject = IoGetRelatedDeviceObject( fileObject );
    01034     } else {
    01035         deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
    01036     }
    01037
    01038     //
    01039     // Make a special check here to determine whether this is a synchronous
    01040     // I/O operation.  If it is, then wait here until the file is owned by
    01041     // the current thread.  If this is not a (serialized) synchronous I/O
    01042     // operation, then allocate and initialize the local event.
    01043     //
    01044
    01045     if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
    01046
    01047         BOOLEAN interrupted;
    01048
    01049         if (!IopAcquireFastLock( fileObject )) {
    01050             status = IopAcquireFileObjectLock( fileObject,
    01051                                                requestorMode,
    01052                                                (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
    01053                                                &interrupted );
    01054             if (interrupted) {
    01055                 ObDereferenceObject( fileObject );
    01056                 return status;
    01057             }
    01058         }
    01059
    01060         //
    01061         // Make a special check here to determine whether or not the caller
    01062         // is attempting to set the file position pointer information.  If so,
    01063         // then set it immediately and get out.
    01064         //
    01065
    01066         if (FileInformationClass == FilePositionInformation) {
    01067
    01068             //
    01069             // The caller has requested setting the current file position
    01070             // context information.  This is a relatively frequent call, so
    01071             // it is optimized here to cut through the normal IRP path.
    01072             //
    01073             // Begin by checking to see whether the file was opened with no
    01074             // intermediate buffering.  If so, then the file pointer must be
    01075             // set in a manner consistent with the alignment requirement of
    01076             // read and write operations to a non-buffered file.
    01077             //
    01078
    01079             PFILE_POSITION_INFORMATION fileInformation = FileInformation;
    01080             LARGE_INTEGER currentByteOffset;
    01081
    01082             try {
    01083
    01084                 //
    01085                 // Attempt to read the position information from the buffer.
    01086                 //
    01087
    01088                 currentByteOffset.QuadPart = fileInformation->CurrentByteOffset.QuadPart;
    01089
    01090             } except( EXCEPTION_EXECUTE_HANDLER ) {
    01091
    01092                 IopReleaseFileObjectLock( fileObject );
    01093                 ObDereferenceObject( fileObject );
    01094                 return GetExceptionCode();
    01095             }
    01096
    01097             if ((fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING &&
    01098                  (deviceObject->SectorSize &&
    01099                  (currentByteOffset.LowPart &
    01100                  (deviceObject->SectorSize - 1)))) ||
    01101                  currentByteOffset.HighPart < 0) {
    01102
    01103                     status = STATUS_INVALID_PARAMETER;
    01104
    01105             } else {
    01106
    01107                 //
    01108                 // Set the current file position information.
    01109                 //
    01110
    01111                 fileObject->CurrentByteOffset.QuadPart = currentByteOffset.QuadPart;
    01112
    01113                 try {
    01114
    01115                     //
    01116                     // Write the I/O status block.
    01117                     //
    01118
    01119                     IoStatusBlock->Status = STATUS_SUCCESS;
    01120                     IoStatusBlock->Information = 0;
    01121
    01122                 } except( EXCEPTION_EXECUTE_HANDLER ) {
    01123
    01124                     //
    01125                     // Writes to I/O status blocks are ignored since the
    01126                     // operation succeeded.
    01127                     //
    01128
    01129                     NOTHING;
    01130
    01131                 }
    01132
    01133             }
    01134
    01135             //
    01136             // Update the transfer count statistic for the current process for
    01137             // operations other than read and write.
    01138             //
    01139
    01140             IopUpdateOtherTransferCount( Length );
    01141
    01142             //
    01143             // Note that the file object's event has not yet been reset,
    01144             // so it is not necessary to set it to the Signaled state, since
    01145             // that is it's state at this point by definition.  Therefore,
    01146             // simply cleanup and return.
    01147             //
    01148
    01149             IopReleaseFileObjectLock( fileObject );
    01150             ObDereferenceObject( fileObject );
    01151             return status;
    01152         }
    01153         synchronousIo = TRUE;
    01154     } else {
    01155
    01156         //
    01157         // This is a synchronous API being invoked for a file that is opened
    01158         // for asynchronous I/O.  This means that this system service is
    01159         // to synchronize the completion of the operation before returning
    01160         // to the caller.  A local event is used to do this.
    01161         //
    01162
    01163         event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
    01164         if (event == NULL) {
    01165             ObDereferenceObject( fileObject );
    01166             return STATUS_INSUFFICIENT_RESOURCES;
    01167         }
    01168         KeInitializeEvent( event, SynchronizationEvent, FALSE );
    01169         synchronousIo = FALSE;
    01170     }
    01171
    01172     //
    01173     // Set the file object to the Not-Signaled state.
    01174     //
    01175
    01176     KeClearEvent( &fileObject->Event );
    01177
    01178     //
    01179     // If a link is being tracked, handle this out-of-line.
    01180     //
    01181
    01182     if (FileInformationClass == FileTrackingInformation) {
    01183         status = IopTrackLink( fileObject,
    01184                                &localIoStatus,
    01185                                FileInformation,
    01186                                Length,
    01187                                synchronousIo ? &fileObject->Event : event,
    01188                                requestorMode );
    01189         if (NT_SUCCESS( status )) {
    01190             try {
    01191                 IoStatusBlock->Information = 0;
    01192                 IoStatusBlock->Status = status;
    01193             } except(EXCEPTION_EXECUTE_HANDLER) {
    01194                 NOTHING;
    01195             }
    01196         }
    01197
    01198         if (synchronousIo) {
    01199             IopReleaseFileObjectLock( fileObject );
    01200         } else {
    01201             ExFreePool( event );
    01202         }
    01203         ObDereferenceObject( fileObject );
    01204         return status;
    01205     }
    01206
    01207     //
    01208     // Allocate and initialize the I/O Request Packet (IRP) for this operation.
    01209     // The allocation is performed with an exception handler in case the
    01210     // caller does not have enough quota to allocate the packet.
    01211
    01212     irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
    01213     if (!irp) {
    01214
    01215         //
    01216         // An IRP could not be allocated.  Cleanup and return an appropriate
    01217         // error status code.
    01218         //
    01219
    01220         if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
    01221             ExFreePool( event );
    01222         }
    01223
    01224         IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
    01225
    01226         return STATUS_INSUFFICIENT_RESOURCES;
    01227     }
    01228     irp->Tail.Overlay.OriginalFileObject = fileObject;
    01229     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    01230     irp->RequestorMode = requestorMode;
    01231
    01232     //
    01233     // Fill in the service independent parameters in the IRP.
    01234     //
    01235
    01236     if (synchronousIo) {
    01237         irp->UserEvent = (PKEVENT) NULL;
    01238         irp->UserIosb = IoStatusBlock;
    01239     } else {
    01240         irp->UserEvent = event;
    01241         irp->UserIosb = &localIoStatus;
    01242         irp->Flags = IRP_SYNCHRONOUS_API;
    01243     }
    01244     irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
    01245
    01246     //
    01247     // Get a pointer to the stack location for the first driver.  This will
    01248     // be used to pass the original function codes and parameters.
    01249     //
    01250
    01251     irpSp = IoGetNextIrpStackLocation( irp );
    01252     irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
    01253     irpSp->FileObject = fileObject;
    01254
    01255     //
    01256     // Allocate a buffer and copy the information that is to be set on the
    01257     // file into it.  Also, set the flags so that the completion code will
    01258     // properly handle getting rid of the buffer and will not attempt to
    01259     // copy data.
    01260     //
    01261
    01262     irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
    01263     irp->MdlAddress = (PMDL) NULL;
    01264
    01265     try {
    01266
    01267         PVOID systemBuffer;
    01268
    01269         systemBuffer =
    01270         irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota( NonPagedPool,
    01271                                                                    Length );
    01272         RtlCopyMemory( irp->AssociatedIrp.SystemBuffer,
    01273                        FileInformation,
    01274                        Length );
    01275
    01276         //
    01277         //  Negative file offsets are illegal.
    01278         //
    01279
    01280         ASSERT((FIELD_OFFSET(FILE_END_OF_FILE_INFORMATION, EndOfFile) |
    01281                 FIELD_OFFSET(FILE_ALLOCATION_INFORMATION, AllocationSize) |
    01282                 FIELD_OFFSET(FILE_POSITION_INFORMATION, CurrentByteOffset)) == 0);
    01283
    01284         if (((FileInformationClass == FileEndOfFileInformation) ||
    01285              (FileInformationClass == FileAllocationInformation) ||
    01286              (FileInformationClass == FilePositionInformation)) &&
    01287             (((PFILE_POSITION_INFORMATION)systemBuffer)->CurrentByteOffset.HighPart < 0)) {
    01288
    01289             ExRaiseStatus(STATUS_INVALID_PARAMETER);
    01290         }
    01291
    01292
    01293
    01294     } except(EXCEPTION_EXECUTE_HANDLER) {
    01295
    01296         //
    01297         // An exception was incurred while allocating the intermediary
    01298         // system buffer or while copying the caller's data into the
    01299         // buffer. Cleanup and return an appropriate error status code.
    01300         //
    01301
    01302         IopExceptionCleanup( fileObject,
    01303                              irp,
    01304                              (PKEVENT) NULL,
    01305                              event );
    01306
    01307         return GetExceptionCode();
    01308
    01309     }
    01310
    01311     irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_DEFER_IO_COMPLETION;
    01312
    01313     //
    01314     // Copy the caller's parameters to the service-specific portion of the
    01315     // IRP.
    01316     //
    01317
    01318     irpSp->Parameters.SetFile.Length = Length;
    01319     irpSp->Parameters.SetFile.FileInformationClass = FileInformationClass;
    01320
    01321     //
    01322     // Insert the packet at the head of the IRP list for the thread.
    01323     //
    01324
    01325     IopQueueThreadIrp( irp );
    01326
    01327     //
    01328     // Update the operation count statistic for the current process for
    01329     // operations other than read and write.
    01330     //
    01331
    01332     IopUpdateOtherOperationCount();
    01333
    01334
    01335     //
    01336     // Everything is now set to invoke the device driver with this request.
    01337     // However, it is possible that the information that the caller wants
    01338     // to set is device independent.  If this is the case, then the request
    01339     // can be satisfied here without having to have all of the drivers
    01340     // implement the same code.  Note that having the IRP is still necessary
    01341     // since the I/O completion code requires it.
    01342     //
    01343
    01344     if (FileInformationClass == FileModeInformation) {
    01345
    01346         PFILE_MODE_INFORMATION modeBuffer = irp->AssociatedIrp.SystemBuffer;
    01347
    01348         //
    01349         // Set the various flags in the mode field for the file object, if
    01350         // they are reasonable.  There are 4 different invalid combinations
    01351         // that the caller may not specify:
    01352         //
    01353         //     1)  An invalid flag was set in the mode field.  Not all Create/
    01354         //         Open options may be changed.
    01355         //
    01356         //     2)  The caller set one of the synchronous I/O flags (alert or
    01357         //         nonalert), but the file is not opened for synchronous I/O.
    01358         //
    01359         //     3)  The file is opened for synchronous I/O but the caller did
    01360         //         not set either of the synchronous I/O flags (alert or non-
    01361         //         alert).
    01362         //
    01363         //     4)  The caller set both of the synchronous I/O flags (alert and
    01364         //         nonalert).
    01365         //
    01366
    01367         if ((modeBuffer->Mode & ~FILE_VALID_SET_FLAGS) ||
    01368             ((modeBuffer->Mode & (FSIO_A | FSIO_NA)) && (!(fileObject->Flags & FO_SYNCHRONOUS_IO))) ||
    01369             ((!(modeBuffer->Mode & (FSIO_A | FSIO_NA))) && (fileObject->Flags & FO_SYNCHRONOUS_IO)) ||
    01370             (((modeBuffer->Mode & FSIO_A) && (modeBuffer->Mode & FSIO_NA) ))) {
    01371             status = STATUS_INVALID_PARAMETER;
    01372
    01373         } else {
    01374
    01375             //
    01376             // Set or clear the appropriate flags in the file object.
    01377             //
    01378
    01379             if (!(fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)) {
    01380                 if (modeBuffer->Mode & FILE_WRITE_THROUGH) {
    01381                     fileObject->Flags |= FO_WRITE_THROUGH;
    01382                 } else {
    01383                     fileObject->Flags &= ~FO_WRITE_THROUGH;
    01384                 }
    01385             }
    01386
    01387             if (modeBuffer->Mode & FILE_SEQUENTIAL_ONLY) {
    01388                 fileObject->Flags |= FO_SEQUENTIAL_ONLY;
    01389             } else {
    01390                 fileObject->Flags &= ~FO_SEQUENTIAL_ONLY;
    01391             }
    01392
    01393             if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
    01394                 if (modeBuffer->Mode & FSIO_A) {
    01395                     fileObject->Flags |= FO_ALERTABLE_IO;
    01396                 } else {
    01397                     fileObject->Flags &= ~FO_ALERTABLE_IO;
    01398                 }
    01399             }
    01400
    01401             status = STATUS_SUCCESS;
    01402         }
    01403
    01404         //
    01405         // Complete the I/O operation.
    01406         //
    01407
    01408         irp->IoStatus.Status = status;
    01409         irp->IoStatus.Information = 0L;
    01410
    01411     } else if (FileInformationClass == FileRenameInformation ||
    01412                FileInformationClass == FileLinkInformation ||
    01413                FileInformationClass == FileMoveClusterInformation) {
    01414
    01415         //
    01416         // Note that following code depends on the fact that the rename
    01417         // information, link information and copy-on-write information
    01418         // structures look exactly the same.
    01419         //
    01420
    01421         PFILE_RENAME_INFORMATION renameBuffer = irp->AssociatedIrp.SystemBuffer;
    01422
    01423         //
    01424         // The information being set is a variable-length structure with
    01425         // embedded size information.  Walk the structure to ensure that
    01426         // it is valid so the driver does not walk off the end and incur
    01427         // an access violation in kernel mode.
    01428         //
    01429
    01430         if ((ULONG) (Length - FIELD_OFFSET( FILE_RENAME_INFORMATION, FileName[0] )) < renameBuffer->FileNameLength) {
    01431             status = STATUS_INVALID_PARAMETER;
    01432             irp->IoStatus.Status = status;
    01433
    01434         } else {
    01435
    01436             //
    01437             // Copy the value of the replace BOOLEAN (or the ClusterCount field)
    01438             // from the caller's buffer to the I/O stack location parameter
    01439             // field where it is expected by file systems.
    01440             //
    01441
    01442             if (FileInformationClass == FileMoveClusterInformation) {
    01443                 irpSp->Parameters.SetFile.ClusterCount =
    01444                     ((FILE_MOVE_CLUSTER_INFORMATION *) renameBuffer)->ClusterCount;
    01445             } else {
    01446                 irpSp->Parameters.SetFile.ReplaceIfExists = renameBuffer->ReplaceIfExists;
    01447             }
    01448
    01449             //
    01450             // Check to see whether or not a fully qualified pathname was
    01451             // supplied.  If so, then more processing is required.
    01452             //
    01453
    01454             if (renameBuffer->FileName[0] == (WCHAR) OBJ_NAME_PATH_SEPARATOR ||
    01455                 renameBuffer->RootDirectory) {
    01456
    01457                 //
    01458                 // A fully qualified file name was specified as the target of
    01459                 // the rename operation.  Attempt to open the target file and
    01460                 // ensure that the replacement policy for the file is consistent
    01461                 // with the caller's request, and ensure that the file is on the
    01462                 // same volume.
    01463                 //
    01464
    01465                 status = IopOpenLinkOrRenameTarget( &targetHandle,
    01466                                                     irp,
    01467                                                     renameBuffer,
    01468                                                     fileObject );
    01469                 if (!NT_SUCCESS( status )) {
    01470                     irp->IoStatus.Status = status;
    01471
    01472                 } else {
    01473
    01474                     //
    01475                     // The fully qualified file name specifies a file on the
    01476                     // same volume and if it exists, then the caller specified
    01477                     // that it should be replaced.
    01478                     //
    01479
    01480                     status = IoCallDriver( deviceObject, irp );
    01481
    01482                 }
    01483
    01484             } else {
    01485
    01486                 //
    01487                 // This is a simple rename operation, so call the driver and
    01488                 // let it perform the rename operation within the same directory
    01489                 // as the source file.
    01490                 //
    01491
    01492                 status = IoCallDriver( deviceObject, irp );
    01493
    01494             }
    01495         }
    01496
    01497     } else if (FileInformationClass == FileDispositionInformation) {
    01498
    01499         PFILE_DISPOSITION_INFORMATION disposition = irp->AssociatedIrp.SystemBuffer;
    01500
    01501         //
    01502         // Check to see whether the disposition delete field has been set to
    01503         // TRUE and, if so, copy the handle being used to do this to the IRP
    01504         // stack location parameter.
    01505         //
    01506
    01507         if (disposition->DeleteFile) {
    01508             irpSp->Parameters.SetFile.DeleteHandle = FileHandle;
    01509         }
    01510
    01511         //
    01512         // Simply invoke the driver to perform the (un)delete operation.
    01513         //
    01514
    01515         status = IoCallDriver( deviceObject, irp );
    01516
    01517     } else if (FileInformationClass == FileCompletionInformation) {
    01518
    01519         PFILE_COMPLETION_INFORMATION completion = irp->AssociatedIrp.SystemBuffer;
    01520         PIO_COMPLETION_CONTEXT context;
    01521         PVOID portObject;
    01522
    01523         //
    01524         // It is an error if this file object already has an LPC port associated
    01525         // with it.
    01526         //
    01527
    01528         if (fileObject->CompletionContext || fileObject->Flags & FO_SYNCHRONOUS_IO) {
    01529
    01530             status = STATUS_INVALID_PARAMETER;
    01531
    01532         } else {
    01533
    01534             //
    01535             // Attempt to reference the port object by its handle and convert it
    01536             // into a pointer to the port object itself.
    01537             //
    01538
    01539             status = ObReferenceObjectByHandle( completion->Port,
    01540                                                 IO_COMPLETION_MODIFY_STATE,
    01541                                                 IoCompletionObjectType,
    01542                                                 requestorMode,
    01543                                                 (PVOID *) &portObject,
    01544                                                 NULL );
    01545             if (NT_SUCCESS( status )) {
    01546
    01547                 //
    01548                 // Allocate the memory to be associated w/this file object
    01549                 //
    01550
    01551                 context = ExAllocatePoolWithTag( PagedPool,
    01552                                                  sizeof( IO_COMPLETION_CONTEXT ),
    01553                                                  'cCoI' );
    01554                 if (!context) {
    01555
    01556                     ObDereferenceObject( portObject );
    01557                     status = STATUS_INSUFFICIENT_RESOURCES;
    01558
    01559                 } else {
    01560
    01561                     //
    01562                     // Everything was successful.  Capture the completion port
    01563                     // and the key.
    01564                     //
    01565
    01566                     context->Port = portObject;
    01567                     context->Key = completion->Key;
    01568
    01569                     if (!InterlockedCompareExchangePointer( &fileObject->CompletionContext, context, NULL )) {
    01570
    01571                         status = STATUS_SUCCESS;
    01572
    01573                     } else {
    01574
    01575                         //
    01576                         // Someone set the completion context after the check.
    01577                         // Simply drop everything on the floor and return an
    01578                         // error.
    01579                         //
    01580
    01581                         ExFreePool( context );
    01582                         ObDereferenceObject( portObject );
    01583                         status = STATUS_INVALID_PARAMETER;
    01584                     }
    01585                 }
    01586             }
    01587         }
    01588
    01589         //
    01590         // Complete the I/O operation.
    01591         //
    01592
    01593         irp->IoStatus.Status = status;
    01594         irp->IoStatus.Information = 0;
    01595
    01596     } else {
    01597
    01598         //
    01599         // This is not a request that can be performed here, so invoke the
    01600         // driver at its appropriate dispatch entry with the IRP.
    01601         //
    01602
    01603         status = IoCallDriver( deviceObject, irp );
    01604     }
    01605
    01606     //
    01607     // If this operation was a synchronous I/O operation, check the return
    01608     // status to determine whether or not to wait on the file object.  If
    01609     // the file object is to be waited on, wait for the operation to complete
    01610     // and obtain the final status from the file object itself.
    01611     //
    01612
    01613     if (status == STATUS_PENDING) {
    01614
    01615         if (synchronousIo) {
    01616
    01617             status = KeWaitForSingleObject( &fileObject->Event,
    01618                                             Executive,
    01619                                             requestorMode,
    01620                                             (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
    01621                                             (PLARGE_INTEGER) NULL );
    01622
    01623             if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
    01624
    01625                 //
    01626                 // The wait request has ended either because the thread was
    01627                 // alerted or an APC was queued to this thread, because of
    01628                 // thread rundown or CTRL/C processing.  In either case, try
    01629                 // to bail out of this I/O request carefully so that the IRP
    01630                 // completes before this routine exists so that synchronization
    01631                 // with the file object will remain intact.
    01632                 //
    01633
    01634                 IopCancelAlertedRequest( &fileObject->Event, irp );
    01635
    01636             }
    01637
    01638             status = fileObject->FinalStatus;
    01639
    01640             IopReleaseFileObjectLock( fileObject );
    01641
    01642         } else {
    01643
    01644             //
    01645             // This is a normal synchronous I/O operation, as opposed to a
    01646             // serialized synchronous I/O operation.  For this case, wait for
    01647             // the local event and copy the final status information back to
    01648             // the caller.
    01649             //
    01650
    01651             status = KeWaitForSingleObject( event,
    01652                                             Executive,
    01653                                             requestorMode,
    01654                                             FALSE,
    01655                                             (PLARGE_INTEGER) NULL );
    01656
    01657             if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
    01658
    01659                 //
    01660                 // The wait request has ended either because the thread was
    01661                 // alerted or an APC was queued to this thread, because of
    01662                 // thread rundown or CTRL/C processing.  In either case, try
    01663                 // to bail out of this I/O request carefully so that the IRP
    01664                 // completes before this routine exists or the event will not
    01665                 // be around to set to the Signaled state.
    01666                 //
    01667
    01668                 IopCancelAlertedRequest( event, irp );
    01669
    01670             }
    01671
    01672             status = localIoStatus.Status;
    01673
    01674             try {
    01675
    01676                 *IoStatusBlock = localIoStatus;
    01677
    01678             } except(EXCEPTION_EXECUTE_HANDLER) {
    01679
    01680                 //
    01681                 // An exception occurred attempting to write the caller's I/O
    01682                 // status block.  Simply change the final status of the
    01683                 // operation to the exception code.
    01684                 //
    01685
    01686                 status = GetExceptionCode();
    01687             }
    01688
    01689             ExFreePool( event );
    01690
    01691         }
    01692
    01693     } else {
    01694
    01695         //
    01696         // The I/O operation finished without return a status of pending.
    01697         // This means that the operation has not been through I/O completion,
    01698         // so it must be done here.
    01699         //
    01700
    01701         PKNORMAL_ROUTINE normalRoutine;
    01702         PVOID normalContext;
    01703         KIRQL irql;
    01704
    01705         if (!synchronousIo) {
    01706
    01707             //
    01708             // This is not a synchronous I/O operation, it is a synchronous
    01709             // I/O API to a file opened for asynchronous I/O.  Since this
    01710             // code path need never wait on the allocated and supplied event,
    01711             // get rid of it so that it doesn't have to be set to the
    01712             // Signaled state by the I/O completion code.
    01713             //
    01714
    01715             irp->UserEvent = (PKEVENT) NULL;
    01716             ExFreePool( event );
    01717         }
    01718
    01719         irp->UserIosb = IoStatusBlock;
    01720         KeRaiseIrql( APC_LEVEL, &irql );
    01721         IopCompleteRequest( &irp->Tail.Apc,
    01722                             &normalRoutine,
    01723                             &normalContext,
    01724                             (PVOID *) &fileObject,
    01725                             &normalContext );
    01726         KeLowerIrql( irql );
    01727
    01728         if (synchronousIo) {
    01729             IopReleaseFileObjectLock( fileObject );
    01730         }
    01731
    01732     }
    01733
    01734     //
    01735     // If there was a target handle generated because of a rename operation,
    01736     // close it now.
    01737     //
    01738
    01739     if (targetHandle) {
    01740         NtClose( targetHandle );
    01741     }
    01742
    01743     return status;
    01744 }
    }