Ejemplo n.º 1
0
VOID
NpAcquireExclusiveCcb (
    IN PNONPAGED_CCB NonpagedCcb
    )

/*++

Routine Description:

    This routine acquires exclusive access to the Ccb by first getting
    shared access to the Fcb.

Arguments:

    NonpagedCcb - Supplies the Ccb to acquire

Return Value:

    None.

--*/

{
    PAGED_CODE();

    DebugTrace(+1, Dbg, "NpAcquireExclusiveCcb, NonpagedCcb = %08lx\n", NonpagedCcb);

    (VOID)ExAcquireResourceShared( &(NpVcb->Resource), TRUE );

    (VOID)ExAcquireResourceExclusive( &(NonpagedCcb->Resource), TRUE );

    DebugTrace(-1, Dbg, "NpAcquireExclusiveCcb -> (VOID)\n", 0);

    return;
}
Ejemplo n.º 2
0
VOID
NpAcquireExclusiveVcb (
    )

/*++

Routine Description:

    This routine acquires exclusive access to the Vcb

Arguments:

Return Value:

    None.

--*/

{
    PAGED_CODE();

    DebugTrace(+1, Dbg, "NpAcquireExclusiveVcb\n", 0);

    ExAcquireResourceExclusive( &(NpVcb->Resource), TRUE );

    DebugTrace(-1, Dbg, "NpAcquireExclusiveVcb -> (VOID)\n", 0);

    return;
}
Ejemplo n.º 3
0
VOID
NtfsAcquireExclusiveGlobal (
    IN PIRP_CONTEXT IrpContext
    )

/*++

Routine Description:

    This routine acquires exclusive access to the global resource.

    This routine will raise if it cannot acquire the resource and wait
    in the IrpContext is false.

Arguments:

Return Value:

    None.

--*/

