Exemplo n.º 1
0
NTSTATUS
BuildQueryDirectoryIrp(
    IN HANDLE FileHandle,
    IN HANDLE Event OPTIONAL,
    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
    IN PVOID ApcContext OPTIONAL,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    OUT PVOID FileInformation,
    IN ULONG Length,
    IN FILE_INFORMATION_CLASS FileInformationClass,
    IN BOOLEAN ReturnSingleEntry,
    IN PUNICODE_STRING FileName OPTIONAL,
    IN BOOLEAN RestartScan,
    IN UCHAR MinorFunction,
    OUT BOOLEAN *SynchronousIo,
    OUT PDEVICE_OBJECT *DeviceObject,
    OUT PIRP *Irp,
    OUT PFILE_OBJECT *FileObject,
    OUT KPROCESSOR_MODE *RequestorMode
    )

/*++

Routine Description:

    This service operates on a directory file or OLE container specified by the
    FileHandle parameter.  The service returns information about files in the
    directory or embeddings and streams in the container specified by the file
    handle.  The ReturnSingleEntry parameter specifies that only a single entry
    should be returned rather than filling the buffer.  The actual number of
    files whose information is returned, is the smallest of the following:

        o  One entry, if the ReturnSingleEntry parameter is TRUE.

        o  The number of entries whose information fits into the specified
           buffer.

        o  The number of entries that exist.

        o  One entry if the optional FileName parameter is specified.

    If the optional FileName parameter is specified, then the only information
    that is returned is for that single entries, if it exists.  Note that the
    file name may not specify any wildcard characters according to the naming
    conventions of the target file system.  The ReturnSingleEntry parameter is
    simply ignored.

    The information that is obtained about the entries in the directory or OLE
    container is based on the FileInformationClass parameter.  Legal values are
    hard coded based on the MinorFunction.

Arguments:

    FileHandle - Supplies a handle to the directory file or OLE container for
        which information should be returned.

    Event - Supplies an optional event to be set to the Signaled state when
        the query is complete.

    ApcRoutine - Supplies an optional APC routine to be executed when the
        query is complete.

    ApcContext - Supplies a context parameter to be passed to the ApcRoutine,
        if an ApcRoutine was specified.

    IoStatusBlock - Address of the caller's I/O status block.

    FileInformation - Supplies a buffer to receive the requested information
        returned about the contents of the directory.

    Length - Supplies the length, in bytes, of the FileInformation buffer.

    FileInformationClass - Specfies the type of information that is to be
        returned about the files in the specified directory or OLE container.

    ReturnSingleEntry - Supplies a BOOLEAN value that, if TRUE, indicates that
        only a single entry should be returned.

    FileName - Optionally supplies a file name within the specified directory
        or OLE container.

    RestartScan - Supplies a BOOLEAN value that, if TRUE, indicates that the
        scan should be restarted from the beginning.  This parameter must be
        set to TRUE by the caller the first time the service is invoked.

    MinorFunction - IRP_MN_QUERY_DIRECTORY or IRP_MN_QUERY_OLE_DIRECTORY

    SynchronousIo - pointer to returned BOOLEAN; TRUE if synchronous I/O

    DeviceObject - pointer to returned pointer to device object

    Irp - pointer to returned pointer to device object

    FileObject - pointer to returned pointer to file object

    RequestorMode - pointer to returned requestor mode

Return Value:

    The status returned is STATUS_SUCCESS if a valid irp was created for the
    query operation.

--*/