{
    ASSERT_IRP_CONTEXT(IrpContext);

    PAGED_CODE();

    if (!ExAcquireResourceExclusive( &NtfsData.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {

        NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
    }

    return;
}
Ejemplo n.º 4
0
BOOLEAN
NtfsAcquireVolumeForClose (
    IN PVOID OpaqueVcb,
    IN BOOLEAN Wait
    )

/*++

Routine Description:

    The address of this routine is specified when creating a CacheMap for
    a file.  It is subsequently called by the Lazy Writer prior to its
    performing closes to the file.  This callback is necessary to
    avoid deadlocks with the Lazy Writer.  (Note that normal closes
    acquire the Vcb, and then call the Cache Manager, who must acquire
    some of his internal structures.  If the Lazy Writer could not call
    this routine first, and were to issue a write after locking Caching
    data structures, then a deadlock could occur.)

Arguments:

    Vcb - The Vcb which was specified as a close context parameter for this
          routine.

    Wait - TRUE if the caller is willing to block.

Return Value:

    FALSE - if Wait was specified as FALSE and blocking would have
            been required.  The Fcb is not acquired.

    TRUE - if the Vcb has been acquired

--*/

{
    PVCB Vcb = (PVCB)OpaqueVcb;

    ASSERT_VCB(Vcb);

    PAGED_CODE();

    //
    //  Do the code of acquire exclusive Vcb but without the IrpContext
    //

    if (ExAcquireResourceExclusive( &Vcb->Resource, Wait )) {

        return TRUE;
    }

    return FALSE;
}
Ejemplo n.º 5
0
BOOLEAN
NtfsAcquireExclusiveVcb (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN BOOLEAN RaiseOnCantWait
    )

/*++

Routine Description:

    This routine acquires exclusive access to the Vcb.

    This routine will raise if it cannot acquire the resource and wait
    in the IrpContext is false.

Arguments:

    Vcb - Supplies the Vcb to acquire

    RaiseOnCantWait - Indicates if we should raise on an acquisition error
        or simply return a BOOLEAN indicating that we couldn't get the
        resource.

Return Value:

    BOOLEAN - Indicates if we were able to acquire the resource.  This is really
        only meaningful if the RaiseOnCantWait value is FALSE.

--*/

{
    ASSERT_IRP_CONTEXT(IrpContext);
    ASSERT_VCB(Vcb);

    PAGED_CODE();

    if (ExAcquireResourceExclusive( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {

        return TRUE;
    }

    if (RaiseOnCantWait) {

        NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
    }

    return FALSE;
}
Ejemplo n.º 6
0
VOID
NtfsAcquireForCreateSection (
    IN PFILE_OBJECT FileObject
    )

{
    PSCB Scb = (PSCB)FileObject->FsContext;

    PAGED_CODE();

    if (Scb->Header.PagingIoResource != NULL) {

        ExAcquireResourceExclusive( Scb->Header.PagingIoResource, TRUE );
    }
}
Ejemplo n.º 7
0
FINISHED
FatAcquireExclusiveVcb (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb
    )

/*++

Routine Description:

    This routine acquires exclusive access to the Vcb.

    After we acquire the resource check to see if this operation is legal.
    If it isn't (ie. we get an exception), release the resource.

Arguments:

    Vcb - Supplies the Vcb to acquire

Return Value:

    FINISHED - TRUE if we have the resource and FALSE if we needed to block
        for the resource but Wait is FALSE.

--*/

{
    if (ExAcquireResourceExclusive( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {

        try {

            FatVerifyOperationIsLegal( IrpContext );

        } finally {

            if ( AbnormalTermination() ) {

                FatReleaseVcb( IrpContext, Vcb );
            }
        }

        return TRUE;

    } else {

        return FALSE;
Ejemplo n.º 8
0
NTSTATUS
DfsCommonClose (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
) {
    NTSTATUS Status;

    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
    PFILE_OBJECT FileObject = IrpSp->FileObject;

    TYPE_OF_OPEN TypeOfOpen;
    PDFS_VCB Vcb;
    PDFS_FCB Fcb;

    BOOLEAN DontComplete = FALSE;
    BOOLEAN pktLocked;

    DfsDbgTrace(+1, Dbg, "DfsCommonClose: Entered\n", 0);

    DfsDbgTrace( 0, Dbg, "Irp          = %08lx\n", Irp);
    DfsDbgTrace( 0, Dbg, "->FileObject = %08lx\n", FileObject);


    //
    //  This action is a noop for unopened file objects.  Nothing needs
    //  to be done for FS device opens, either.
    //

    TypeOfOpen = DfsDecodeFileObject( FileObject, &Vcb, &Fcb);
    if (TypeOfOpen == UnopenedFileObject ||
        TypeOfOpen == FilesystemDeviceOpen ) {

        DfsDbgTrace(-1, Dbg, "DfsCommonClose:  Filesystem file object\n", 0);
        DfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
        return STATUS_SUCCESS;
    }

    try {

        //
        //  Case on the type of open that we are trying to close.
        //

        switch (TypeOfOpen) {

        case LogicalRootDeviceOpen:

            DfsDbgTrace(0, Dbg, "DfsCommonClose: Close LogicalRootDevice\n", 0);

            ExInterlockedDecrementLong(&Vcb->DirectAccessOpenCount, &DfsData.DfsLock);
            ExInterlockedDecrementLong(&Vcb->OpenFileCount, &DfsData.DfsLock);

            if (Vcb->VcbState & VCB_STATE_FLAG_LOCKED) {
                ASSERT (Vcb->FileObjectWithVcbLocked == FileObject);
                Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED;
                Vcb->FileObjectWithVcbLocked = NULL;
            }

            try_return( Status = STATUS_SUCCESS );

        case RedirectedFileOpen:

            DfsDbgTrace(0, Dbg, "DfsCommonClose:  File -> %wZ\n", &Fcb->FullFileName);

            //
            //  Decrement the OpenFileCount for the Vcb through which this
            //  file was opened.
            //

            ExInterlockedDecrementLong(&Vcb->OpenFileCount, &DfsData.DfsLock);

            //
            //  Decrement the RefCount on the DFS_MACHINE_ENTRY through which
            //  this file was opened
            //

            PktAcquireExclusive( TRUE, &pktLocked );

            ExAcquireResourceExclusive( &DfsData.Resource, TRUE );

            DfsDecrementMachEntryCount(Fcb->DfsMachineEntry, TRUE);

            ExReleaseResource( &DfsData.Resource );

            PktRelease();


            //
            //  Close the redirected file by simply passing through
            //  to the redirected device.  We detach the DFS_FCB from the
            //  file object before the close so it cannot be looked
            //  up in some other thread.
            //

            DfsDetachFcb( FileObject, Fcb);
            Status = DfsFilePassThrough(Fcb, Irp);

            DontComplete = TRUE;

            DfsDeleteFcb( IrpContext, Fcb );

            break;

        default:
            BugCheck("Dfs close, unexpected open type");
        }

        Status = STATUS_SUCCESS;

    try_exit: NOTHING;

    } finally {

        //
        //  If this is a normal termination, then complete the request.
        //  Even if we're not to complete the IRP, we still need to
        //  delete the IRP_CONTEXT.
        //

        if (!AbnormalTermination()) {
            if (DontComplete) {
                DfsCompleteRequest( IrpContext, NULL, 0 );
            } else {
                DfsCompleteRequest( IrpContext, Irp, Status );
            }
        }

        DfsDbgTrace(-1, Dbg, "DfsCommonClose:  Exit -> %08lx\n", Status);
    }
    return Status;
}
Ejemplo n.º 9
0
VOID
BowserTrace(
    PCHAR FormatString,
    ...
    )

#define LAST_NAMED_ARGUMENT FormatString

{
    CHAR OutputString[1024];
    IO_STATUS_BLOCK IoStatus;
    BOOLEAN ProcessAttached = FALSE;
    va_list ParmPtr;                    // Pointer to stack parms.
    NTSTATUS Status;

    PAGED_CODE();

    if (IoGetCurrentProcess() != BowserFspProcess) {
        KeAttachProcess(BowserFspProcess);

        ProcessAttached = TRUE;
    }


    if (BrowserTraceLogHandle == NULL) {

        if (!NT_SUCCESS(BowserOpenTraceLogFile(L"\\SystemRoot\\Bowser.Log"))) {

            BrowserTraceLogHandle = (HANDLE)0xffffffff;

            if (ProcessAttached) {
                KeDetachProcess();
            }

            return;
        }

    } else if (BrowserTraceLogHandle == (HANDLE)0xffffffff) {

        if (ProcessAttached) {
            KeDetachProcess();
        }

        return;
    }


    ExAcquireResourceExclusive(&BrowserTraceLock, TRUE);

    if (BrowserTraceLogHandle == NULL) {

        ExReleaseResource(&BrowserTraceLock);

        if (ProcessAttached) {
            KeDetachProcess();
        }

        return;
    }

    try {
        LARGE_INTEGER EndOfFile;

        EndOfFile.HighPart = 0xffffffff;
        EndOfFile.LowPart = FILE_WRITE_TO_END_OF_FILE;

        if (LastCharacter == '\n') {
            LARGE_INTEGER SystemTime;
            TIME_FIELDS TimeFields;

            KeQuerySystemTime(&SystemTime);

            ExSystemTimeToLocalTime(&SystemTime, &SystemTime);

            RtlTimeToTimeFields(&SystemTime, &TimeFields);

            //
            //  The last character written was a newline character.  We should
            //  timestamp this record in the file.
            //
/****
            sprintf(OutputString, "%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d.%3.3d: ", TimeFields.Month,
                                                            TimeFields.Day,
                                                            TimeFields.Year,
                                                            TimeFields.Hour,
                                                            TimeFields.Minute,
                                                            TimeFields.Second,
                                                            TimeFields.Milliseconds);
****/

            if (!NT_SUCCESS(Status = ZwWriteFile(BrowserTraceLogHandle, NULL, NULL, NULL, &IoStatus, OutputString, strlen(OutputString), &EndOfFile, NULL))) {
                KdPrint(("Error writing time to Browser log file: %lX\n", Status));
                return;
            }

            if (!NT_SUCCESS(IoStatus.Status)) {
                KdPrint(("Error writing time to Browser log file: %lX\n", IoStatus.Status));
                return;
            }

            if (IoStatus.Information != strlen(OutputString)) {
                KdPrint(("Error writing time to Browser log file: %lX\n", IoStatus.Status));
                return;
            }

        }

        va_start(ParmPtr, LAST_NAMED_ARGUMENT);

        //
        //  Format the parameters to the string.
        //

        vsprintf(OutputString, FormatString, ParmPtr);

        if (!NT_SUCCESS(Status = ZwWriteFile(BrowserTraceLogHandle, NULL, NULL, NULL, &IoStatus, OutputString, strlen(OutputString), &EndOfFile, NULL))) {
            KdPrint(("Error writing string to Browser log file: %ld\n", Status));
            return;
        }

        if (!NT_SUCCESS(IoStatus.Status)) {
            KdPrint(("Error writing string to Browser log file: %lX\n", IoStatus.Status));
            return;
        }

        if (IoStatus.Information != strlen(OutputString)) {
            KdPrint(("Error writing string to Browser log file: %ld\n", IoStatus.Status));
            return;
        }

        //
        //  Remember the last character output to the log.
        //

        LastCharacter = OutputString[strlen(OutputString)-1];

    } finally {
        ExReleaseResource(&BrowserTraceLock);

        if (ProcessAttached) {
            KeDetachProcess();
        }
    }
}
Ejemplo n.º 10
0
VOID
DfsDeleteDevices(
    PDFS_TIMER_CONTEXT DfsTimerContext)
{
    PLIST_ENTRY plink;
    PDFS_VCB Vcb;
    PLOGICAL_ROOT_DEVICE_OBJECT DeletedObject;

    if (DfsData.DeletedVcbQueue.Flink != &DfsData.DeletedVcbQueue) {

        DfsDbgTrace(0, Dbg, "Examining Deleted Vcbs...\n", 0);

        ExAcquireResourceExclusive(&DfsData.Resource, TRUE);

        for (plink = DfsData.DeletedVcbQueue.Flink;
                plink != &DfsData.DeletedVcbQueue;
                    NOTHING) {

             Vcb = CONTAINING_RECORD(
                        plink,
                        DFS_VCB,
                        VcbLinks);

             plink = plink->Flink;

             DeletedObject = CONTAINING_RECORD(
                                Vcb,
                                LOGICAL_ROOT_DEVICE_OBJECT,
                                Vcb);

             if (Vcb->OpenFileCount == 0 &&
                    Vcb->DirectAccessOpenCount == 0 &&
                        DeletedObject->DeviceObject.ReferenceCount == 0) {

                 DfsDbgTrace(0, Dbg, "Deleting Vcb@%08lx\n", Vcb);

                 if (Vcb->LogRootPrefix.Buffer != NULL)
                     ExFreePool(Vcb->LogRootPrefix.Buffer);

                 if (Vcb->LogicalRoot.Buffer != NULL)
                     ExFreePool(Vcb->LogicalRoot.Buffer);

                 RemoveEntryList(&Vcb->VcbLinks);

                 ObDereferenceObject((PVOID) DeletedObject);

                 IoDeleteDevice( &DeletedObject->DeviceObject );

             } else {

                 DfsDbgTrace(0, Dbg, "Not deleting Vcb@%08lx\n", Vcb);

                 DfsDbgTrace(0, Dbg,
                    "OpenFileCount = %d\n", Vcb->OpenFileCount);

                 DfsDbgTrace(0, Dbg,
                    "DirectAccessOpens = %d\n", Vcb->DirectAccessOpenCount);

                 DfsDbgTrace(0, Dbg,
                    "DeviceObject Reference count = %d\n",
                    DeletedObject->DeviceObject.ReferenceCount);

             }

        }

        ExReleaseResource(&DfsData.Resource);

    }

    DfsTimerContext->InUse = FALSE;

}
Ejemplo n.º 11
0
NTSTATUS
IopGetSetSecurityObject(
    IN PVOID Object,
    IN SECURITY_OPERATION_CODE OperationCode,
    IN PSECURITY_INFORMATION SecurityInformation,
    IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
    IN OUT PULONG CapturedLength,
    IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
    IN POOL_TYPE PoolType,
    IN PGENERIC_MAPPING GenericMapping
    )

/*++

Routine Description:

    This routine is invoked to either query or set the security descriptor
    for a file, directory, volume, or device.  It implements these functions
    by either performing an in-line check if the file is a device or a
    volume, or an I/O Request Packet (IRP) is generated and given to the
    driver to perform the operation.

Arguments:

    Object - Pointer to the file or device object representing the open object.

    SecurityInformation - Information about what is being done to or obtained
        from the object's security descriptor.

    SecurityDescriptor - Supplies the base security descriptor and returns
        the final security descriptor.  Note that if this buffer is coming
        from user space, it has already been probed by the object manager
        to length "CapturedLength", otherwise it points to kernel space and
        should not be probed.  It must, however, be referenced in a try
        clause.

    CapturedLength - For a query operation this specifies the size, in
        bytes, of the output security descriptor buffer and on return
        contains the number of bytes needed to store the complete security
        descriptor.  If the length needed is greater than the length
        supplied the operation will fail.  This parameter is ignored for
        the set and delete operations.  It is expected to point into
        system space, ie, it need not be probed and it will not change.

    ObjectsSecurityDescriptor - Supplies and returns the object's security
        descriptor.

    PoolType - Specifies from which type of pool memory is to be allocated.

    GenericMapping - Supplies the generic mapping for the object type.

Return Value:

    The final status of the operation is returned as the function value.

--*/

{
    NTSTATUS status;
    PFILE_OBJECT fileObject;
    PDEVICE_OBJECT deviceObject;
    PDEVICE_OBJECT devicePDO = NULL;
    BOOLEAN synchronousIo;

    UNREFERENCED_PARAMETER( ObjectsSecurityDescriptor );
    UNREFERENCED_PARAMETER( PoolType );

    PAGED_CODE();


    //
    // Begin by determining whether the security operation is to be performed
    // in this routine or by the driver.  This is based upon whether the
    // object represents a device object, or it represents a file object
    // to a device, or a file on the device. If the open is a direct device
    // open then use the device object.
    //

    if (((PDEVICE_OBJECT) (Object))->Type == IO_TYPE_DEVICE) {
        deviceObject = (PDEVICE_OBJECT) Object;
        fileObject = (PFILE_OBJECT) NULL;
    } else {
        fileObject = (PFILE_OBJECT) Object;
        if (fileObject->Flags & FO_DIRECT_DEVICE_OPEN) {
            deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
        }
        else {
                deviceObject = fileObject->DeviceObject;
        }
    }

    if (!fileObject ||
        (!fileObject->FileName.Length && !fileObject->RelatedFileObject) ||
        (fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {

        //
        // This security operation is for the device itself, either through
        // a file object, or directly to the device object.  For the latter
        // case, assignment operations are also possible.  Also note that
        // this may be a stream file object, which do not have security.
        // The security for a stream file is actually represented by the
        // security descriptor on the file itself, or the volume, or the
        // device.
        //

        if (OperationCode == AssignSecurityDescriptor) {

            //
            // Simply assign the security descriptor to the device object,
            // if this is a device object.
            //

            if (fileObject == NULL || !(fileObject->Flags & FO_STREAM_FILE)) {
                KeEnterCriticalRegion();
                ExAcquireResourceExclusive( &IopSecurityResource, TRUE );
                deviceObject->SecurityDescriptor = SecurityDescriptor;
                ExReleaseResource( &IopSecurityResource );
                KeLeaveCriticalRegion();
            }
            status = STATUS_SUCCESS;

        } else if (OperationCode == SetSecurityDescriptor) {

            //
            // This is a set operation.  The SecurityInformation parameter
            // determines what part of the SecurityDescriptor is going to
            // be applied to the ObjectsSecurityDescriptor.
            //

            //
            // if this deviceObject is attached to a PDO then we want
            // to modify the security on the PDO and apply it up the
            // device chain
            //
            if (fileObject == NULL || !(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
                //
                // see if there is a PDO for this object, and obtain it
                //
                devicePDO = IopGetDevicePDO(deviceObject);
            } else {
                devicePDO = NULL;
            }
            if (devicePDO) {
                //
                // set PDO and all attached device objects
                //
                status = IopSetDeviceSecurityDescriptors(devicePDO,SecurityInformation,SecurityDescriptor,PoolType,GenericMapping,TRUE);
                ObDereferenceObject( devicePDO );
            } else {
                //
                // set this device object only
                //
                status = IopSetDeviceSecurityDescriptors(deviceObject,SecurityInformation,SecurityDescriptor,PoolType,GenericMapping,FALSE);
            }

        } else if (OperationCode == QuerySecurityDescriptor) {

            //
            // This is a get operation.  The SecurityInformation parameter
            // determines what part of the SecurityDescriptor is going to
            // be returned from the ObjectsSecurityDescriptor.
            //

            KeEnterCriticalRegion();
            ExAcquireResourceShared( &IopSecurityResource, TRUE );
            status = SeQuerySecurityDescriptorInfo( SecurityInformation,
                                                    SecurityDescriptor,
                                                    CapturedLength,
                                                    &deviceObject->SecurityDescriptor );
            ExReleaseResource( &IopSecurityResource );
            KeLeaveCriticalRegion();

        } else {

            //
            // This is a delete operation.  Simply indicate that everything
            // worked just fine.
            //

            status = STATUS_SUCCESS;

        }

    } else if (OperationCode == DeleteSecurityDescriptor) {

        //
        // This is a delete operation for the security descriptor on a file
        // object.  This function will be performed by the file system once
        // the FCB itself is deleted.  Simply indicate that the operation
        // was successful.
        //

        status = STATUS_SUCCESS;

    } else {

        PIRP irp;
        IO_STATUS_BLOCK localIoStatus;
        KEVENT event;
        PIO_STACK_LOCATION irpSp;
        KPROCESSOR_MODE requestorMode;

        //
        // This file object does not refer to the device itself.  Rather, it
        // refers to either a file or a directory on the device.  This means
        // that the request must be passed to the file system for processing.
        // Note that the only requests that are passed through in this manner
        // are SET or QUERY security operations.  DELETE operations have
        // already been taken care of above since the file system which just
        // drop the storage on the floor when it really needs to, and ASSIGN
        // operations are irrelevant to file systems since they never
        // generate one because they never assign the security descriptor
        // to the object in the first place, they just assign it to the FCB.
        //

        requestorMode = KeGetPreviousMode();

        //
        // Begin by referencing the object by pointer.   Note that the object
        // handle has already been checked for the appropriate access by the
        // object system caller.  This reference must be performed because
        // standard I/O completion will dereference the object.
        //

        ObReferenceObject( fileObject );

        //
        // 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 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 {
            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.  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, TRUE );
        if (!irp) {

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

            IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );

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

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

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

        //
        // 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 );

        //
        // Now determine whether this is a set or a query operation.
        //

        if (OperationCode == QuerySecurityDescriptor) {

            //
            // This is a query operation.  Fill in the appropriate fields in
            // the stack location for the packet, as well as the fixed part
            // of the packet.  Note that each of these parameters has been
            // captured as well, so there is no need to perform any probing.
            // The only exception is the UserBuffer memory may change, but
            // that is the file system's responsibility to check.  Note that
            // it has already been probed, so the pointer is at least not
            // in an address space that the caller should not be accessing
            // because of mode.
            //

            irpSp->MajorFunction = IRP_MJ_QUERY_SECURITY;
            irpSp->Parameters.QuerySecurity.SecurityInformation = *SecurityInformation;
            irpSp->Parameters.QuerySecurity.Length = *CapturedLength;
            irp->UserBuffer = SecurityDescriptor;

        } else {

            //
            // This is a set operation.  Fill in the appropriate fields in
            // the stack location for the packet.  Note that access to the
            // SecurityInformation parameter is safe, as the parameter was
            // captured by the caller.  Likewise, the SecurityDescriptor
            // refers to a captured copy of the descriptor.
            //

            irpSp->MajorFunction = IRP_MJ_SET_SECURITY;
            irpSp->Parameters.SetSecurity.SecurityInformation = *SecurityInformation;
            irpSp->Parameters.SetSecurity.SecurityDescriptor = SecurityDescriptor;

        }

        irpSp->FileObject = fileObject;

        //
        // Insert the packet at the head of the IRP list for the thread.
        //

        IopQueueThreadIrp( irp );

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

        IopUpdateOtherOperationCount();

        //
        // Everything has been properly set up, so simply invoke the driver.
        //

        status = IoCallDriver( deviceObject, irp );

        //
        // If this operation was a synchronous I/O operation, check the return
        // status to determine whether or not to wait on the file object.  If
        // the file object is to be waited on, wait for the operation to be
        // completed and obtain the final status from the file object itself.
        //

        if (synchronousIo) {
            if (status == STATUS_PENDING) {
                (VOID) KeWaitForSingleObject( &fileObject->Event,
                                              Executive,
                                              KernelMode,
                                              FALSE,
                                              (PLARGE_INTEGER) NULL );
                status = fileObject->FinalStatus;
            }
            IopReleaseFileObjectLock( fileObject );

        } else {

            //
            // This is a normal synchronous I/O operation, as opposed to a
            // serialized synchronous I/O operation.  For this case, wait
            // for the local event and return the final status information
            // back to the caller.
            //

            if (status == STATUS_PENDING) {
                (VOID) KeWaitForSingleObject( &event,
                                              Executive,
                                              KernelMode,
                                              FALSE,
                                              (PLARGE_INTEGER) NULL );
                status = localIoStatus.Status;
            }
        }

        //
        // If this operation was just attempted on a file system or a device
        // driver of some kind that does not implement security, then return
        // a normal null security descriptor.
        //

        if (status == STATUS_INVALID_DEVICE_REQUEST) {

            //
            // The file system does not implement a security policy.  Determine
            // what type of operation this was and implement the correct
            // semantics for the file system.
            //

            if (OperationCode == QuerySecurityDescriptor) {

                //
                // The operation is a query.  If the caller's buffer is too
                // small, then indicate that this is the case and let him know
                // what size buffer is required.  Otherwise, attempt to return
                // a null security descriptor.
                //

               try {
                    status = SeAssignWorldSecurityDescriptor(
                                 SecurityDescriptor,
                                 CapturedLength,
                                 SecurityInformation
                                 );

                } except( EXCEPTION_EXECUTE_HANDLER ) {

                    //
                    // An exception was incurred while attempting to
                    // access the caller's buffer.  Clean everything
                    // up and return an appropriate status code.
                    //

                    status = GetExceptionCode();
                }

            } else {

                //
                // This was an operation other than a query.  Simply indicate
                // that the operation was successful.
                //

                status = STATUS_SUCCESS;
            }

        } else if (OperationCode == QuerySecurityDescriptor) {
Ejemplo n.º 12
0
NTSTATUS
IopSetDeviceSecurityDescriptors(
    IN PDEVICE_OBJECT           DeviceObject,
    IN PSECURITY_INFORMATION    SecurityInformation,
    IN PSECURITY_DESCRIPTOR     SecurityDescriptor,
    IN POOL_TYPE                PoolType,
    IN PGENERIC_MAPPING         GenericMapping,
    IN BOOLEAN                  DoAttachedDevices
    )
/*++

Routine Description:

    Call this routine to set device security descriptor

Arguments:

    DeviceObject - pointer to base device object (first one to set)
    SecurityInformation )_ passed directly from IopGetSetSecurityObject
    SecurityDescriptor  )
    PoolType            )
    GenericMapping      )
    DoAttachedDevices - if true, iterate the AttachedDevice list

ReturnValue:

    success, or error from first failure

--*/
{
    PDEVICE_OBJECT NewDeviceObject = NULL;
    PSECURITY_DESCRIPTOR OldSecurityDescriptor;
    KIRQL irql;
    NTSTATUS status;
    NTSTATUS firsterr = STATUS_SUCCESS;
    BOOLEAN first = TRUE;

    ASSERT(DeviceObject);

    IopAcquireEnumerationLock(NULL);        // ensure we have acquired P&P locks
    //
    // pre-reference this object to match the dereference later
    //
    ObReferenceObject( DeviceObject );

    do {
        KeEnterCriticalRegion();
        ExAcquireResourceExclusive( &IopSecurityResource, TRUE );

        OldSecurityDescriptor = DeviceObject->SecurityDescriptor;

        if (OldSecurityDescriptor || first) {
            //
            // always call this on the first object, only do it for others that have a security descriptor
            //
            status = SeSetSecurityDescriptorInfo( NULL,
                                                  SecurityInformation,
                                                  SecurityDescriptor,
                                                  &DeviceObject->SecurityDescriptor,
                                                  PoolType,
                                                  GenericMapping );

            if (NT_SUCCESS(firsterr)) {
                firsterr = status;
            }
            if (NT_SUCCESS( status )) {
                ASSERT(OldSecurityDescriptor);
                ExFreePool( OldSecurityDescriptor );
            }
            first = FALSE;
        }

        ExReleaseResource( &IopSecurityResource );
        KeLeaveCriticalRegion();

        //
        // get next device on attachment chain
        //
        ExAcquireSpinLock(&IopDatabaseLock,&irql);
        NewDeviceObject = DeviceObject->AttachedDevice;
        if ( NewDeviceObject != NULL ) {
            ObReferenceObject( NewDeviceObject );
        } else {
            DoAttachedDevices = FALSE;
        }
        ExReleaseSpinLock(&IopDatabaseLock,irql);

        ObDereferenceObject( DeviceObject );
        DeviceObject = NewDeviceObject;

    } while(DoAttachedDevices);

    IopReleaseEnumerationLock(NULL);

    return firsterr;    // of the PDO / single object
}
Ejemplo n.º 13
0
BOOLEAN
NtfsAcquireExclusiveFcb (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PSCB Scb OPTIONAL,
    IN BOOLEAN NoDeleteCheck,
    IN BOOLEAN DontWait
    )

/*++

Routine Description:

    This routine acquires exclusive access to the Fcb.

    This routine will raise if it cannot acquire the resource and wait
    in the IrpContext is false.

Arguments:

    Fcb - Supplies the Fcb to acquire

    Scb - This is the Scb for which we are acquiring the Fcb

    NoDeleteCheck - If TRUE, we don't do any check for deleted files but
        always acquire the Fcb.

    DontWait - If TRUE this overrides the wait value in the IrpContext.
        We won't wait for the resource and return whether the resource
        was acquired.

Return Value:

    BOOLEAN - TRUE if acquired.  FALSE otherwise.

--*/

{
    NTSTATUS Status;
    BOOLEAN Wait;

    ASSERT_IRP_CONTEXT(IrpContext);
    ASSERT_FCB(Fcb);

    PAGED_CODE();

    Status = STATUS_CANT_WAIT;

    if (DontWait ||
        !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {

        Wait = FALSE;

    } else {

        Wait = TRUE;
    }

    if (ExAcquireResourceExclusive( Fcb->Resource, Wait )) {

        //
        //  The link count should be non-zero or the file has been
        //  deleted.  We allow deleted files to be acquired for close and
        //  also allow them to be acquired recursively in case we
        //  acquire them a second time after marking them deleted (i.e. rename)
        //

        if (NoDeleteCheck

            ||

            (IrpContext->MajorFunction == IRP_MJ_CLOSE)

            ||

            (IrpContext->MajorFunction == IRP_MJ_CREATE)

            ||

            (!FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED )
             && (!ARGUMENT_PRESENT( Scb )
                 || !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )))) {

            //
            //  Put Fcb in the exclusive Fcb list for this IrpContext,
            //  excluding the bitmap for the volume, since we do not need
            //  to modify its file record and do not want unnecessary
            //  serialization/deadlock problems.
            //

            if ((Fcb->Vcb->BitmapScb == NULL) ||
                (Fcb->Vcb->BitmapScb->Fcb != Fcb)) {

                //
                //  We need to check if this Fcb is already in an
                //  exclusive list.  If it is then we want to attach
                //  the current IrpContext to the IrpContext holding
                //  this Fcb.
                //

                if (Fcb->ExclusiveFcbLinks.Flink == NULL) {

                    ASSERT( Fcb->BaseExclusiveCount == 0 );

                    InsertTailList( &IrpContext->ExclusiveFcbList,
                                    &Fcb->ExclusiveFcbLinks );
                }

                Fcb->BaseExclusiveCount += 1;
            }

            return TRUE;
        }

        //
        //  We need to release the Fcb and remember the status code.
        //

        ExReleaseResource( Fcb->Resource );
        Status = STATUS_FILE_DELETED;

    } else if (DontWait) {

        return FALSE;
    }

    NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
}
Ejemplo n.º 14
0
NTSTATUS
FFSWriteVolume(
	IN PFFS_IRP_CONTEXT IrpContext)
{
	NTSTATUS            Status = STATUS_UNSUCCESSFUL;

	PFFS_VCB            Vcb  = NULL;
	PFFS_CCB            Ccb = NULL;
	PFFS_FCBVCB         FcbOrVcb  = NULL;
	PFILE_OBJECT        FileObject  = NULL;

	PDEVICE_OBJECT      DeviceObject  = NULL;

	PIRP                Irp  = NULL;
	PIO_STACK_LOCATION  IoStackLocation  = NULL;

	ULONG               Length;
	LARGE_INTEGER       ByteOffset;

	BOOLEAN             PagingIo;
	BOOLEAN             Nocache;
	BOOLEAN             SynchronousIo;
	BOOLEAN             MainResourceAcquired = FALSE;
	BOOLEAN             PagingIoResourceAcquired = FALSE;

	BOOLEAN             bDeferred = FALSE;

	PUCHAR              Buffer = NULL;

	__try
	{
		ASSERT(IrpContext);

		ASSERT((IrpContext->Identifier.Type == FFSICX) &&
				(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));

		DeviceObject = IrpContext->DeviceObject;

		Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;

		ASSERT(Vcb != NULL);

		ASSERT((Vcb->Identifier.Type == FFSVCB) &&
				(Vcb->Identifier.Size == sizeof(FFS_VCB)));

		FileObject = IrpContext->FileObject;

		FcbOrVcb = (PFFS_FCBVCB)FileObject->FsContext;

		ASSERT(FcbOrVcb);

		if (!(FcbOrVcb->Identifier.Type == FFSVCB && (PVOID)FcbOrVcb == (PVOID)Vcb))
		{
			Status = STATUS_INVALID_DEVICE_REQUEST;
			__leave;
		}

		Ccb = (PFFS_CCB)FileObject->FsContext2;

		Irp = IrpContext->Irp;

		IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

		Length = IoStackLocation->Parameters.Write.Length;
		ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;

		PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
		Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
		SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);

		FFSPrint((DBG_INFO, "FFSWriteVolume: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
					ByteOffset.QuadPart, Length, PagingIo, Nocache));

		if (Length == 0)
		{
			Irp->IoStatus.Information = 0;
			Status = STATUS_SUCCESS;
			__leave;
		}

		// For the case of "Direct Access Storage Device", we
		// need flush/purge the cache

		if (Ccb != NULL)
		{
			ExAcquireResourceExclusive(&Vcb->MainResource, TRUE);
			MainResourceAcquired = TRUE;

			Status = FFSPurgeVolume(Vcb, TRUE);

			ExReleaseResource(&Vcb->MainResource);
			MainResourceAcquired = FALSE;

			if(!IsFlagOn(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO))
			{
				if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart)
				{
					Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
				}
			}

			{
				FFS_BDL BlockArray;

				if ((ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
						(Length & (SECTOR_SIZE - 1)))
				{
					Status = STATUS_INVALID_PARAMETER;
					__leave;
				}

				Status = FFSLockUserBuffer(
							IrpContext->Irp,
							Length,
							IoReadAccess);

				if (!NT_SUCCESS(Status))
				{
					__leave;
				}

				BlockArray.Irp = NULL;
				BlockArray.Lba = ByteOffset.QuadPart;;
				BlockArray.Offset = 0;
				BlockArray.Length = Length;

				Status = FFSReadWriteBlocks(IrpContext,
							Vcb,
							&BlockArray,
							Length,
							1,
							FALSE);
				Irp = IrpContext->Irp;

				__leave;
			}
		}                    

		if (Nocache &&
				(ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
				 Length & (SECTOR_SIZE - 1)))
		{
			Status = STATUS_INVALID_PARAMETER;
			__leave;
		}

		if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC))
		{
			ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
			Status = STATUS_PENDING;
			__leave;
		}

		if (ByteOffset.QuadPart >=
				Vcb->PartitionInformation.PartitionLength.QuadPart)
		{
			Irp->IoStatus.Information = 0;
			Status = STATUS_END_OF_FILE;
			__leave;
		}

#if FALSE

		if (!Nocache)
		{
			BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
			BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
			BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);

			if (!CcCanIWrite(
						FileObject,
						Length,
						(bWait && bQueue),
						bAgain))
			{
				SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);

				CcDeferWrite(FileObject,
						(PCC_POST_DEFERRED_WRITE)FFSDeferWrite,
						IrpContext,
						Irp,
						Length,
						bAgain);

				bDeferred = TRUE;

				FFSBreakPoint();

				Status = STATUS_PENDING;

				__leave;
			}
		}

#endif

		if (Nocache && !PagingIo && (Vcb->SectionObject.DataSectionObject != NULL)) 
		{
			ExAcquireResourceExclusive(&Vcb->MainResource, TRUE);
			MainResourceAcquired = TRUE;

			ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
			ExReleaseResource(&Vcb->PagingIoResource);

			CcFlushCache(&(Vcb->SectionObject),
					&ByteOffset,
					Length,
					&(Irp->IoStatus));

			if (!NT_SUCCESS(Irp->IoStatus.Status)) 
			{
				Status = Irp->IoStatus.Status;
				__leave;
			}

			ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
			ExReleaseResource(&Vcb->PagingIoResource);

			CcPurgeCacheSection(&(Vcb->SectionObject),
					(PLARGE_INTEGER)&(ByteOffset),
					Length,
					FALSE);

			ExReleaseResource(&Vcb->MainResource);
			MainResourceAcquired = FALSE;
		}

		if (!PagingIo)
		{
			if (!ExAcquireResourceExclusiveLite(
						&Vcb->MainResource,
						IrpContext->IsSynchronous))
			{
				Status = STATUS_PENDING;
				__leave;
			}

			MainResourceAcquired = TRUE;
		}
		else
		{
			/*
			ULONG ResShCnt, ResExCnt; 
			ResShCnt = ExIsResourceAcquiredSharedLite(&Vcb->PagingIoResource);
			ResExCnt = ExIsResourceAcquiredExclusiveLite(&Vcb->PagingIoResource);

			FFSPrint((DBG_USER, "PagingIoRes: %xh:%xh Synchronous=%xh\n", ResShCnt, ResExCnt, IrpContext->IsSynchronous));
			*/

			if (Ccb)
			{
				if (!ExAcquireResourceSharedLite(
							&Vcb->PagingIoResource,
							IrpContext->IsSynchronous))
				{
					Status = STATUS_PENDING;
					__leave;
				}

				PagingIoResourceAcquired = TRUE;
			}
		}

		if (!Nocache)
		{
			if ((ByteOffset.QuadPart + Length) >
					Vcb->PartitionInformation.PartitionLength.QuadPart
			)
			{
				Length = (ULONG) (
						Vcb->PartitionInformation.PartitionLength.QuadPart -
						ByteOffset.QuadPart);

				Length &= ~((ULONG)SECTOR_SIZE - 1);
			}

			if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL))
			{

				CcPrepareMdlWrite(
						Vcb->StreamObj,
						&ByteOffset,
						Length,
						&Irp->MdlAddress,
						&Irp->IoStatus);

				Status = Irp->IoStatus.Status;
			}
			else
			{
				Buffer = FFSGetUserBuffer(Irp);

				if (Buffer == NULL)
				{
					FFSBreakPoint();

					Status = STATUS_INVALID_USER_BUFFER;
					__leave;
				}

				if (!CcCopyWrite(Vcb->StreamObj,
							(PLARGE_INTEGER)(&ByteOffset),
							Length,
							TRUE,
							Buffer))
				{
					Status = STATUS_PENDING;
					__leave;
				}

				Status = Irp->IoStatus.Status;
				FFSAddMcbEntry(Vcb, ByteOffset.QuadPart, (LONGLONG)Length);
			}

			if (NT_SUCCESS(Status))
			{
				Irp->IoStatus.Information = Length;
			}
		}
		else
		{
			PFFS_BDL            ffs_bdl = NULL;
			ULONG               Blocks = 0;

			LONGLONG            DirtyStart;
			LONGLONG            DirtyLba;
			LONGLONG            DirtyLength;
			LONGLONG            RemainLength;

			if ((ByteOffset.QuadPart + Length) >
					Vcb->PartitionInformation.PartitionLength.QuadPart)
			{
				Length = (ULONG)(
						Vcb->PartitionInformation.PartitionLength.QuadPart -
						ByteOffset.QuadPart);

				Length &= ~((ULONG)SECTOR_SIZE - 1);
			}

			Status = FFSLockUserBuffer(
					IrpContext->Irp,
					Length,
					IoReadAccess);

			if (!NT_SUCCESS(Status))
			{
				__leave;
			}

			ffs_bdl = ExAllocatePool(PagedPool, 
					(Length / Vcb->BlockSize) *
					sizeof(FFS_BDL));

			if (!ffs_bdl)
			{
				Status = STATUS_INSUFFICIENT_RESOURCES;
				__leave;
			}

			DirtyLba = ByteOffset.QuadPart;
			RemainLength = (LONGLONG)Length;

			while (RemainLength > 0)
			{
				DirtyStart = DirtyLba;

				if (FFSLookupMcbEntry(Vcb, 
							DirtyStart,
							&DirtyLba,
							&DirtyLength,
							(PLONGLONG)NULL,
							(PLONGLONG)NULL,
							(PULONG)NULL))
				{

					if (DirtyLba == -1)
					{
						DirtyLba = DirtyStart + DirtyLength;

						RemainLength = ByteOffset.QuadPart + 
							(LONGLONG)Length -
							DirtyLba;
						continue;
					}

					ffs_bdl[Blocks].Irp = NULL;
					ffs_bdl[Blocks].Lba = DirtyLba;
					ffs_bdl[Blocks].Offset = (ULONG)((LONGLONG)Length +
							DirtyStart -
							RemainLength - 
							DirtyLba);

					if (DirtyLba + DirtyLength > DirtyStart + RemainLength)
					{
						ffs_bdl[Blocks].Length = (ULONG)(DirtyStart +
								RemainLength -
								DirtyLba);
						RemainLength = 0;
					}
					else
					{
						ffs_bdl[Blocks].Length = (ULONG)DirtyLength;
						RemainLength =  (DirtyStart + RemainLength) -
							(DirtyLba + DirtyLength);
					}

					DirtyLba = DirtyStart + DirtyLength;
					Blocks++;
				}
				else
				{
					if (Blocks == 0)
					{
						if (ffs_bdl)
							ExFreePool(ffs_bdl);

						//
						// Lookup fails at the first time, ie. 
						// no dirty blocks in the run
						//

						FFSBreakPoint();

						if (RemainLength == (LONGLONG)Length)
							Status = STATUS_SUCCESS;
						else
							Status = STATUS_UNSUCCESSFUL;

						__leave;
					}
					else
					{
						break;
					}
				}
			}

			if (Blocks > 0)
			{
				Status = FFSReadWriteBlocks(IrpContext,
							Vcb,
							ffs_bdl,
							Length,
							Blocks,
							FALSE);
				Irp = IrpContext->Irp;

				if (NT_SUCCESS(Status))
				{
					ULONG   i;

					for (i = 0; i < Blocks; i++)
					{
						FFSRemoveMcbEntry(Vcb,
								ffs_bdl[i].Lba,
								ffs_bdl[i].Length);
					}
				}

				if (ffs_bdl)
					ExFreePool(ffs_bdl);

				if (!Irp)
					__leave;

			}
			else
			{
				if (ffs_bdl)
					ExFreePool(ffs_bdl);

				Irp->IoStatus.Information = Length;

				Status = STATUS_SUCCESS;
				__leave;
			}
		}
	}

	__finally
	{
		if (PagingIoResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Vcb->PagingIoResource,
					ExGetCurrentResourceThread());
		}

		if (MainResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Vcb->MainResource,
					ExGetCurrentResourceThread());
		}

		if (!IrpContext->ExceptionInProgress)
		{
			if (Irp)
			{
				if (Status == STATUS_PENDING)
				{
					if(!bDeferred)
					{
						Status = FFSLockUserBuffer(
								IrpContext->Irp,
								Length,
								IoReadAccess);

						if (NT_SUCCESS(Status))
						{
							Status = FFSQueueRequest(IrpContext);
						}
						else
						{
							FFSCompleteIrpContext(IrpContext, Status);
						}
					}
				}
				else
				{
					if (NT_SUCCESS(Status))
					{
						if (SynchronousIo && !PagingIo)
						{
							FileObject->CurrentByteOffset.QuadPart =
								ByteOffset.QuadPart + Irp->IoStatus.Information;
						}

						if (!PagingIo)
						{
							SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
						}
					}

					FFSCompleteIrpContext(IrpContext, Status);
				}
			}
			else
			{
				FFSFreeIrpContext(IrpContext);
			}
		}
	}

	return Status;
}
Ejemplo n.º 15
0
BOOLEAN
NtfsFastUnlockAllByKey (
    IN PFILE_OBJECT FileObject,
    PVOID ProcessId,
    ULONG Key,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This is a call back routine for doing the fast unlock all by key call.

Arguments:

    FileObject - Supplies the file object used in this operation

    ProcessId - Supplies the process ID used in this operation

    Key - Supplies the key used in this operation

    Status - Receives the Status if this operation is successful

Return Value:

    BOOLEAN - TRUE if this operation completed and FALSE if caller
        needs to take the long route.

--*/

{
    BOOLEAN Results;
    IRP_CONTEXT IrpContext;
    TYPE_OF_OPEN TypeOfOpen;
    PVCB Vcb;
    PFCB Fcb;
    PSCB Scb;
    PCCB Ccb;

    UNREFERENCED_PARAMETER( DeviceObject );

    PAGED_CODE();

    DebugTrace( +1, Dbg, ("NtfsFastUnlockAllByKey\n") );

    IoStatus->Information = 0;

    //
    //  Decode the type of file object we're being asked to process and
    //  make sure that is is only a user file open.
    //

    TypeOfOpen = NtfsDecodeFileObject( &IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );

    if (TypeOfOpen != UserFileOpen) {

        IoStatus->Status = STATUS_INVALID_PARAMETER;
        IoStatus->Information = 0;

        DebugTrace( -1, Dbg, ("NtfsFastUnlockAllByKey -> TRUE (STATUS_INVALID_PARAMETER)\n") );
        return TRUE;
    }

    //
    //  Acquire exclusive access to the Fcb this operation can always wait
    //

    FsRtlEnterFileSystem();

    if (Scb->ScbType.Data.FileLock == NULL) {

        (VOID) ExAcquireResourceExclusive( Fcb->Resource, TRUE );

    } else {

        (VOID) ExAcquireResourceShared( Fcb->Resource, TRUE );
    }

    try {

        //
        //  We check whether we can proceed based on the state of the file oplocks.
        //

        if (!FsRtlOplockIsFastIoPossible( &Scb->ScbType.Data.Oplock )) {

            try_return( Results = FALSE );
        }

        //
        //  If we don't have a file lock, then get one now.
        //

        if (Scb->ScbType.Data.FileLock == NULL
            && !NtfsCreateFileLock( Scb, FALSE )) {

            try_return( Results = FALSE );
        }

        //
        //  Now call the FsRtl routine to do the actual processing of the
        //  Lock request.  The call will always succeed.
        //

        Results = TRUE;
        IoStatus->Status = FsRtlFastUnlockAllByKey( Scb->ScbType.Data.FileLock,
                                                    FileObject,
                                                    ProcessId,
                                                    Key,
                                                    NULL );

        //
        //  Set the flag indicating if Fast I/O is possible
        //

        NtfsAcquireFsrtlHeader( Scb );
        Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
        NtfsReleaseFsrtlHeader( Scb );

    try_exit:  NOTHING;
    } finally {

        DebugUnwind( NtfsFastUnlockAllByKey );

        //
        //  Release the Fcb, and return to our caller
        //

        ExReleaseResource( Fcb->Resource );

        FsRtlExitFileSystem();

        DebugTrace( -1, Dbg, ("NtfsFastUnlockAllByKey -> %08lx\n", Results) );
    }

    return Results;
}
Ejemplo n.º 16
0
NTSTATUS
NtAllocateUuids (
    OUT PULARGE_INTEGER Time,
    OUT PULONG Range,
    OUT PULONG Sequence
    )

/*++

Routine Description:

    This function reserves a range of time for the caller(s) to use for 
    handing out Uuids.  As far a possible the same range of time and 
    sequence number will never be given out.  

    (It's possible to reboot 2^14-1 times and set the clock backwards and then 
    call this allocator and get a duplicate.  Since only the low 14bits of the 
    sequence number are used in a real uuid.) 

Arguments:

    Time - Supplies the address of a variable that will receive the
        start time (SYSTEMTIME format) of the range of time reserved.

    Range - Supplies the address of a variable that will receive the
        number of ticks (100ns) reserved after the value in Time.
        The range reserved is *Time to (*Time + *Range - 1).

    Sequence - Supplies the address of a variable that will receive
        the time sequence number.  This value is used with the associated
        range of time to prevent problems with clocks going backwards.

Return Value:

    STATUS_SUCCESS is returned if the service is successfully executed.

    STATUS_RETRY is returned if we're unable to reserve a range of
        UUIDs.  This may (?) occur if system clock hasn't advanced
        and the allocator is out of cached values.

    STATUS_ACCESS_VIOLATION is returned if the output parameter for the
        UUID cannot be written.

    STATUS_UNSUCCESSFUL is returned if some other service reports
        an error, most likly the registery.

--*/

{

    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;
    LARGE_INTEGER CurrentTime;
    LARGE_INTEGER AvailableTime;
    LARGE_INTEGER OutputTime;
    ULONG OutputRange;
    ULONG OutputSequence;

    PAGED_CODE();

    //
    // Establish an exception handler and attempt to write the output
    // arguments. If the write attempt fails, then return
    // the exception code as the service status. Otherwise return success
    // as the service status.
    //

    try {

        //
        // Get previous processor mode and probe arguments if necessary.
        //

        PreviousMode = KeGetPreviousMode();
        if (PreviousMode != KernelMode) {
            ProbeForWrite((PVOID)Time, sizeof(LARGE_INTEGER), sizeof(ULONG));
            ProbeForWrite((PVOID)Range, sizeof(ULONG), sizeof(ULONG));
            ProbeForWrite((PVOID)Sequence, sizeof(ULONG), sizeof(ULONG));
            }
        }
    except (ExSystemExceptionFilter())
        {
        return GetExceptionCode();
        }

    ExAcquireResourceExclusive(&ExpUuidLock, TRUE);

    //
    // Make sure we have a valid sequence number.  If not, make one up.
    //

    if (ExpUuidSequenceNumberValid == FALSE) {
        Status = ExpUuidLoadSequenceNumber(&ExpUuidSequenceNumber);

        if (!NT_SUCCESS(Status)) {
            // Unable read the sequence number, this means we should make one up.

            LARGE_INTEGER PerfCounter;
            LARGE_INTEGER PerfFrequency;

            // This should only happen when NtAllocateUuids() is called
            // for the first time on a given machine. (machine, not boot)

            KdPrint(("Uuid: Generating first sequence number.\n"));

            PerfCounter = KeQueryPerformanceCounter(&PerfFrequency);

            ExpUuidSequenceNumber ^= (ULONG)&Status ^ PerfCounter.LowPart ^
                PerfCounter.HighPart ^ (ULONG)Sequence;
            }
        else {
            // We increment the sequence number on every boot.
            ExpUuidSequenceNumber++;
            }

        ExpUuidSequenceNumberValid = TRUE;
        ExpUuidSequenceNumberNotSaved = TRUE;
        }

    //
    // Get the current time, usually we will have plenty of avaliable
    // to give the caller.  But we may need to deal with time going
    // backwards and really fast machines.
    //

    KeQuerySystemTime(&CurrentTime);

    AvailableTime.QuadPart = CurrentTime.QuadPart - ExpUuidLastTimeAllocated.QuadPart;

    if (AvailableTime.QuadPart < 0) {
            
        // Time has been set time backwards. This means that we must make sure
        // that somebody increments the sequence number and saves the new
        // sequence number in the registry.

        ExpUuidSequenceNumberNotSaved = TRUE;
        ExpUuidSequenceNumber++;

        // The sequence number has been changed, so it's now okay to set time
        // backwards.  Since time is going backwards anyway, it's okay to set
        // it back an extra millisecond or two.

        ExpUuidLastTimeAllocated.QuadPart = CurrentTime.QuadPart - 20000;
        AvailableTime.QuadPart = 20000;
        }

    if (AvailableTime.QuadPart == 0) {
        // System time hasn't moved.  The caller should yield the CPU and retry.
        ExReleaseResource(&ExpUuidLock);
        return(STATUS_RETRY);
        }

    //
    // Common case, time has moved forward.
    //

    if (AvailableTime.QuadPart > 10*1000*1000) {
        // We never want to give out really old (> 1 second) Uuids.
        AvailableTime.QuadPart = 10*1000*1000;
        }

    if (AvailableTime.QuadPart > 10000) {
        // We've got over a millisecond to give out.  We'll save some time for
        // another caller so that we can avoid returning STATUS_RETRY very offen.
        OutputRange = 10000;
        AvailableTime.QuadPart -= 10000;
        }
    else {
        // Not much time avaiable, give it all away.
        OutputRange = (ULONG)AvailableTime.QuadPart;
        AvailableTime.QuadPart = 0;
        }

    OutputTime.QuadPart = CurrentTime.QuadPart - (OutputRange + AvailableTime.QuadPart);

    ExpUuidLastTimeAllocated.QuadPart = OutputTime.QuadPart + OutputRange;

    // Last time allocated is just after the range we hand back to the caller
    // this may be almost a second behind the true system time.

    OutputSequence = ExpUuidSequenceNumber;

    ExReleaseResource(&ExpUuidLock);

    // Saving the sequence number will usually complete without any problems.
    // So we let any other threads go at this point. If the save fails,
    // we'll retry on some future call.

    if (ExpUuidSequenceNumberNotSaved == TRUE) {
        if (ExAcquireResourceExclusive(&ExpSequenceLock, FALSE) == TRUE) {
            if (ExpUuidSequenceNumberNotSaved == TRUE) {

                ExpUuidSequenceNumberNotSaved = FALSE;

                // Print this message just to make sure we aren't hitting the
                // registry too much under normal usage.

                KdPrint(("Uuid: Saving new sequence number.\n"));

                Status = ExpUuidSaveSequenceNumber(ExpUuidSequenceNumber);

                if (!NT_SUCCESS(Status)) {
                    ExpUuidSequenceNumberNotSaved = TRUE;
                    }
                }
            }
        ExReleaseResource(&ExpSequenceLock);
        }

    //
    // Attempt to store the result of this call into the output parameters.
    // This is done within an exception handler in case output parameters
    // are now invalid.
    //

    try {
        Time->QuadPart = OutputTime.QuadPart;
        *Range = OutputRange;
        *Sequence = OutputSequence;
    }
    except (ExSystemExceptionFilter()) {
        return GetExceptionCode();
        }

    return(STATUS_SUCCESS);
}
Ejemplo n.º 17
0
//+----------------------------------------------------------------------
//
// Function:    DfsAgePktEntries, public
//
// Synopsis:    This function gets called in the FSP to step through the PKT
//              entries and delete those entries which are old.
//
// Arguments:   [TimerContext] -- This context block contains a busy flag
//                                and a count of the number of ticks that
//                                have elapsed.
//
// Returns:     Nothing.
//
// Notes:       In case the PKT cannot be acquired exclusive, the
//              routine just returns without doing anything.  We
//              will have missed an aging interval, but aging is
//              a non-critical activity.
//
// History:     04/23/93        SudK    Created.
//
//-----------------------------------------------------------------------
VOID
DfsAgePktEntries(PDFS_TIMER_CONTEXT     DfsTimerContext)
{

    PDFS_PKT            pkt = _GetPkt();
    PDFS_PKT_ENTRY      entry, nextEntry;
    PLIST_ENTRY         link;
    PDFS_CREDENTIALS    creds;
    BOOLEAN             pktLocked = FALSE;

    DfsDbgTrace(+1, Dbg, "DfsAgePktEntries called\n", 0);

    //
    // First we need to acquire a lock on the PKT and step through the PKT
    //
    //

    // If we can't get to the resource then let us return right away.
    // This is really not that critical.  We can always try again.
    //

    PktAcquireExclusive(FALSE, &pktLocked);

    if (pktLocked == FALSE) {

        DfsTimerContext->TickCount = 0;

        DfsTimerContext->InUse = FALSE;

        DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan)\n", 0);

        return;

    }

    if (ExAcquireResourceExclusive(&DfsData.Resource, FALSE) == FALSE) {

        PktRelease();

        DfsTimerContext->TickCount = 0;

        DfsTimerContext->InUse = FALSE;

        DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan 2)\n", 0);

        return;

    }

    entry = PktFirstEntry(pkt);

    while (entry != NULL)       {
        DfsDbgTrace(0, Dbg, "DfsAgePktEntries: Scanning %wZ\n",
                                        &entry->Id.Prefix);
        //
        // We may lose this entry due to deletion. Let us get the Next
        // entry before we go into the next stage.
        //
        nextEntry = PktNextEntry(pkt, entry);

        //
        // For each entry if it is not permanent and its expire time is
        // less than DFS_MAX_TICKS then we can delete it else we just
        // update its expire time and go on to the next entry.
        //

        if ( !(entry->Type & PKT_ENTRY_TYPE_PERMANENT)

                   &&

              (entry->UseCount == 0)

                   &&

              IsListEmpty(&entry->ChildList)) {

            if (entry->ExpireTime < DfsTimerContext->TickCount) {
                DfsDbgTrace(0, Dbg, "DfsAgePktEntries: Deleted: %wZ\n",
                                                &entry->Id.Prefix);
                PktEntryDestroy(entry, pkt, (BOOLEAN) TRUE);
            } else {
                entry->ExpireTime -= DfsTimerContext->TickCount;
            }

        }

        entry = nextEntry;

    }

    //
    // Check the deleted credentials queue...
    //

    for (link = DfsData.DeletedCredentials.Flink;
            link != &DfsData.DeletedCredentials;
                NOTHING) {

         creds = CONTAINING_RECORD(link, DFS_CREDENTIALS, Link);

         link = link->Flink;

         if (creds->RefCount == 0) {

             RemoveEntryList( &creds->Link );

             ExFreePool( creds );

         }

    }


    ExReleaseResource( &DfsData.Resource );

    PktRelease();

    //
    // Finally we need to reset the count so that the Timer Routine can
    // work fine.  We also release the context block by resetting the InUse
    // boolean.  This will make sure that the next count towards the PKT
    // aging will start again.
    //

    DfsTimerContext->TickCount = 0;

    DfsTimerContext->InUse = FALSE;

    DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit\n", 0);
}
Ejemplo n.º 18
0
VOID
NtfsAcquireAllFiles (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN BOOLEAN Exclusive,
    IN BOOLEAN AcquirePagingIo
    )

/*++

Routine Description:

    This routine non-recursively requires all files on a volume.

Arguments:

    Vcb - Supplies the volume

    Exclusive - Indicates if we should be acquiring all the files exclusively.
        If FALSE then we acquire all the files shared except for files with
        streams which could be part of transactions.

    AcquirePagingIo - Indicates if we need to acquire the paging io resource
        exclusively.  Only needed if a future call will flush the volume
        (i.e. shutdown)

Return Value:

    None

--*/

{
    PFCB Fcb;
    PSCB *Scb;
    PSCB NextScb;
    PVOID RestartKey;

    PAGED_CODE();

    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );

    NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );

    RestartKey = NULL;
    while (TRUE) {

        NtfsAcquireFcbTable( IrpContext, Vcb );
        Fcb = NtfsGetNextFcbTableEntry(Vcb, &RestartKey);
        NtfsReleaseFcbTable( IrpContext, Vcb );

        if (Fcb == NULL) {

            break;
        }

        ASSERT_FCB( Fcb );

        //
        //  We can skip over the Fcb's for any of the Scb's in the Vcb.
        //  We delay acquiring those to avoid deadlocks.
        //

        if (NtfsSegmentNumber( &Fcb->FileReference ) >= FIRST_USER_FILE_NUMBER) {

            //
            //  If there is a paging Io resource then acquire this if required.
            //

            if (AcquirePagingIo && (Fcb->PagingIoResource != NULL)) {

                ExAcquireResourceExclusive( Fcb->PagingIoResource, TRUE );
            }

            //
            //  Acquire this Fcb whether or not the underlying file has been deleted.
            //

            if (Exclusive ||
                IsDirectory( &Fcb->Info )) {

                NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, TRUE, FALSE );

            } else {

                //
                //  Assume that we only need this file shared.  We will then
                //  look for Lsn related streams.
                //

                NtfsAcquireSharedFcb( IrpContext, Fcb, NULL, TRUE );

                //
                //  Walk through all of the Scb's for the file and look for
                //  an Lsn protected stream.
                //

                NtfsLockFcb( IrpContext, Fcb );

                NextScb = NULL;

                while (NextScb = NtfsGetNextChildScb( Fcb, NextScb )) {

                    if (!(NextScb->AttributeTypeCode == $DATA ||
                          NextScb->AttributeTypeCode == $EA)) {

                        break;
                    }
                }

                NtfsUnlockFcb( IrpContext, Fcb );

                //
                //  If we found a protected Scb then release and reacquire the Fcb
                //  exclusively.
                //

                if (NextScb != NULL) {

                    NtfsReleaseFcb( IrpContext, Fcb );
                    NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, TRUE, FALSE );
                }
            }
        }
    }

    //
    //  Now acquire the Fcb's in the Vcb.
    //

    Scb = &Vcb->QuotaTableScb;

    while (TRUE) {

        if ((*Scb != NULL)
            && (*Scb != Vcb->BitmapScb)) {

            if (AcquirePagingIo && ((*Scb)->Fcb->PagingIoResource != NULL)) {

                ExAcquireResourceExclusive( (*Scb)->Fcb->PagingIoResource, TRUE );
            }

            NtfsAcquireExclusiveFcb( IrpContext, (*Scb)->Fcb, NULL, TRUE, FALSE );
        }

        if (Scb == &Vcb->MftScb) {

            break;
        }

        Scb -= 1;
    }

    //
    //  Treat the bitmap as an end resource and acquire it last.
    //

    if (Vcb->BitmapScb != NULL) {

        if (AcquirePagingIo && (Vcb->BitmapScb->Fcb->PagingIoResource != NULL)) {

            ExAcquireResourceExclusive( Vcb->BitmapScb->Fcb->PagingIoResource, TRUE );
        }

        NtfsAcquireExclusiveFcb( IrpContext, Vcb->BitmapScb->Fcb, NULL, TRUE, FALSE );
    }

    return;
}
Ejemplo n.º 19
0
VOID
NtfsAcquireSharedScbForTransaction (
    IN PIRP_CONTEXT IrpContext,
    IN PSCB Scb
    )

/*++

Routine Description:

    This routine is called to acquire an Scb shared in order to perform updates to
    the an Scb stream.  This is used if the transaction writes to a range of the
    stream without changing the size or position of the data.  The caller must
    already provide synchronization to the data itself.

    There is no corresponding Scb release.  It will be released when the transaction commits.
    We will acquire the Scb exclusive if it is not yet in the open attribute table.

Arguments:

    Scb - Scb to acquire

Return Value:

    None.

--*/

{
    PSCB *Position;
    PSCB *ScbArray;
    ULONG Count;

    PAGED_CODE();

    //
    //  Make sure we have a free spot in the Scb array in the IrpContext.
    //

    if (IrpContext->SharedScb == NULL) {

        Position = (PSCB *) &IrpContext->SharedScb;
        IrpContext->SharedScbSize = 1;

    //
    //  Too bad the first one is not available.  If the current size is one then allocate a
    //  new block and copy the existing value to it.
    //

    } else if (IrpContext->SharedScbSize == 1) {

        ScbArray = NtfsAllocatePool( PagedPool, sizeof( PSCB ) * 4 );
        RtlZeroMemory( ScbArray, sizeof( PSCB ) * 4 );
        *ScbArray = IrpContext->SharedScb;
        IrpContext->SharedScb = ScbArray;
        IrpContext->SharedScbSize = 4;
        Position = ScbArray + 1;

    //
    //  Otherwise look through the existing array and look for a free spot.  Allocate a larger
    //  array if we need to grow it.
    //

    } else {

        Position = IrpContext->SharedScb;
        Count = IrpContext->SharedScbSize;

        do {

            if (*Position == NULL) {

                break;
            }

            Count -= 1;
            Position += 1;

        } while (Count != 0);

        //
        //  If we didn't find one then allocate a new structure.
        //

        if (Count == 0) {

            ScbArray = NtfsAllocatePool( PagedPool, sizeof( PSCB ) * IrpContext->SharedScbSize * 2 );
            RtlZeroMemory( ScbArray, sizeof( PSCB ) * IrpContext->SharedScbSize * 2 );
            RtlCopyMemory( ScbArray,
                           IrpContext->SharedScb,
                           sizeof( PSCB ) * IrpContext->SharedScbSize );

            NtfsFreePool( IrpContext->SharedScb );
            IrpContext->SharedScb = ScbArray;
            Position = ScbArray + IrpContext->SharedScbSize;
            IrpContext->SharedScbSize *= 2;
        }
    }

    ExAcquireResourceShared( Scb->Header.Resource, TRUE );

    if (Scb->NonpagedScb->OpenAttributeTableIndex == 0) {

        ExReleaseResource( Scb->Header.Resource );
        ExAcquireResourceExclusive( Scb->Header.Resource, TRUE );
    }

    *Position = Scb;

    return;
}
Ejemplo n.º 20
0
NTSTATUS
FatCommonRead (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
)