{
    PIRP irp;
    NTSTATUS status;
    PFILE_OBJECT fileObject;
    PDEVICE_OBJECT deviceObject;
    PKEVENT eventObject = (PKEVENT) NULL;
    KPROCESSOR_MODE requestorMode;
    PCHAR auxiliaryBuffer = (PCHAR) NULL;
    PIO_STACK_LOCATION irpSp;
    PMDL mdl;
    PETHREAD CurrentThread;

    PAGED_CODE();

    //
    // Get the previous mode;  i.e., the mode of the caller.
    //

    CurrentThread = PsGetCurrentThread ();
    requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
    *RequestorMode = requestorMode;

    try {

        if (requestorMode != KernelMode) {

            ULONG operationlength = 0;  // assume invalid

            //
            // The caller's access mode is not kernel so probe and validate
            // each of the arguments as necessary.  If any failures occur,
            // the condition handler will be invoked to handle them.  It
            // will simply cleanup and return an access violation status
            // code back to the system service dispatcher.
            //

            //
            // The IoStatusBlock parameter must be writeable by the caller.
            //

            ProbeForWriteIoStatus(IoStatusBlock);

            //
            // Ensure that the FileInformationClass parameter is legal for
            // querying information about files in the directory or object.
            //

            if (FileInformationClass == FileDirectoryInformation) {
                operationlength = sizeof(FILE_DIRECTORY_INFORMATION);
            } else if (MinorFunction == IRP_MN_QUERY_DIRECTORY) {
                switch (FileInformationClass)
                {
                case FileFullDirectoryInformation:
                    operationlength = sizeof(FILE_FULL_DIR_INFORMATION);
                    break;

                case FileIdFullDirectoryInformation:
                    operationlength = sizeof(FILE_ID_FULL_DIR_INFORMATION);
                    break;

                case FileBothDirectoryInformation:
                    operationlength = sizeof(FILE_BOTH_DIR_INFORMATION);
                    break;

                case FileIdBothDirectoryInformation:
                    operationlength = sizeof(FILE_ID_BOTH_DIR_INFORMATION);
                    break;

                case FileNamesInformation:
                    operationlength = sizeof(FILE_NAMES_INFORMATION);
                    break;

                case FileObjectIdInformation:
                    operationlength = sizeof(FILE_OBJECTID_INFORMATION);
                    break;

                case FileQuotaInformation:
                    operationlength = sizeof(FILE_QUOTA_INFORMATION);
                    break;

                case FileReparsePointInformation:
                    operationlength = sizeof(FILE_REPARSE_POINT_INFORMATION);
                    break;                    
                }
            }

            //
            // If the FileInformationClass parameter is illegal, fail now.
            //

            if (operationlength == 0) {
                return STATUS_INVALID_INFO_CLASS;
            }

            //
            // Ensure that the caller's supplied buffer is at least large enough
            // to contain the fixed part of the structure required for this
            // query.
            //

            if (Length < operationlength) {
                return STATUS_INFO_LENGTH_MISMATCH;
            }


            //
            // The FileInformation buffer must be writeable by the caller.
            //

#if defined(_X86_)
            ProbeForWrite( FileInformation, Length, sizeof( ULONG ) );
#elif defined(_WIN64)

            //
            // If we are a wow64 process, follow the X86 rules
            //

            if (PsGetCurrentProcessByThread(CurrentThread)->Wow64Process) {
                ProbeForWrite( FileInformation, Length, sizeof( ULONG ) );
            } else {
                ProbeForWrite( FileInformation,
                               Length,
                               IopQuerySetAlignmentRequirement[FileInformationClass] );
            }
            
#else
            ProbeForWrite( FileInformation,
                           Length,
                           IopQuerySetAlignmentRequirement[FileInformationClass] );
#endif
        }

        //
        // If the optional FileName parameter was specified, then it must be
        // readable by the caller.  Capture the file name string in a pool
        // block.  Note that if an error occurs during the copy, the cleanup
        // code in the exception handler will deallocate the pool before
        // returning an access violation status.
        //

        if (ARGUMENT_PRESENT( FileName )) {

            UNICODE_STRING fileName;
            PUNICODE_STRING nameBuffer;

            //
            // Capture the string descriptor itself to ensure that the
            // string is readable by the caller without the caller being
            // able to change the memory while its being checked.
            //

            if (requestorMode != KernelMode) {
                ProbeAndReadUnicodeStringEx( &fileName, FileName );
            } else {
                fileName = *FileName;
            }

            //
            // If the length is not an even number of bytes
            // return an error.
            //

            if (fileName.Length & (sizeof(WCHAR) - 1)) {
                return STATUS_INVALID_PARAMETER;
            }

            if (fileName.Length) {

                //
                // The length of the string is non-zero, so probe the
                // buffer described by the descriptor if the caller was
                // not kernel mode.  Likewise, if the caller's mode was
                // not kernel, then check the length of the name string
                // to ensure that it is not too long.
                //

                if (requestorMode != KernelMode) {
                    ProbeForRead( fileName.Buffer,
                                  fileName.Length,
                                  sizeof( UCHAR ) );
                    //
                    // account for unicode
                    //

                    if (fileName.Length > MAXIMUM_FILENAME_LENGTH<<1) {
                        ExRaiseStatus( STATUS_INVALID_PARAMETER );
                    }
                }

                //
                // Allocate an auxiliary buffer large enough to contain
                // a file name descriptor and to hold the entire file
                // name itself.  Copy the body of the string into the
                // buffer.
                //

                auxiliaryBuffer = ExAllocatePoolWithQuota( NonPagedPool,
                                                           fileName.Length + sizeof( UNICODE_STRING ) );
                RtlCopyMemory( auxiliaryBuffer + sizeof( UNICODE_STRING ),
                               fileName.Buffer,
                               fileName.Length );

                //
                // Finally, build the Unicode string descriptor in the
                // auxiliary buffer.
                //

                nameBuffer = (PUNICODE_STRING) auxiliaryBuffer;
                nameBuffer->Length = fileName.Length;
                nameBuffer->MaximumLength = fileName.Length;
                nameBuffer->Buffer = (PWSTR) (auxiliaryBuffer + sizeof( UNICODE_STRING ) );
            }
        }

    } except(EXCEPTION_EXECUTE_HANDLER) {

        //
        // An exception was incurred while probing the caller's buffers,
        // attempting to allocate a pool buffer, or while trying to copy
        // the caller's data.  Determine what happened, clean everything
        // up, and return an appropriate error status code.
        //

        if (auxiliaryBuffer) {
            ExFreePool( auxiliaryBuffer );
        }


        return GetExceptionCode();
    }

    //
    // There were no blatant errors so far, so reference the file object so
    // the target device object can be found.  Note that if the handle does
    // not refer to a file object, or if the caller does not have the required
    // access to the file, then it will fail.
    //

    status = ObReferenceObjectByHandle( FileHandle,
                                        FILE_LIST_DIRECTORY,
                                        IoFileObjectType,
                                        requestorMode,
                                        (PVOID *) &fileObject,
                                        (POBJECT_HANDLE_INFORMATION) NULL );
    if (!NT_SUCCESS( status )) {
        if (auxiliaryBuffer) {
            ExFreePool( auxiliaryBuffer );
        }
        return status;
    }
    *FileObject = fileObject;

    //
    // If this file has an I/O completion port associated w/it, then ensure
    // that the caller did not supply an APC routine, as the two are mutually
    // exclusive methods for I/O completion notification.
    //

    if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) {
        ObDereferenceObject( fileObject );
        if (auxiliaryBuffer) {
            ExFreePool( auxiliaryBuffer );
        }
        return STATUS_INVALID_PARAMETER;

    }

    //
    // Get the address of the event object and set the event to the Not-
    // Signaled state, if an event was specified.  Note here, too, that if
    // the handle does not refer to an event, or if the event cannot be
    // written, then the reference will fail.
    //

    if (ARGUMENT_PRESENT( Event )) {
        status = ObReferenceObjectByHandle( Event,
                                            EVENT_MODIFY_STATE,
                                            ExEventObjectType,
                                            requestorMode,
                                            (PVOID *) &eventObject,
                                            (POBJECT_HANDLE_INFORMATION) NULL );
        if (!NT_SUCCESS( status )) {
            if (auxiliaryBuffer) {
                ExFreePool( auxiliaryBuffer );
            }
            ObDereferenceObject( fileObject );
            return status;
        } else {
            KeClearEvent( eventObject );
        }
    }

    //
    // Make a special check here to determine whether this is a synchronous
    // I/O operation.  If it is, then wait here until the file is owned by
    // the current thread.
    //

    if (fileObject->Flags & FO_SYNCHRONOUS_IO) {

        BOOLEAN interrupted;

        if (!IopAcquireFastLock( fileObject )) {
            status = IopAcquireFileObjectLock( fileObject,
                                               requestorMode,
                                               (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
                                               &interrupted );
            if (interrupted) {
                if (auxiliaryBuffer != NULL) {
                    ExFreePool( auxiliaryBuffer );
                }
                if (eventObject != NULL) {
                    ObDereferenceObject( eventObject );
                }
                ObDereferenceObject( fileObject );
                return status;
            }
        }
        *SynchronousIo = TRUE;
    } else {
        *SynchronousIo = FALSE;

#if defined(_WIN64)
        if (requestorMode != KernelMode) {
            try {
            
                //
                // If this is a 32-bit asynchronous IO, then mark the Iosb being sent as so.
                // Note: IopMarkApcRoutineIfAsyncronousIo32 must be called after probing
                //       the IoStatusBlock structure for write.
                //

                IopMarkApcRoutineIfAsyncronousIo32(IoStatusBlock,ApcRoutine,FALSE);

            } except (EXCEPTION_EXECUTE_HANDLER) {
                
                //
                // An IRP could not be allocated.  Cleanup and return an appropriate
                // error status code.
                //

                IopAllocateIrpCleanup( fileObject, eventObject );                
                if (auxiliaryBuffer) {
                    ExFreePool( auxiliaryBuffer );
                }

                return GetExceptionCode ();
            }
        }
#endif
    }

    //
    // Set the file object to the Not-Signaled state.
    //

    KeClearEvent( &fileObject->Event );

    //
    // Get the address of the target device object.
    //

    deviceObject = IoGetRelatedDeviceObject( fileObject );
    *DeviceObject = deviceObject;

    //
    // Allocate and initialize the I/O Request Packet (IRP) for this operation.
    // The allocation is performed with an exception handler in case the
    // caller does not have enough quota to allocate the packet.

    irp = IoAllocateIrp( deviceObject->StackSize, !(*SynchronousIo) );
    if (!irp) {

        //
        // An IRP could not be allocated.  Cleanup and return an appropriate
        // error status code.
        //

        IopAllocateIrpCleanup( fileObject, eventObject );
        if (auxiliaryBuffer) {
            ExFreePool( auxiliaryBuffer );
        }

        return STATUS_INSUFFICIENT_RESOURCES;
    }
    *Irp = irp;

    irp->Tail.Overlay.OriginalFileObject = fileObject;
    irp->Tail.Overlay.Thread = CurrentThread;
    irp->RequestorMode = requestorMode;

    //
    // Fill in the service independent parameters in the IRP.
    //

    irp->UserEvent = eventObject;
    irp->UserIosb = IoStatusBlock;
    irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
    irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;

    //
    // Get a pointer to the stack location for the first driver.  This will be
    // used to pass the original function codes and parameters.
    //

    irpSp = IoGetNextIrpStackLocation( irp );
    irpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
    irpSp->MinorFunction = MinorFunction;
    irpSp->FileObject = fileObject;

    // Also, copy the caller's parameters to the service-specific portion of
    // the IRP.
    //

    irp->Tail.Overlay.AuxiliaryBuffer = auxiliaryBuffer;
    irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
    irp->MdlAddress = (PMDL) NULL;

    //
    // Now determine whether this driver expects to have data buffered to it
    // or whether it performs direct I/O.  This is based on the DO_BUFFERED_IO
    // flag in the device object.  If the flag is set, then a system buffer is
    // allocated and the driver's data will be copied into it.  Otherwise, a
    // Memory Descriptor List (MDL) is allocated and the caller's buffer is
    // locked down using it.
    //

    if (deviceObject->Flags & DO_BUFFERED_IO) {

        //
        // The device does not support direct I/O.  Allocate a system buffer
        // and specify that it should be deallocated on completion.  Also
        // indicate that this is an input operation so the data will be copied
        // into the caller's buffer.  This is done using an exception handler
        // that will perform cleanup if the operation fails.
        //

        try {

            //
            // Allocate the intermediary system buffer from nonpaged pool and
            // charge quota for it.
            //

            irp->AssociatedIrp.SystemBuffer =
                ExAllocatePoolWithQuota( NonPagedPool, Length );

        } except(EXCEPTION_EXECUTE_HANDLER) {

            //
            // An exception was incurred while either probing the caller's
            // buffer or allocate the system buffer.  Determine what actually
            // happened, clean everything up, and return an appropriate error
            // status code.
            //

            IopExceptionCleanup( fileObject,
                                 irp,
                                 eventObject,
                                 (PKEVENT) NULL );

            if (auxiliaryBuffer != NULL) {
                ExFreePool( auxiliaryBuffer );
            }

            return GetExceptionCode();

        }

        //
        // Remember the address of the caller's buffer so the copy can take
        // place during I/O completion.  Also, set the flags so that the
        // completion code knows to do the copy and to deallocate the buffer.
        //

        irp->UserBuffer = FileInformation;
        irp->Flags = (ULONG) (IRP_BUFFERED_IO |
                              IRP_DEALLOCATE_BUFFER |
                              IRP_INPUT_OPERATION);

    } else if (deviceObject->Flags & DO_DIRECT_IO) {
Exemplo n.º 2
0
NTSTATUS
NtFlushBuffersFile (
    __in HANDLE FileHandle,
    __out PIO_STATUS_BLOCK IoStatusBlock
    )

/*++

Routine Description:

    This service causes all buffered data to the file to be written.

Arguments:

    FileHandle - Supplies a handle to the file whose buffers should be flushed.

    IoStatusBlock - Address of the caller's I/O status block.

Return Value:

    The status returned is the final completion status of the operation.

--*/

{
    PIRP irp;
    NTSTATUS status;
    PFILE_OBJECT fileObject;
    PDEVICE_OBJECT deviceObject;
    PKEVENT event;
    KPROCESSOR_MODE requestorMode;
    PIO_STACK_LOCATION irpSp;
    IO_STATUS_BLOCK localIoStatus;
    OBJECT_HANDLE_INFORMATION objectHandleInformation;
    BOOLEAN synchronousIo;
    PETHREAD CurrentThread;

    PAGED_CODE();

    //
    // Get the previous mode;  i.e., the mode of the caller.
    //

    CurrentThread = PsGetCurrentThread ();
    requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);

    if (requestorMode != KernelMode) {

        //
        // The caller's access mode is not kernel so probe each of the arguments
        // and capture them as necessary.  If any failures occur, the condition
        // handler will be invoked to handle them.  It will simply cleanup and
        // return an access violation status code back to the system service
        // dispatcher.
        //

        try {

            //
            // The IoStatusBlock parameter must be writeable by the caller.
            //

            ProbeForWriteIoStatus( IoStatusBlock );

        } except(EXCEPTION_EXECUTE_HANDLER) {

            //
            // An exception was incurred attempting to probe the caller's
            // I/O status block.  Simply return an appropriate error status
            // code.
            //

            return GetExceptionCode();

        }
    }

    //
    // There were no blatant errors so far, so reference the file object so
    // the target device object can be found.  Note that if the handle does
    // not refer to a file object, or if the caller does not have the required
    // access to the file, then it will fail.
    //

    status = ObReferenceObjectByHandle( FileHandle,
                                        0,
                                        IoFileObjectType,
                                        requestorMode,
                                        (PVOID *) &fileObject,
                                        &objectHandleInformation );
    if (!NT_SUCCESS( status )) {
        return status;
    }

    //
    // Ensure that the caller has either WRITE or APPEND access to the file
    // before allowing this call to continue.  This is especially important
    // if the caller opened a volume, where a flush operation may flush more
    // than what this opener has written to buffers.  Note however that if
    // this is a pipe, then the APPEND access cannot be made since this
    // access code is overlaid with the CREATE_PIPE_INSTANCE access.
    //

    if (SeComputeGrantedAccesses( objectHandleInformation.GrantedAccess,
                                  (!(fileObject->Flags & FO_NAMED_PIPE) ?
                                  FILE_APPEND_DATA : 0) |
                                  FILE_WRITE_DATA ) == 0) {
        ObDereferenceObject( fileObject );
        return STATUS_ACCESS_DENIED;
    }

    //
    // Make a special check here to determine whether this is a synchronous
    // I/O operation.  If it is, then wait here until the file is owned by
    // the current thread.  If this is not a (serialized) synchronous I/O
    // operation, then allocate and initialize the local event.
    //

    if (fileObject->Flags & FO_SYNCHRONOUS_IO) {

        BOOLEAN interrupted;

        if (!IopAcquireFastLock( fileObject )) {
            status = IopAcquireFileObjectLock( fileObject,
                                               requestorMode,
                                               (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
                                               &interrupted );
            if (interrupted) {
                ObDereferenceObject( fileObject );
                return status;
            }
        }
        synchronousIo = TRUE;
        event = NULL;
    } else {

        //
        // This is a synchronous API being invoked for a file that is opened
        // for asynchronous I/O.  This means that this system service is
        // to synchronize the completion of the operation before returning
        // to the caller.  A local event is used to do this.
        //

        event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
        if (event == NULL) {
            ObDereferenceObject( fileObject );
            return STATUS_INSUFFICIENT_RESOURCES;
        }
        KeInitializeEvent( event, SynchronizationEvent, FALSE );
        synchronousIo = FALSE;
    }

    //
    // Set the file object to the Not-Signaled state.
    //

    KeClearEvent( &fileObject->Event );

    //
    // Get the address of the target device object.
    //

    deviceObject = IoGetRelatedDeviceObject( fileObject );

    //
    // Allocate and initialize the I/O Request Packet (IRP) for this operation.
    //

    irp = IoAllocateIrp( deviceObject->StackSize, FALSE );
    if (!irp) {

        //
        // An exception was incurred while attempting to allocate the IRP.
        // Cleanup and return an appropriate error status code.
        //

        if (event) {
            ExFreePool( event );
        }

        IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );

        return STATUS_INSUFFICIENT_RESOURCES;
    }
    irp->Tail.Overlay.OriginalFileObject = fileObject;
    irp->Tail.Overlay.Thread = CurrentThread;
    irp->RequestorMode = requestorMode;

    //
    // Fill in the service independent parameters in the IRP.
    //

    if (synchronousIo) {
        irp->UserEvent = (PKEVENT) NULL;
        irp->UserIosb = IoStatusBlock;
    } else {
        irp->UserEvent = event;
        irp->UserIosb = &localIoStatus;
        irp->Flags = IRP_SYNCHRONOUS_API;
    }
    irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;

    //
    // Get a pointer to the stack location for the first driver.  This is used
    // to pass the original function codes and parameters.
    //

    irpSp = IoGetNextIrpStackLocation( irp );
    irpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
    irpSp->FileObject = fileObject;

    //
    // Queue the packet, call the driver, and synchronize appropriately with
    // I/O completion.
    //

    status = IopSynchronousServiceTail( deviceObject,
                                        irp,
                                        fileObject,
                                        FALSE,
                                        requestorMode,
                                        synchronousIo,
                                        OtherTransfer );

    //
    // If the file for this operation was not opened for synchronous I/O, then
    // synchronization of completion of the I/O operation has not yet occurred
    // since the allocated event must be used for synchronous APIs on files
    // opened for asynchronous I/O.  Synchronize the completion of the I/O
    // operation now.
    //

    if (!synchronousIo) {

        status = IopSynchronousApiServiceTail( status,
                                               event,
                                               irp,
                                               requestorMode,
                                               &localIoStatus,
                                               IoStatusBlock );
    }

    return status;
}
Exemplo n.º 3
0
NTSTATUS
NtCancelIoFile (
    __in HANDLE FileHandle,
    __out PIO_STATUS_BLOCK IoStatusBlock
    )

/*++

Routine Description:

    This service causes all pending I/O operations for the specified file to be
    marked as canceled.  Most types of operations can be canceled immediately,
    while others may continue toward completion before they are actually
    canceled and the caller is notified.

    Only those pending operations that were issued by the current thread using
    the specified handle are canceled.  Any operations issued for the file by
    any other thread or any other process continues normally.

Arguments:

    FileHandle - Supplies a handle to the file whose operations are to be
        canceled.

    IoStatusBlock - Address of the caller's I/O status block.

Return Value:

    The status returned is the final completion status of the operation.

--*/

{
    PIRP irp;
    NTSTATUS status;
    PFILE_OBJECT fileObject;
    KPROCESSOR_MODE requestorMode;
    PETHREAD thread;
    BOOLEAN found = FALSE;
    PLIST_ENTRY header;
    PLIST_ENTRY entry;
    KIRQL irql;

    PAGED_CODE();


    //
    // Get the address of the current thread.  The thread contains a list of
    // the pending operations for this file.
    //

    thread = PsGetCurrentThread();

    //
    // Get the previous mode;  i.e., the mode of the caller.
    //

    requestorMode = KeGetPreviousModeByThread(&thread->Tcb);

    if (requestorMode != KernelMode) {

        //
        // The caller's access mode is user, so probe each of the arguments
        // and capture them as necessary.  If any failures occur, the condition
        // handler will be invoked to handle them.  It will simply cleanup and
        // return an access violation status code back to the system service
        // dispatcher.
        //

        try {

            //
            // The IoStatusBlock parameter must be writeable by the caller.
            //

            ProbeForWriteIoStatus( IoStatusBlock );

        } except(EXCEPTION_EXECUTE_HANDLER) {

            //
            // An exception was incurred attempting to probe the caller'
            // I/O status block.  Simply return an appropriate error status
            // code.
            //

            return GetExceptionCode();
        }
    }

    //
    // There were no blatant errors so far, so reference the file object so
    // the target device object can be found.  Note that if the handle does
    // not refer to a file object, or if the caller does not have the required
    // access to the file, then it will fail.
    //

    status = ObReferenceObjectByHandle( FileHandle,
                                        0,
                                        IoFileObjectType,
                                        requestorMode,
                                        (PVOID *) &fileObject,
                                        NULL );
    if (!NT_SUCCESS( status )) {
        return(status);
    }

    //
    // Note that here the I/O system would normally make a check to determine
    // whether or not the file was opened for synchronous I/O.  If it was, then
    // it would attempt to exclusively acquire the file object lock.  However,
    // since this service is attempting to cancel all of the I/O for the file,
    // it does not make much sense to wait until it has all completed before
    // attempting to cancel it.
    //


    //
    // Update the operation count statistic for the current process for
    // operations other than read and write.
    //

    IopUpdateOtherOperationCount();

    //
    // Walk the list of IRPs on the thread's pending I/O queue looking for IRPs
    // which specify the same file as the FileHandle refers to.  For each IRP
    // found, set its cancel flag.  If no IRPs are found, simply complete the
    // I/O here.  The only synchronization needed here is to block out all APCs
    // for this thread so that no I/O can complete and remove packets from the
    // queue.  No considerations need be made for multi-processing since this
    // thread can only be running on one processor at a time and this routine
    // has control of the thread for now.
    //

    KeRaiseIrql( APC_LEVEL, &irql );

    header = &thread->IrpList;
    entry = thread->IrpList.Flink;

    while (header != entry) {

        //
        // An IRP has been found for this thread.  If the IRP refers to the
        // appropriate file object, set its cancel flag and remember that it
        // was found;  otherwise, simply continue the loop.
        //

        irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry );
        if (irp->Tail.Overlay.OriginalFileObject == fileObject) {
            found = TRUE;
            IoCancelIrp( irp );
        }

        entry = entry->Flink;
    }

    //
    // Lower the IRQL back down to what it was on entry to this procedure.
    //

    KeLowerIrql( irql );

    if (found) {

        LARGE_INTEGER interval;

        //
        // Delay execution for a time and let the request
        // finish.  The delay time is 10ms.
        //

        interval.QuadPart = -10 * 1000 * 10;

        //
        // Wait for a while so the canceled requests can complete.
        //

        while (found) {

            (VOID) KeDelayExecutionThread( KernelMode, FALSE, &interval );

            found = FALSE;

            //
            // Raise the IRQL to prevent modification to the IRP list by the
            // thread's APC routine.
            //

            KeRaiseIrql( APC_LEVEL, &irql );

            //
            // Check the IRP list for requests which refer to the specified
            // file object.
            //

            entry = thread->IrpList.Flink;

            while (header != entry) {

                //
                // An IRP has been found for this thread.  If the IRP refers
                // to the appropriate file object,  remember that it
                // was found;  otherwise, simply continue the loop.
                //

                irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry );
                if (irp->Tail.Overlay.OriginalFileObject == fileObject) {
                    found = TRUE;
                    break;
                }

                entry = entry->Flink;
            }

            //
            // Lower the IRQL back down to what it was on entry to this procedure.
            //

            KeLowerIrql( irql );

        }
    }

    try {

        //
        // Write the status back to the user.
        //

        IoStatusBlock->Status = STATUS_SUCCESS;
        IoStatusBlock->Information = 0L;

    } except(EXCEPTION_EXECUTE_HANDLER) {

        //
        // An exception was incurred attempting to write the caller's
        // I/O status block; however, the service completed successfully so
        // just return success.
        //

    }

    //
    // Dereference the file object.
    //

    ObDereferenceObject( fileObject );

    return STATUS_SUCCESS;
}
Exemplo n.º 4
0
NTSTATUS
NtQueryVolumeInformationFile(
    IN HANDLE FileHandle,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    OUT PVOID FsInformation,
    IN ULONG Length,
    IN FS_INFORMATION_CLASS FsInformationClass
    )