/*++

Routine Description:

    This is the common read routine for NtReadFile, called from both
    the Fsd, or from the Fsp if a request could not be completed without
    blocking in the Fsd.  This routine has no code where it determines
    whether it is running in the Fsd or Fsp.  Instead, its actions are
    conditionalized by the Wait input parameter, which determines whether
    it is allowed to block or not.  If a blocking condition is encountered
    with Wait == FALSE, however, the request is posted to the Fsp, who
    always calls with WAIT == TRUE.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    PVCB Vcb;
    PFCB FcbOrDcb;
    PCCB Ccb;

    VBO StartingVbo;
    ULONG ByteCount;
    ULONG RequestedByteCount;

    PIO_STACK_LOCATION IrpSp;
    PFILE_OBJECT FileObject;
    TYPE_OF_OPEN TypeOfRead;

    BOOLEAN PostIrp = FALSE;
    BOOLEAN OplockPostIrp = FALSE;

    BOOLEAN FcbOrDcbAcquired = FALSE;

    BOOLEAN Wait;
    BOOLEAN PagingIo;
    BOOLEAN NonCachedIo;
    BOOLEAN SynchronousIo;

    NTSTATUS Status;

    FAT_IO_CONTEXT StackFatIoContext;

    //
    // A system buffer is only used if we have to access the
    // buffer directly from the Fsp to clear a portion or to
    // do a synchronous I/O, or a cached transfer.  It is
    // possible that our caller may have already mapped a
    // system buffer, in which case we must remember this so
    // we do not unmap it on the way out.
    //

    PVOID SystemBuffer = NULL;

    LARGE_INTEGER StartingByte;

    //
    // Get current Irp stack location.
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );
    FileObject = IrpSp->FileObject;

    //
    // Initialize the appropriate local variables.
    //

    Wait          = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
    PagingIo      = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
    NonCachedIo   = BooleanFlagOn(Irp->Flags,IRP_NOCACHE);
    SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);

    DebugTrace(+1, Dbg, "CommonRead\n", 0);
    DebugTrace( 0, Dbg, "  Irp                   = %8lx\n", Irp);
    DebugTrace( 0, Dbg, "  ->ByteCount           = %8lx\n", IrpSp->Parameters.Read.Length);
    DebugTrace( 0, Dbg, "  ->ByteOffset.LowPart  = %8lx\n", IrpSp->Parameters.Read.ByteOffset.LowPart);
    DebugTrace( 0, Dbg, "  ->ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.HighPart);

    //
    //  Extract starting Vbo and offset.
    //

    StartingByte = IrpSp->Parameters.Read.ByteOffset;

    StartingVbo = StartingByte.LowPart;

    ByteCount = IrpSp->Parameters.Read.Length;
    RequestedByteCount = ByteCount;

    //
    //  Check for a null request, and return immediately
    //

    if (ByteCount == 0) {

        Irp->IoStatus.Information = 0;
        FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
        return STATUS_SUCCESS;
    }

    //
    //  Check for a non-zero high part offset
    //

    if ( StartingByte.HighPart != 0 ) {

        Irp->IoStatus.Information = 0;
        FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE );
        return STATUS_END_OF_FILE;
    }

    //
    // Extract the nature of the read from the file object, and case on it
    //

    TypeOfRead = FatDecodeFileObject(FileObject, &Vcb, &FcbOrDcb, &Ccb);

    //
    // Collect interesting statistics.  The FLAG_USER_IO bit will indicate
    // what type of io we're doing in the FatNonCachedIo function.
    //

    if (PagingIo) {
        CollectReadStats(Vcb, TypeOfRead, ByteCount);

        if (TypeOfRead == UserFileOpen) {
            SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
        } else {
            ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
        }
    }

    //
    //  If there is a previous STACK FatIoContext pointer, NULL it.
    //

    if ((IrpContext->FatIoContext != NULL) &&
            FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) {

        IrpContext->FatIoContext = NULL;
    }

    //
    //  Allocate if necessary and initialize a FAT_IO_CONTEXT block for
    //  all non cached Io, except Cvf file Io.  For synchronous Io
    //  we use stack storage, otherwise we allocate pool.
    //

    if (NonCachedIo &&
            !(FcbOrDcb && FlagOn(FcbOrDcb->FcbState,
                                 FCB_STATE_COMPRESSED_VOLUME_FILE))) {

        if (IrpContext->FatIoContext == NULL) {

            if (!Wait) {

                IrpContext->FatIoContext =
                    FsRtlAllocatePool( NonPagedPool, sizeof(FAT_IO_CONTEXT) );

            } else {

                IrpContext->FatIoContext = &StackFatIoContext;

                SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT );
            }
        }

        RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );

        if (Wait) {

            KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
                               NotificationEvent,
                               FALSE );

        } else {

            IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
                ExGetCurrentResourceThread();

            IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
                ByteCount;

            IrpContext->FatIoContext->Wait.Async.FileObject = FileObject;
        }
    }

    
    //
    // These two cases correspond to either a general opened volume, ie.
    // open ("a:"), or a read of the volume file (boot sector + fat(s))
    //

    if ((TypeOfRead == VirtualVolumeFile) ||
            (TypeOfRead == UserVolumeOpen)) {

        DebugTrace(0, Dbg, "Type of read is User Volume or virtual volume file\n", 0);

        if (TypeOfRead == UserVolumeOpen) {

            //
            //  Verify that the volume for this handle is still valid
            //

            FatQuickVerifyVcb( IrpContext, Vcb );

            if (!FlagOn( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE )) {

                (VOID)ExAcquireResourceExclusive( &Vcb->Resource, TRUE );

                try {

                    //
                    //  If the volume isn't locked, flush it.
                    //

                    if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {

                        FatFlushVolume( IrpContext, Vcb );
                    }

                }
                finally {

                    ExReleaseResource( &Vcb->Resource );
                }

                SetFlag( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE );
            }
Ejemplo n.º 21
0
BOOLEAN
NtfsFastUnlockSingle (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER FileOffset,
    IN PLARGE_INTEGER Length,
    PEPROCESS ProcessId,
    ULONG Key,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This is a call back routine for doing the fast unlock single call.

Arguments:

    FileObject - Supplies the file object used in this operation

    FileOffset - Supplies the file offset used in this operation

    Length - Supplies the length used in this operation

    ProcessId - Supplies the process ID used in this operation

    Key - Supplies the key used in this operation

    Status - Receives the Status if this operation is successful

Return Value:

    BOOLEAN - TRUE if this operation completed and FALSE if caller
        needs to take the long route.

--*/

{
    BOOLEAN Results;
    PFCB Fcb;
    PSCB Scb;
    BOOLEAN ResourceAcquired = FALSE;

    UNREFERENCED_PARAMETER( DeviceObject );

    PAGED_CODE();

    DebugTrace( +1, Dbg, ("NtfsFastUnlockSingle\n") );

    IoStatus->Information = 0;

    //
    //  Decode the type of file object we're being asked to process and
    //  make sure that is is only a user file open.
    //

    if ((Scb = NtfsFastDecodeUserFileOpen( FileObject )) == NULL) {

        IoStatus->Status = STATUS_INVALID_PARAMETER;

        DebugTrace( -1, Dbg, ("NtfsFastUnlockSingle -> TRUE (STATUS_INVALID_PARAMETER)\n") );
        return TRUE;
    }

    Fcb = Scb->Fcb;

    //
    //  Acquire exclusive access to the Fcb this operation can always wait
    //

    FsRtlEnterFileSystem();

    if (Scb->ScbType.Data.FileLock == NULL) {

        (VOID) ExAcquireResourceExclusive( Fcb->Resource, TRUE );
        ResourceAcquired = TRUE;

    } else {

        //(VOID) ExAcquireResourceShared( Fcb->Resource, TRUE );
    }

    try {

        //
        //  We check whether we can proceed based on the state of the file oplocks.
        //

        if ((Scb->ScbType.Data.Oplock != NULL) &&
            !FsRtlOplockIsFastIoPossible( &Scb->ScbType.Data.Oplock )) {

            try_return( Results = FALSE );
        }

        //
        //  If we don't have a file lock, then get one now.
        //

        if (Scb->ScbType.Data.FileLock == NULL
            && !NtfsCreateFileLock( Scb, FALSE )) {

            try_return( Results = FALSE );
        }

        //
        //  Now call the FsRtl routine to do the actual processing of the
        //  Lock request.  The call will always succeed.
        //

        Results = TRUE;
        IoStatus->Status = FsRtlFastUnlockSingle( Scb->ScbType.Data.FileLock,
                                                  FileObject,
                                                  FileOffset,
                                                  Length,
                                                  ProcessId,
                                                  Key,
                                                  NULL,
                                                  FALSE );

        //
        //  Set the flag indicating if Fast I/O is possible.  We are
        //  only concerned if there are no longer any filelocks on this
        //  file.
        //

        if (!FsRtlAreThereCurrentFileLocks( Scb->ScbType.Data.FileLock ) &&
            (Scb->Header.IsFastIoPossible != FastIoIsPossible)) {

            NtfsAcquireFsrtlHeader( Scb );
            Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
            NtfsReleaseFsrtlHeader( Scb );
        }

    try_exit:  NOTHING;
    } finally {

        DebugUnwind( NtfsFastUnlockSingle );

        //
        //  Release the Fcb, and return to our caller
        //

        if (ResourceAcquired) {
            ExReleaseResource( Fcb->Resource );
        }

        FsRtlExitFileSystem();

        DebugTrace( -1, Dbg, ("NtfsFastUnlockSingle -> %08lx\n", Results) );
    }

    return Results;
}
Ejemplo n.º 22
0
VOID
NtfsReleaseVcbCheckDelete (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN UCHAR MajorCode,
    IN PFILE_OBJECT FileObject OPTIONAL
    )