/*++

Routine Description:

    This service returns information about the volume associated with the
    FileHandle parameter.  The information returned in the buffer is defined
    by the FsInformationClass parameter.  The legal values for this parameter
    are as follows:

        o  FileFsVolumeInformation

        o  FileFsSizeInformation

        o  FileFsDeviceInformation

        o  FileFsAttributeInformation

Arguments:

    FileHandle - Supplies a handle to an open volume, directory, or file
        for which information about the volume is returned.

    IoStatusBlock - Address of the caller's I/O status block.

    FsInformation - Supplies a buffer to receive the requested information
        returned about the volume.

    Length - Supplies the length, in bytes, of the FsInformation buffer.

    FsInformationClass - Specifies the type of information which should be
        returned about the volume.

Return Value:

    The status returned is the final completion status of the operation.

--*/

{
    PIRP irp;
    NTSTATUS status;
    PFILE_OBJECT fileObject;
    PDEVICE_OBJECT deviceObject;
    PKEVENT event = (PKEVENT) NULL;
    KPROCESSOR_MODE requestorMode;
    PIO_STACK_LOCATION irpSp;
    IO_STATUS_BLOCK localIoStatus;
    BOOLEAN synchronousIo;

    PAGED_CODE();


    //
    // Get the previous mode;  i.e., the mode of the caller.
    //

    requestorMode = KeGetPreviousMode();

    if (requestorMode != KernelMode) {

        //
        // Ensure that the FsInformationClass parameter is legal for querying
        // information about the volume.
        //

        if ((ULONG) FsInformationClass >= FileFsMaximumInformation ||
            IopQueryFsOperationLength[FsInformationClass] == 0) {
            return STATUS_INVALID_INFO_CLASS;
        }

        //
        // Finally, ensure that the supplied buffer is large enough to contain
        // the information associated with the specified query operation that
        // is to be performed.
        //

        if (Length < (ULONG) IopQueryFsOperationLength[FsInformationClass]) {
            return STATUS_INFO_LENGTH_MISMATCH;
        }

        //
        // The caller's access mode is not kernel so probe each of the arguments
        // and capture them as necessary.  If any failures occur, the condition
        // handler will be invoked to handle them.  It will simply cleanup and
        // return an access violation status code back to the system service
        // dispatcher.
        //

        try {

            //
            // The IoStatusBlock parameter must be writeable by the caller.
            //

            ProbeForWriteIoStatus( IoStatusBlock );

            //
            // The FsInformation buffer must be writeable by the caller.
            //

#if defined(_X86_)
            ProbeForWrite( FsInformation, Length, sizeof( ULONG ) );
#elif defined(_WIN64)

            //
            // If we are a wow64 process, follow the X86 rules
            //

            if (PsGetCurrentProcess()->Wow64Process) {
                ProbeForWrite( FsInformation, Length, sizeof( ULONG ) );
            } else {
                ProbeForWrite( FsInformation,
                               Length,
                               IopQuerySetFsAlignmentRequirement[FsInformationClass] );

            }
#else
            ProbeForWrite( FsInformation,
                           Length,
                           IopQuerySetFsAlignmentRequirement[FsInformationClass] );
#endif

        } except(EXCEPTION_EXECUTE_HANDLER) {

            //
            // An exception was incurred probing the caller's parameters.
            // Simply return an appropriate error status code.
            //

#if DBG
            if (GetExceptionCode() == STATUS_DATATYPE_MISALIGNMENT) {
                DbgBreakPoint();
            }
#endif // DBG

            return GetExceptionCode();

        }
    }

    //
    // There were no blatant errors so far, so reference the file object so
    // the target device object can be found.  Note that if the handle does
    // not refer to a file object, or if the caller does not have the required
    // access to the file, then it will fail.
    //

    status = ObReferenceObjectByHandle( FileHandle,
                                        IopQueryFsOperationAccess[FsInformationClass],
                                        IoFileObjectType,
                                        requestorMode,
                                        (PVOID *) &fileObject,
                                        NULL );
    if (!NT_SUCCESS( status )) {
        return status;
    }

    //
    // If this open file object represents an open device that was explicitly
    // opened for querying the device's attributes, then ensure that the type
    // of information class was device information.
    //

    if ((fileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
        FsInformationClass != FileFsDeviceInformation) {
        ObDereferenceObject( fileObject );
        return STATUS_INVALID_DEVICE_REQUEST;
    }

    //
    // Make a special check here to determine whether this is a synchronous
    // I/O operation.  If it is, then wait here until the file is owned by
    // the current thread.  If this is not a (serialized) synchronous I/O
    // operation, then allocate and initialize the local event.
    //

    if (fileObject->Flags & FO_SYNCHRONOUS_IO) {

        BOOLEAN interrupted;

        if (!IopAcquireFastLock( fileObject )) {
            status = IopAcquireFileObjectLock( fileObject,
                                               requestorMode,
                                               (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
                                               &interrupted );
            if (interrupted) {
                ObDereferenceObject( fileObject );
                return status;
            }
        }
        synchronousIo = TRUE;
    } else {
        synchronousIo = FALSE;
    }

    //
    // Get the address of the target device object.  A special check is made
    // here to determine whether this query is for device information.  If
    // it is, and either:
    //
    //     a)  The open was for the device itself, or
    //
    //     b)  The open was for a file but this is not a redirected device,
    //
    // then perform the query operation in-line.  That is, do not allocate
    // an IRP and call the driver, rather, simply copy the device type and
    // characteristics information from the target device object pointed
    // to by the device object in the file object (the "real" device object
    // in a mass storage device stack).
    //

    if (FsInformationClass == FileFsDeviceInformation &&
        (fileObject->Flags & FO_DIRECT_DEVICE_OPEN ||
        fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM)) {

        PFILE_FS_DEVICE_INFORMATION deviceAttributes;
        BOOLEAN deviceMounted = FALSE;

        //
        // This query operation can be performed in-line.  Simply copy the
        // information directly from the target device object and indicate
        // that the operation was successful.  Begin, however, by determining
        // whether or not the device is mounted.  This cannot be done at the
        // same time as attempting to touch the user's buffer, as looking at
        // the mounted bit occurs at raised IRQL.
        //

        deviceObject = fileObject->DeviceObject;
        if (deviceObject->Vpb) {
            deviceMounted = IopGetMountFlag( deviceObject );
        }

        //
        // Copy the characteristics information from the device's object
        // into the caller's buffer.
        //

        deviceAttributes = (PFILE_FS_DEVICE_INFORMATION) FsInformation;

        try {

            deviceAttributes->DeviceType = deviceObject->DeviceType;
            deviceAttributes->Characteristics = deviceObject->Characteristics;
            if (deviceMounted) {
                deviceAttributes->Characteristics |= FILE_DEVICE_IS_MOUNTED;
            }

            IoStatusBlock->Status = STATUS_SUCCESS;
            IoStatusBlock->Information = sizeof( FILE_FS_DEVICE_INFORMATION );
            status = STATUS_SUCCESS;

        } except( EXCEPTION_EXECUTE_HANDLER ) {

            //
            // An error occurred attempting to write into one of the caller's
            // buffers.  Simply indicate that the error occurred, and fall
            // through.
            //

            status = GetExceptionCode();
        }

        //
        // If this operation was performed as synchronous I/O, then release
        // the file object lock.
        //

        if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
            IopReleaseFileObjectLock( fileObject );
        }

        //
        // Now simply cleanup and return the final status of the operation.
        //

        ObDereferenceObject( fileObject );
        return status;

    }