/*++

Routine Description:

    This routine will release the Vcb.  We will also test here whether we should
    teardown the Vcb at this point.  If this is the last open queued to a dismounted
    volume or the last close from a failed mount or the failed mount then we will
    want to test the Vcb for a teardown.

Arguments:

    Vcb - Supplies the Vcb to acquire

    MajorCode - Indicates what type of operation we were called from.

    FileObject - Optionally supplies the file object whose VPB pointer we need to
        zero out

Return Value:

    None.

--*/

{
    ASSERT_IRP_CONTEXT(IrpContext);
    ASSERT_VCB(Vcb);

    if (FlagOn( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT ) &&
        (Vcb->CloseCount == 0)) {

        ULONG ReferenceCount;
        ULONG ResidualCount;

        KIRQL SavedIrql;
        BOOLEAN DeleteVcb = FALSE;

        ASSERT_EXCLUSIVE_RESOURCE( &Vcb->Resource );

        //
        //  The volume has gone through dismount.  Now we need to decide if this
        //  release of the Vcb is the last reference for this volume.  If so we
        //  can tear the volume down.
        //
        //  We compare the reference count in the Vpb with the state of the volume
        //  and the type of operation.  We also need to check if there is a
        //  referenced log file object.
        //

        IoAcquireVpbSpinLock( &SavedIrql );

        ReferenceCount = Vcb->Vpb->ReferenceCount;

        IoReleaseVpbSpinLock( SavedIrql );

        ResidualCount = 0;

        if (Vcb->LogFileObject != NULL) {

            ResidualCount = 1;
        }

        if (MajorCode == IRP_MJ_CREATE) {

            ResidualCount += 1;
        }

        //
        //  If the residual count is the same as the count in the Vpb then we
        //  can delete the Vpb.
        //

        if (ResidualCount == ReferenceCount) {

            SetFlag( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY );

            ExReleaseResource( &Vcb->Resource );

            //
            //  Never delete the Vcb unless this is the last release of
            //  this Vcb.
            //

            if (!ExIsResourceAcquiredExclusive( &Vcb->Resource ) &&
                (ExIsResourceAcquiredShared( &Vcb->Resource ) == 0)) {

                if (ARGUMENT_PRESENT(FileObject)) { FileObject->Vpb = NULL; }

                //
                //  If this is a create then the IO system will handle the
                //  Vpb.
                //

                if (MajorCode == IRP_MJ_CREATE) {

                    ClearFlag( Vcb->VcbState, VCB_STATE_TEMP_VPB );
                }

                //
                //  Use the global resource to synchronize the DeleteVcb process.
                //

                (VOID) ExAcquireResourceExclusive( &NtfsData.Resource, TRUE );

                RemoveEntryList( &Vcb->VcbLinks );

                ExReleaseResource( &NtfsData.Resource );

                NtfsDeleteVcb( IrpContext, &Vcb );

            } else {

                ClearFlag( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY );
            }

        } else {

            ExReleaseResource( &Vcb->Resource );
        }

    } else {

        ExReleaseResource( &Vcb->Resource );
    }
}
Ejemplo n.º 23
0
BOOLEAN
PiInitPhase1(
    VOID
    )

/*++

Routine Description:

    This function performs Phase 1 initializaion of the Plug and Play Manager
    component of the NT system. It performs the following tasks:

    (1) performs initialization of value entries under all subkeys of
        HKLM\System\Enum (e.g., resetting 'FoundAtEnum' to FALSE).
    (2) initializes bus enumerator structures for all built-in bus extenders
        provided by the HAL.
    (3) builds up a list of all installed bus extenders.


Arguments:

    None.

Return Value:

    TRUE  - Initialization succeeded.

    FALSE - Initialization failed.

--*/

{
#if _PNP_POWER_
    NTSTATUS Status;
#endif

    PiScratchBuffer = ExAllocatePool(PagedPool, PNP_LARGE_SCRATCH_BUFFER_SIZE);
    if(!PiScratchBuffer) {
        return FALSE;
    }

    //
    // Since we'll be writing to PnP device sections in the registry, acquire
    // the PnP device registry resource for exclusive access. We'll also be
    // initializing the bus enumerator list, so we need exclusive access to
    // the PnP bus enumerator list as well.
    //
    KeEnterCriticalRegion();

#if _PNP_POWER_
    ExAcquireResourceExclusive(&PpBusResource, TRUE);
#endif // _PNP_POWER_

    ExAcquireResourceExclusive(&PpRegistryDeviceResource, TRUE);

    //
    // Initialize all 'FoundAtEnum' value entries in the HKLM\System\Enum tree
    // to FALSE.
    //
    PiInitializeSystemEnum();

#if _PNP_POWER_
    //
    // Initialize our bus enumerator list with all bus instances under the control
    // of the HAL's built-in bus extenders.
    //
    Status = PiRegisterBuiltInBuses();

    if(!NT_SUCCESS(Status)) {
#if DBG
        DbgPrint("PiInitPhase1: Couldn't register built-in buses\n");
#endif
        return FALSE;
    }

    //
    // Enumerate all services in the registry, building up a list of all
    // installed bus extenders.
    //
    Status = IopApplyFunctionToSubKeys(NULL,
                                       &CmRegistryMachineSystemCurrentControlSetServices,
                                       KEY_READ,
                                       TRUE,
                                       PiAddPlugPlayBusEnumeratorToList,
                                       NULL
                                      );
    if(!NT_SUCCESS(Status)) {
#if DBG
        DbgPrint("PiInitPhase1: Couldn't build bus enumerator list\n");
#endif
        return FALSE;
    }
#endif // _PNP_POWER_

    ExReleaseResource(&PpRegistryDeviceResource);

#if _PNP_POWER_
    ExReleaseResource(&PpBusResource);
#endif // _PNP_POWER_

    KeLeaveCriticalRegion();

    ExFreePool(PiScratchBuffer);

    return TRUE;
}
Ejemplo n.º 24
0
BOOLEAN
NtfsAcquireFcbWithPaging (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN BOOLEAN DontWait
    )

/*++

Routine Description:

    This routine is used in the create path only.  It acquires the Fcb
    and also the paging IO resource if it exists but only if the create
    operation was doing a supersede/overwrite operation.

    This routine will raise if it cannot acquire the resource and wait
    in the IrpContext is false.

Arguments:

    Fcb - Supplies the Fcb to acquire

    DontWait - If TRUE this overrides the wait value in the IrpContext.
        We won't wait for the resource and return whether the resource
        was acquired.

Return Value:

    BOOLEAN - TRUE if acquired.  FALSE otherwise.

--*/

{
    BOOLEAN Status = FALSE;
    BOOLEAN Wait = FALSE;
    BOOLEAN PagingIoAcquired = FALSE;

    ASSERT_IRP_CONTEXT(IrpContext);
    ASSERT_FCB(Fcb);

    PAGED_CODE();

    //
    //  Sanity check that this is create.  The supersede flag is only
    //  set in the create path and only tested here.
    //

    ASSERT( IrpContext->MajorFunction == IRP_MJ_CREATE );

    if (!DontWait && FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {

        Wait = TRUE;
    }

    //
    //  Free any exclusive paging I/O resource, we currently have, which
    //  must presumably be from a directory with a paging I/O resource.
    //
    //  We defer releasing the paging io resource when we have logged
    //  changes against a stream.  The only transaction that should be
    //  underway at this point is the create file case where we allocated
    //  a file record.  In this case it is OK to release the paging io
    //  resource for the parent.
    //

    if (IrpContext->FcbWithPagingExclusive != NULL) {
        //  ASSERT(IrpContext->TransactionId == 0);
        NtfsReleasePagingIo( IrpContext, IrpContext->FcbWithPagingExclusive );
    }

    //
    //  Loop until we get it right - worst case is twice through loop.
    //

    while (TRUE) {

        //
        //  Acquire Paging I/O first.  Testing for the PagingIoResource
        //  is not really safe without holding the main resource, so we
        //  correct for that below.
        //

        if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) &&
            (Fcb->PagingIoResource != NULL)) {
            if (!ExAcquireResourceExclusive( Fcb->PagingIoResource, Wait )) {
                break;
            }
            IrpContext->FcbWithPagingExclusive = Fcb;
            PagingIoAcquired = TRUE;
        }

        //
        //  Let's acquire this Fcb exclusively.
        //

        if (!NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, TRUE, DontWait )) {

            if (PagingIoAcquired) {
                ASSERT(IrpContext->TransactionId == 0);
                NtfsReleasePagingIo( IrpContext, Fcb );
            }
            break;
        }

        //
        //  If we now do not see a paging I/O resource we are golden,
        //  othewise we can absolutely release and acquire the resources
        //  safely in the right order, since a resource in the Fcb is
        //  not going to go away.
        //

        if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) ||
            PagingIoAcquired ||
            (Fcb->PagingIoResource == NULL)) {

            Status = TRUE;
            break;
        }

        NtfsReleaseFcb( IrpContext, Fcb );
    }

    return Status;
}
Ejemplo n.º 25
0
NTSTATUS
FFSWriteFile(
	IN PFFS_IRP_CONTEXT IrpContext)
{
	NTSTATUS            Status = STATUS_UNSUCCESSFUL;

	PFFS_VCB            Vcb  = NULL;
	PFFS_FCB            Fcb  = NULL;
	PFFS_CCB            Ccb =  NULL;
	PFILE_OBJECT        FileObject  = NULL;
	PFILE_OBJECT        CacheObject;

	PDEVICE_OBJECT      DeviceObject  = NULL;

	PIRP                Irp  = NULL;
	PIO_STACK_LOCATION  IoStackLocation  = NULL;

	ULONG               Length;
	ULONG               ReturnedLength = 0;
	LARGE_INTEGER       ByteOffset;

	BOOLEAN             PagingIo;
	BOOLEAN             Nocache;
	BOOLEAN             SynchronousIo;
	BOOLEAN             MainResourceAcquired = FALSE;
	BOOLEAN             PagingIoResourceAcquired = FALSE;

	BOOLEAN             bNeedExtending = FALSE;
	BOOLEAN             bAppendFile = FALSE;

	BOOLEAN             bDeferred = FALSE;

	PUCHAR              Buffer = NULL;

	__try
	{
		ASSERT(IrpContext);

		ASSERT((IrpContext->Identifier.Type == FFSICX) &&
				(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));

		DeviceObject = IrpContext->DeviceObject;

		Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;

		ASSERT(Vcb != NULL);

		ASSERT((Vcb->Identifier.Type == FFSVCB) &&
				(Vcb->Identifier.Size == sizeof(FFS_VCB)));

		FileObject = IrpContext->FileObject;

		Fcb = (PFFS_FCB)FileObject->FsContext;

		ASSERT(Fcb);

		ASSERT((Fcb->Identifier.Type == FFSFCB) &&
				(Fcb->Identifier.Size == sizeof(FFS_FCB)));

		Ccb = (PFFS_CCB)FileObject->FsContext2;

		Irp = IrpContext->Irp;

		IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

		Length = IoStackLocation->Parameters.Write.Length;
		ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;

		PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
		Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
		SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);

		FFSPrint((DBG_INFO, "FFSWriteFile: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
					ByteOffset.QuadPart, Length, PagingIo, Nocache));

		/*
		if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED))
		{
			Status = STATUS_FILE_DELETED;
			__leave;
		}

		if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING))
		{
			Status = STATUS_DELETE_PENDING;
			__leave;
		}
		*/

		if (Length == 0)
		{
			Irp->IoStatus.Information = 0;
			Status = STATUS_SUCCESS;
			__leave;
		}

		if (Nocache &&
				(ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
				 Length & (SECTOR_SIZE - 1)))
		{
			Status = STATUS_INVALID_PARAMETER;
			__leave;
		}

		if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC))
		{
			ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
			Status = STATUS_PENDING;
			__leave;
		}

#if FALSE
		if (!Nocache)
		{
			BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
			BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
			BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);

			if (!CcCanIWrite(
						FileObject,
						Length,
						(bWait && bQueue),
						bAgain))
			{
				SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);

				CcDeferWrite(FileObject,
						(PCC_POST_DEFERRED_WRITE)FFSDeferWrite,
						IrpContext,
						Irp,
						Length,
						bAgain);

				bDeferred = TRUE;

				FFSBreakPoint();

				Status = STATUS_PENDING;
				__leave;
			}
		}

#endif

		if (IsEndOfFile(ByteOffset))
		{
			bAppendFile = TRUE;
			ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
		}

		if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) && !PagingIo)
		{
			Status = STATUS_INVALID_DEVICE_REQUEST;
			__leave;
		}

		//
		//  Do flushing for such cases
		//
		if (Nocache && !PagingIo && (Fcb->SectionObject.DataSectionObject != NULL)) 
		{
			ExAcquireResourceExclusive(&Fcb->MainResource, 
					IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));

			MainResourceAcquired = TRUE;

			ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
			ExReleaseResource(&Fcb->PagingIoResource);

			CcFlushCache(&(Fcb->SectionObject),
					&ByteOffset,
					Length,
					&(Irp->IoStatus));
			ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);

			if (!NT_SUCCESS(Irp->IoStatus.Status)) 
			{
				Status = Irp->IoStatus.Status;
				__leave;
			}

			ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
			ExReleaseResource(&Fcb->PagingIoResource);

			CcPurgeCacheSection(&(Fcb->SectionObject),
					(PLARGE_INTEGER)&(ByteOffset),
					Length,
					FALSE);

			ExReleaseResource(&Fcb->MainResource);
			MainResourceAcquired = FALSE;
		}

		if (!PagingIo)
		{
			if (!ExAcquireResourceExclusiveLite(
						&Fcb->MainResource,
						IrpContext->IsSynchronous))
			{
				Status = STATUS_PENDING;
				__leave;
			}

			MainResourceAcquired = TRUE;
		}
		else
		{
			/*
			ULONG ResShCnt, ResExCnt; 
			ResShCnt = ExIsResourceAcquiredSharedLite(&Fcb->PagingIoResource);
			ResExCnt = ExIsResourceAcquiredExclusiveLite(&Fcb->PagingIoResource);

			FFSPrint((DBG_USER, "FFSWriteFile: Inode=%xh %S PagingIo: %xh:%xh Synchronous=%xh\n",
			Fcb->FFSMcb->Inode, Fcb->FFSMcb->ShortName.Buffer, ResShCnt, ResExCnt, IrpContext->IsSynchronous));
			*/
			if (!ExAcquireResourceSharedLite(
						&Fcb->PagingIoResource,
						IrpContext->IsSynchronous))
			{
				Status = STATUS_PENDING;
				__leave;
			}

			PagingIoResourceAcquired = TRUE;
		}

		if (!PagingIo)
		{
			if (!FsRtlCheckLockForWriteAccess(
						&Fcb->FileLockAnchor,
						Irp))
			{
				Status = STATUS_FILE_LOCK_CONFLICT;
				__leave;
			}
		}

		if (Nocache)
		{
			if ((ByteOffset.QuadPart + Length) >
					Fcb->Header.AllocationSize.QuadPart)
			{
				if (ByteOffset.QuadPart >= 
						Fcb->Header.AllocationSize.QuadPart)
				{
					Status = STATUS_SUCCESS;
					Irp->IoStatus.Information = 0;
					__leave;
				}
				else
				{
					if (Length > (ULONG)(Fcb->Header.AllocationSize.QuadPart
								- ByteOffset.QuadPart))
					{
						Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart
								- ByteOffset.QuadPart);
					}
				}
			}
		}

		if (!Nocache)
		{
			if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY))
			{
				__leave;
			}

			if (FileObject->PrivateCacheMap == NULL)
			{
				CcInitializeCacheMap(
						FileObject,
						(PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
						FALSE,
						&FFSGlobal->CacheManagerCallbacks,
						Fcb);

				CcSetReadAheadGranularity(
						FileObject,
						READ_AHEAD_GRANULARITY);

				CcSetFileSizes(
						FileObject, 
						(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
			}

			CacheObject = FileObject;

			//
			//  Need extending the size of inode ?
			//
			if ((bAppendFile) || ((ULONG)(ByteOffset.QuadPart + Length) >
						(ULONG)(Fcb->Header.FileSize.QuadPart)))
			{

				LARGE_INTEGER   ExtendSize;
				LARGE_INTEGER   FileSize;

				bNeedExtending = TRUE;
				FileSize = Fcb->Header.FileSize;
				ExtendSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length);

				if (ExtendSize.QuadPart > Fcb->Header.AllocationSize.QuadPart)
				{
					if (!FFSExpandFile(IrpContext, Vcb, Fcb, &ExtendSize))
					{
						Status = STATUS_INSUFFICIENT_RESOURCES;
						__leave;
					}
				}

				{
					Fcb->Header.FileSize.QuadPart = ExtendSize.QuadPart;
					Fcb->dinode1->di_size = (ULONG)ExtendSize.QuadPart;
				}

				if (FileObject->PrivateCacheMap)
				{
					CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));

					if (ByteOffset.QuadPart > FileSize.QuadPart)
					{
						FFSZeroHoles(IrpContext, Vcb, FileObject, FileSize.QuadPart, 
								ByteOffset.QuadPart - FileSize.QuadPart);
					}

					if (Fcb->Header.AllocationSize.QuadPart > ExtendSize.QuadPart)
					{
						FFSZeroHoles(IrpContext, Vcb, FileObject, ExtendSize.QuadPart, 
								Fcb->Header.AllocationSize.QuadPart - ExtendSize.QuadPart);
					}
				}

				if (FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, Fcb->dinode1))
				{
					Status = STATUS_SUCCESS;
				}

				FFSNotifyReportChange(
						IrpContext,
						Vcb,
						Fcb,
						FILE_NOTIFY_CHANGE_SIZE,
						FILE_ACTION_MODIFIED);
			}

			if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL))
			{
				CcPrepareMdlWrite(
						CacheObject,
						(&ByteOffset),
						Length,
						&Irp->MdlAddress,
						&Irp->IoStatus);

				Status = Irp->IoStatus.Status;
			}
			else
			{
				Buffer = FFSGetUserBuffer(Irp);

				if (Buffer == NULL)
				{
					FFSBreakPoint();
					Status = STATUS_INVALID_USER_BUFFER;
					__leave;
				}

				if (!CcCopyWrite(
							CacheObject,
							(PLARGE_INTEGER)&ByteOffset,
							Length,
							IrpContext->IsSynchronous,
							Buffer))
				{
					Status = STATUS_PENDING;
					__leave;
				}

				Status = Irp->IoStatus.Status;
			}

			if (NT_SUCCESS(Status))
			{
				Irp->IoStatus.Information = Length;

				if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK))
				{
					FFSPrint((DBG_USER, "FFSWriteFile is starting FlushingDpc...\n"));
					FFSStartFloppyFlushDpc(Vcb, Fcb, FileObject);
				}
			}
		}
		else
		{
			ReturnedLength = Length;

			Status = FFSLockUserBuffer(
					IrpContext->Irp,
					Length,
					IoReadAccess);

			if (!NT_SUCCESS(Status))
			{
				__leave;
			}

			Irp->IoStatus.Status = STATUS_SUCCESS;
			Irp->IoStatus.Information = Length;

			Status = 
				FFSv1WriteInode(
						IrpContext,
						Vcb,
						Fcb->dinode1,
						(ULONGLONG)(ByteOffset.QuadPart),
						NULL,
						Length,
						TRUE,
						&ReturnedLength);

			Irp = IrpContext->Irp;

		}
	}

	__finally
	{
		if (PagingIoResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Fcb->PagingIoResource,
					ExGetCurrentResourceThread());
		}

		if (MainResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Fcb->MainResource,
					ExGetCurrentResourceThread());
		}

		if (!IrpContext->ExceptionInProgress)
		{
			if (Irp)
			{
				if (Status == STATUS_PENDING)
				{
					if (!bDeferred)
					{
						Status = FFSLockUserBuffer(
									IrpContext->Irp,
									Length,
									IoReadAccess);

						if (NT_SUCCESS(Status))
						{
							Status = FFSQueueRequest(IrpContext);
						}
						else
						{
							FFSCompleteIrpContext(IrpContext, Status);
						}
					}
				}
				else
				{
					if (NT_SUCCESS(Status))
					{
						if (SynchronousIo && !PagingIo)
						{
							FileObject->CurrentByteOffset.QuadPart =
								ByteOffset.QuadPart + Irp->IoStatus.Information;
						}

						if (!PagingIo)
						{
							SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
							SetFlag(Fcb->Flags, FCB_FILE_MODIFIED);
						}
					}

					FFSCompleteIrpContext(IrpContext, Status);
				}
			}
			else
			{
				FFSFreeIrpContext(IrpContext);
			}
		}
	}

	return Status;

}
Ejemplo n.º 26
0
Archivo: bind.c Proyecto: BuloZB/WinNT4
NTSTATUS
AfdBind (
    IN PIRP Irp,
    IN PIO_STACK_LOCATION IrpSp
    )

/*++

Routine Description:

    Handles the IOCTL_AFD_BIND IOCTL.

Arguments:

    Irp - Pointer to I/O request packet.

    IrpSp - pointer to the IO stack location to use for this request.

Return Value:

    NTSTATUS -- Indicates whether the request was successfully queued.

--*/

{
    NTSTATUS status;
    OBJECT_ATTRIBUTES objectAttributes;
    IO_STATUS_BLOCK iosb;

    PTRANSPORT_ADDRESS transportAddress;
    PTRANSPORT_ADDRESS requestedAddress;
    ULONG requestedAddressLength;
    PAFD_ENDPOINT endpoint;

    PFILE_FULL_EA_INFORMATION ea;
    ULONG eaBufferLength;

    PAGED_CODE( );

    //
    // Set up local pointers.
    //

    requestedAddress = Irp->AssociatedIrp.SystemBuffer;
    requestedAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
    endpoint = IrpSp->FileObject->FsContext;
    ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );

    //
    // Bomb off if this is a helper endpoint.
    //

    if ( endpoint->Type == AfdBlockTypeHelper ) {
        return STATUS_INVALID_PARAMETER;
    }

    //
    // If the client wants a unique address, make sure that there are no
    // other sockets with this address.

    ExAcquireResourceExclusive( AfdResource, TRUE );

    if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0 ) {

        PLIST_ENTRY listEntry;

        //
        // Walk the global list of endpoints,
        // and compare this address againat the address on each endpoint.
        //

        for ( listEntry = AfdEndpointListHead.Flink;
              listEntry != &AfdEndpointListHead;
              listEntry = listEntry->Flink ) {

            PAFD_ENDPOINT compareEndpoint;

            compareEndpoint = CONTAINING_RECORD(
                                  listEntry,
                                  AFD_ENDPOINT,
                                  GlobalEndpointListEntry
                                  );

            ASSERT( IS_AFD_ENDPOINT_TYPE( compareEndpoint ) );

            //
            // Check whether the endpoint has a local address, whether
            // the endpoint has been disconnected, and whether the
            // endpoint is in the process of closing.  If any of these
            // is true, don't compare addresses with this endpoint.
            //

            if ( compareEndpoint->LocalAddress != NULL &&
                     ( (compareEndpoint->DisconnectMode &
                            (AFD_PARTIAL_DISCONNECT_SEND |
                             AFD_ABORTIVE_DISCONNECT) ) == 0 ) &&
                     (compareEndpoint->State != AfdEndpointStateClosing) ) {

                //
                // Compare the bits in the endpoint's address and the
                // address we're attempting to bind to.  Note that we
                // also compare the transport device names on the
                // endpoints, as it is legal to bind to the same address
                // on different transports (e.g.  bind to same port in
                // TCP and UDP).  We can just compare the transport
                // device name pointers because unique names are stored
                // globally.
                //

                if ( compareEndpoint->LocalAddressLength ==
                         IrpSp->Parameters.DeviceIoControl.InputBufferLength

                     &&

                     AfdAreTransportAddressesEqual(
                         compareEndpoint->LocalAddress,
                         compareEndpoint->LocalAddressLength,
                         requestedAddress,
                         requestedAddressLength,
                         FALSE
                         )

                     &&

                     endpoint->TransportInfo ==
                         compareEndpoint->TransportInfo ) {

                    //
                    // The addresses are equal.  Fail the request.
                    //

                    ExReleaseResource( AfdResource );

                    Irp->IoStatus.Information = 0;
                    Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;

                    return STATUS_SHARING_VIOLATION;
                }
            }
        }
    }

    //
    // Store the address to which the endpoint is bound.
    //

    endpoint->LocalAddress = AFD_ALLOCATE_POOL(
                                 NonPagedPool,
                                 requestedAddressLength,
                                 AFD_LOCAL_ADDRESS_POOL_TAG
                                 );

    if ( endpoint->LocalAddress == NULL ) {

        ExReleaseResource( AfdResource );

        Irp->IoStatus.Information = 0;
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

        return STATUS_INSUFFICIENT_RESOURCES;
    }

    endpoint->LocalAddressLength =
        IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    RtlMoveMemory(
        endpoint->LocalAddress,
        requestedAddress,
        endpoint->LocalAddressLength
        );

    ExReleaseResource( AfdResource );

    //
    // Allocate memory to hold the EA buffer we'll use to specify the
    // transport address to NtCreateFile.
    //

    eaBufferLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
                         TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
                         IrpSp->Parameters.DeviceIoControl.InputBufferLength;

#if DBG
    ea = AFD_ALLOCATE_POOL(
             NonPagedPool,
             eaBufferLength,
             AFD_EA_POOL_TAG
             );
#else
    ea = AFD_ALLOCATE_POOL(
             PagedPool,
             eaBufferLength,
             AFD_EA_POOL_TAG
             );
#endif

    if ( ea == NULL ) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // Initialize the EA.
    //

    ea->NextEntryOffset = 0;
    ea->Flags = 0;
    ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
    ea->EaValueLength = (USHORT)IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    RtlMoveMemory(
        ea->EaName,
        TdiTransportAddress,
        ea->EaNameLength + 1
        );

    transportAddress = (PTRANSPORT_ADDRESS)(&ea->EaName[ea->EaNameLength + 1]);

    RtlMoveMemory(
        transportAddress,
        requestedAddress,
        ea->EaValueLength
        );

    //
    // Prepare for opening the address object.
    //

    InitializeObjectAttributes(
        &objectAttributes,
        &endpoint->TransportInfo->TransportDeviceName,
        OBJ_CASE_INSENSITIVE,       // attributes
        NULL,
        NULL
        );

    //
    // Perform the actual open of the address object.
    //

    KeAttachProcess( AfdSystemProcess );

    status = ZwCreateFile(
                 &endpoint->AddressHandle,
                 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
                 &objectAttributes,
                 &iosb,                          // returned status information.
                 0,                              // block size (unused).
                 0,                              // file attributes.
                 FILE_SHARE_READ | FILE_SHARE_WRITE,
                 FILE_CREATE,                    // create disposition.
                 0,                              // create options.
                 ea,
                 eaBufferLength
                 );

    AFD_FREE_POOL(
        ea,
        AFD_EA_POOL_TAG
        );

    if ( !NT_SUCCESS(status) ) {

        //
        // We store the local address in a local before freeing it to
        // avoid a timing window.
        //

        PVOID localAddress = endpoint->LocalAddress;

        endpoint->LocalAddress = NULL;
        endpoint->LocalAddressLength = 0;
        AFD_FREE_POOL(
            localAddress,
            AFD_LOCAL_ADDRESS_POOL_TAG
            );

        KeDetachProcess( );

        return status;
    }

    AfdRecordAddrOpened();

    //
    // Get a pointer to the file object of the address.
    //

    status = ObReferenceObjectByHandle(
                 endpoint->AddressHandle,
                 0L,                         // DesiredAccess
                 NULL,
                 KernelMode,
                 (PVOID *)&endpoint->AddressFileObject,
                 NULL
                 );

    ASSERT( NT_SUCCESS(status) );

    AfdRecordAddrRef();

    IF_DEBUG(BIND) {
        KdPrint(( "AfdBind: address file object for endpoint %lx at %lx\n",
                      endpoint, endpoint->AddressFileObject ));
    }

    //
    // Remember the device object to which we need to give requests for
    // this address object.  We can't just use the
    // fileObject->DeviceObject pointer because there may be a device
    // attached to the transport protocol.
    //

    endpoint->AddressDeviceObject =
        IoGetRelatedDeviceObject( endpoint->AddressFileObject );

    //
    // Determine whether the TDI provider supports data bufferring.
    // If the provider doesn't, then we have to do it.
    //

    if ( (endpoint->TransportInfo->ProviderInfo.ServiceFlags &
             TDI_SERVICE_INTERNAL_BUFFERING) != 0 ) {
        endpoint->TdiBufferring = TRUE;
    } else {
        endpoint->TdiBufferring = FALSE;
    }

    //
    // Determine whether the TDI provider is message or stream oriented.
    //

    if ( (endpoint->TransportInfo->ProviderInfo.ServiceFlags &
             TDI_SERVICE_MESSAGE_MODE) != 0 ) {
        endpoint->TdiMessageMode = TRUE;
    } else {
        endpoint->TdiMessageMode = FALSE;
    }

    //
    // Remember that the endpoint has been bound to a transport address.
    //

    endpoint->State = AfdEndpointStateBound;

    //
    // Set up indication handlers on the address object.  Only set up
    // appropriate event handlers--don't set unnecessary event handlers.
    //

    status = AfdSetEventHandler(
                 endpoint->AddressFileObject,
                 TDI_EVENT_ERROR,
                 AfdErrorEventHandler,
                 endpoint
                 );
#if DBG
    if ( !NT_SUCCESS(status) ) {
        DbgPrint( "AFD: Setting TDI_EVENT_ERROR failed: %lx\n", status );
    }
#endif

    if ( IS_DGRAM_ENDPOINT(endpoint) ) {

        endpoint->EventsActive = AFD_POLL_SEND;

        IF_DEBUG(EVENT_SELECT) {
            KdPrint((
                "AfdBind: Endp %08lX, Active %08lX\n",
                endpoint,
                endpoint->EventsActive
                ));
        }

        status = AfdSetEventHandler(
                     endpoint->AddressFileObject,
                     TDI_EVENT_RECEIVE_DATAGRAM,
                     AfdReceiveDatagramEventHandler,
                     endpoint
                     );
#if DBG
        if ( !NT_SUCCESS(status) ) {
            DbgPrint( "AFD: Setting TDI_EVENT_RECEIVE_DATAGRAM failed: %lx\n", status );
        }
#endif

    } else {