Beispiel #1
0
NTSTATUS
EvtWmiClass6DataQueryInstance(
    WDFWMIINSTANCE WmiInstance,
    ULONG OutBufferSize,
    PVOID OutBuffer,
    PULONG BufferUsed
    )

/*++

Routine Description:

    This is the callback routine for the WMI Query irp on the Instance representing
    the sample class 6. This routine gets the current value for the data members
    of the sample class and copies it to the given output buffer. The sample class6
    contains a fixed array of embedded class EC2.

Arguments:

    WmiInstance - The handle to the WMI instance object.

    OutBufferSize - The size (in bytes) of the output buffer into which the
        instance data is to be copied.

    OutBuffer - Pointer to the output buffer.

    BufferUsed - Pointer to the location that receives the number of bytes that
        were copied into the output buffer.

Return Value:

    NT Status code.

--*/

{
    NTSTATUS status;
    WDFDEVICE device;
    PWMI_SAMPLE_DEVICE_DATA wmiDeviceData;
    ULONG sizeNeeded;
    ULONG sizeUsed;
    ULONG i;

    UNREFERENCED_PARAMETER(OutBufferSize);
    PAGED_CODE();

    device = WdfWmiInstanceGetDevice(WmiInstance);
    wmiDeviceData = GetWmiSampleDeviceData(device);

    //
    // Fixed array of EC2.
    //
    sizeNeeded = 0;
    for (i = 0; i < EC2_COUNT; i++) {
        sizeNeeded += ALIGN_UP(wmiDeviceData->Ec2Length[i], PVOID);
    }

    if (OutBufferSize < sizeNeeded) {

        *BufferUsed = 0;
        status = STATUS_BUFFER_TOO_SMALL;

    } else {

        *BufferUsed = 0;
        for (i = 0; i < EC2_COUNT; i++) {

            sizeUsed = WmiSampGetEc2(wmiDeviceData, OutBuffer, i);
            OutBuffer = Add2Ptr(OutBuffer, ALIGN_UP(sizeUsed, PVOID));
            *BufferUsed += sizeUsed;
        }
        status = STATUS_SUCCESS;
    }

    return status;
}
Beispiel #2
0
VOID
CdUpcaseName (
    IN PIRP_CONTEXT IrpContext,
    IN PCD_NAME Name,
    IN OUT PCD_NAME UpcaseName
    )

/*++

Routine Description:

    This routine is called to upcase a CdName structure.  We will do both
    the filename and version strings.

Arguments:

    Name - This is the mixed case version of the name.

    UpcaseName - This is the destination for the upcase operation.

Return Value:

    None.  This routine will raise all errors.

--*/

{
    NTSTATUS Status;
    PVOID NewBuffer;

    PAGED_CODE();

    //
    //  If the name structures are different then initialize the different components.
    //

    if (Name != UpcaseName) {

        //
        //  Initialize the version string portion of the name.
        //

        UpcaseName->VersionString.Length = 0;

        if (Name->VersionString.Length != 0) {

            UpcaseName->VersionString.MaximumLength =
            UpcaseName->VersionString.Length = Name->VersionString.Length;

            //
            //  Initially set the buffer to point to where we need to insert
            //  the separator.
            //

            UpcaseName->VersionString.Buffer = Add2Ptr( UpcaseName->FileName.Buffer,
                                                        Name->FileName.Length,
                                                        PWCHAR );

            //
            //  We are currently pointing to the location to store the separator.
            //  Store the ';' and then move to the next character to
            //  copy the data.
            //

            *(UpcaseName->VersionString.Buffer) = L';';

            UpcaseName->VersionString.Buffer += 1;
        }
    }

    //
    //  Upcase the string using the correct upcase routine.
    //

    Status = RtlUpcaseUnicodeString( &UpcaseName->FileName,
                                     &Name->FileName,
                                     FALSE );

    //
    //  This should never fail.
    //

    ASSERT( Status == STATUS_SUCCESS );

    if (Name->VersionString.Length != 0) {

        Status = RtlUpcaseUnicodeString( &UpcaseName->VersionString,
                                         &Name->VersionString,
                                         FALSE );

        //
        //  This should never fail.
        //

        ASSERT( Status == STATUS_SUCCESS );
    }

    return;
}
Beispiel #3
0
NTSTATUS
LfsReadRestartArea (
    IN LFS_LOG_HANDLE LogHandle,
    IN OUT PULONG BufferLength,
    IN PVOID Buffer,
    OUT PLSN Lsn
    )

/*++

Routine Description:

    This routine is called by the client when he wishes to read his restart
    area in the log file.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

    BufferLength - On entry it is the length of the user buffer.  On exit
                   it is the size of the data stored in the buffer.

    Buffer - Pointer to the buffer where the client restart data is to be
             copied.

    Lsn - This is the Lsn for client restart area.

Return Value:

    None

--*/

{
    volatile NTSTATUS Status = STATUS_SUCCESS;

    BOOLEAN UsaError;

    PLCH Lch;

    PLFS_CLIENT_RECORD ClientRecord;

    PLFS_RECORD_HEADER RecordHeader;
    PBCB RecordHeaderBcb;

    PLFCB Lfcb;
    NTSTATUS RetStatus = STATUS_SUCCESS;


    PAGED_CODE();

    DebugTrace( +1, Dbg, "LfsReadRestartArea:  Entered\n", 0 );
    DebugTrace(  0, Dbg, "Log Handle    -> %08lx\n", LogHandle );
    DebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
    DebugTrace(  0, Dbg, "Buffer        -> %08lx\n", Buffer );

    RecordHeaderBcb = NULL;

    Lch = (PLCH) LogHandle;

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-except to catch errors.
    //

    try {

        //
        //  Use a try-finally to facilitate cleanup.
        //

        try {

            //
            //  Acquire the log file control block for this log file.
            //

            LfsAcquireLch( Lch );
            Lfcb = Lch->Lfcb;

            //
            //  If the Log file has been closed then refuse access.
            //

            if (Lfcb == NULL) {

                ExRaiseStatus( STATUS_ACCESS_DENIED );
            }

            //
            //  Check that the client Id is valid.
            //

            LfsValidateClientId( Lfcb, Lch );

            ClientRecord = Add2Ptr( Lfcb->ClientArray,
                                    Lch->ClientArrayByteOffset,
                                    PLFS_CLIENT_RECORD );

            //
            //  If the client doesn't have a restart area, go ahead and exit
            //  now.
            //

            if ( ClientRecord->ClientRestartLsn.QuadPart == 0 ) {                                                      //**** xxEqlZero( ClientRecord->ClientRestartLsn )

                //
                //  We show there is no restart area by returning a length
                //  of zero.  We also set the Lsn value to zero so that
                //  we can catch it if the user tries to use the Lsn.
                //

                DebugTrace( 0, Dbg, "No client restart area exists\n", 0 );

                *BufferLength = 0;
                *Lsn = LfsZeroLsn;

                try_return( NOTHING );
            }

            //
            //  Release the Lfcb as we won't be modifying any fields in it.
            //

            LfsReleaseLfcb( Lfcb );

            //
            //  Pin the log record for this Lsn.
            //

            LfsPinOrMapLogRecordHeader( Lfcb,
                                        ClientRecord->ClientRestartLsn,
                                        FALSE,
                                        FALSE,
                                        &UsaError,
                                        &RecordHeader,
                                        &RecordHeaderBcb );

            //
            //  If the Lsn values don't match, then the disk is corrupt.
            //

            if ( ClientRecord->ClientRestartLsn.QuadPart != RecordHeader->ThisLsn.QuadPart ) {                         //**** xxNeq( ClientRecord->ClientRestartLsn, RecordHeader->ThisLsn )

                ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
            }


            //
            //  Check that the user's buffer is big enough to hold the restart
            //  data.  We raise an error status for this error.
            //

            if (RecordHeader->ClientDataLength > *BufferLength) {

                DebugTrace( 0, Dbg, "Client buffer is too small\n", 0 );
                *BufferLength = RecordHeader->ClientDataLength;
                *Lsn = LfsZeroLsn;
                try_return( RetStatus = STATUS_BUFFER_TOO_SMALL );
            }


            //
            //  Use the cache manager to copy the data into the user's buffer.
            //

            LfsCopyReadLogRecord( Lfcb,
                                  RecordHeader,
                                  Buffer );

            //
            //  Pass the length and the Lsn of the restart area back to the
            //  caller.
            //

            *BufferLength = RecordHeader->ClientDataLength;
            *Lsn = RecordHeader->ThisLsn;

        try_exit: NOTHING;
        } finally {

            DebugUnwind( LfsReadRestartArea );

            //
            //  Release the log file control block if held.
            //

            LfsReleaseLch( Lch );

            //
            //  Unpin the log record header for the client restart if pinned.
            //

            if (RecordHeaderBcb != NULL) {

                CcUnpinData( RecordHeaderBcb );
            }

            DebugTrace(  0, Dbg, "Lsn (Low)     -> %08lx\n", Lsn->LowPart );
            DebugTrace(  0, Dbg, "Lsn (High)    -> %08lx\n", Lsn->HighPart );
            DebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
            DebugTrace( -1, Dbg, "LfsReadRestartArea:  Exit\n", 0 );
        }

    } except (LfsExceptionFilter( GetExceptionInformation() )) {

        Status = GetExceptionCode();
    }

    if (Status != STATUS_SUCCESS) {

        ExRaiseStatus( Status );
    }

    return RetStatus;
}
VOID
CdInsertPrefix (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFCB Fcb,
    _In_ PCD_NAME Name,
    _In_ BOOLEAN IgnoreCase,
    _In_ BOOLEAN ShortNameMatch,
    _Inout_ PFCB ParentFcb
    )

/*++

Routine Description:

    This routine inserts the names in the given Lcb into the links for the
    parent.

Arguments:

    Fcb - This is the Fcb whose name is being inserted into the tree.

    Name - This is the name for the component.  The IgnoreCase flag tells
        us which entry this belongs to.

    IgnoreCase - Indicates if we should insert the case-insensitive name.

    ShortNameMatch - Indicates if this is the short name.

    ParentFcb - This is the ParentFcb.  The prefix tree is attached to this.

Return Value:

    None.

--*/

{
    ULONG PrefixFlags;
    PNAME_LINK NameLink;
    PPREFIX_ENTRY PrefixEntry;
    PRTL_SPLAY_LINKS *TreeRoot;

    PWCHAR NameBuffer;

    PAGED_CODE();

    //
    //  Check if we need to allocate a prefix entry for the short name.
    //  If we can't allocate one then fail quietly.  We don't have to
    //  insert the name.
    //

    PrefixEntry = &Fcb->FileNamePrefix;

    if (ShortNameMatch) {

        if (Fcb->ShortNamePrefix == NULL) {

            Fcb->ShortNamePrefix = ExAllocatePoolWithTag( CdPagedPool,
                                                          sizeof( PREFIX_ENTRY ),
                                                          TAG_PREFIX_ENTRY );

            if (Fcb->ShortNamePrefix == NULL) { return; }

            RtlZeroMemory( Fcb->ShortNamePrefix, sizeof( PREFIX_ENTRY ));
        }

        PrefixEntry = Fcb->ShortNamePrefix;
    }

    //
    //  Capture the local variables for the separate cases.
    //

    if (IgnoreCase) {

        PrefixFlags = PREFIX_FLAG_IGNORE_CASE_IN_TREE;
        NameLink = &PrefixEntry->IgnoreCaseName;
        TreeRoot = &ParentFcb->IgnoreCaseRoot;

    } else {

        PrefixFlags = PREFIX_FLAG_EXACT_CASE_IN_TREE;
        NameLink = &PrefixEntry->ExactCaseName;
        TreeRoot = &ParentFcb->ExactCaseRoot;
    }

    //
    //  If neither name is in the tree then check whether we have a buffer for this
    //  name
    //

    if (!FlagOn( PrefixEntry->PrefixFlags,
                 PREFIX_FLAG_EXACT_CASE_IN_TREE | PREFIX_FLAG_IGNORE_CASE_IN_TREE )) {

        //
        //  Allocate a new buffer if the embedded buffer is too small.
        //

        NameBuffer = PrefixEntry->FileNameBuffer;

        if (Name->FileName.Length > BYTE_COUNT_EMBEDDED_NAME) {

            NameBuffer = ExAllocatePoolWithTag( CdPagedPool,
                                                Name->FileName.Length * 2,
                                                TAG_PREFIX_NAME );

            //
            //  Exit if no name buffer.
            //

            if (NameBuffer == NULL) { return; }
        }

        //
        //  Split the buffer and fill in the separate components.
        //

        PrefixEntry->ExactCaseName.FileName.Buffer = NameBuffer;
        PrefixEntry->IgnoreCaseName.FileName.Buffer = Add2Ptr( NameBuffer,
                                                               Name->FileName.Length,
                                                               PWCHAR );

        PrefixEntry->IgnoreCaseName.FileName.MaximumLength =
        PrefixEntry->IgnoreCaseName.FileName.Length =
        PrefixEntry->ExactCaseName.FileName.MaximumLength =
        PrefixEntry->ExactCaseName.FileName.Length = Name->FileName.Length;
    }

    //
    //  Only insert the name if not already present.
    //

    if (!FlagOn( PrefixEntry->PrefixFlags, PrefixFlags )) {

        //
        //  Initialize the name in the prefix entry.
        //

        RtlCopyMemory( NameLink->FileName.Buffer,
                       Name->FileName.Buffer,
                       Name->FileName.Length );

        CdInsertNameLink( IrpContext,
                          TreeRoot,
                          NameLink );

        PrefixEntry->Fcb = Fcb;
        SetFlag( PrefixEntry->PrefixFlags, PrefixFlags );
    }

    return;
}
NTSTATUS
CdCommonWrite (
    _Inout_ PIRP_CONTEXT IrpContext,
    _Inout_ PIRP Irp
    )

/*++

Routine Description:

    This is the common entry point for NtWriteFile calls.  For synchronous requests,
    CommonWrite will complete the request in the current thread.  If not
    synchronous the request will be passed to the Fsp if there is a need to
    block.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The result of this operation.

--*/

{
    NTSTATUS Status = STATUS_SUCCESS;
    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );

    TYPE_OF_OPEN TypeOfOpen;
    PFCB Fcb;
    PCCB Ccb;

    BOOLEAN Wait;
    ULONG SynchronousIo;
    PVOID UserBuffer;

    LONGLONG StartingOffset;
    LONGLONG ByteRange;
    ULONG ByteCount;
    ULONG WriteByteCount;
    ULONG OriginalByteCount;

    BOOLEAN ReleaseFile = TRUE;

    CD_IO_CONTEXT LocalIoContext;

    PAGED_CODE();

    //
    //  If this is a zero length write then return SUCCESS immediately.
    //

    if (IrpSp->Parameters.Write.Length == 0) {

        CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
        return STATUS_SUCCESS;
    }

    //
    //  Decode the file object and verify we support write on this.  It
    //  must be a volume file.
    //

    TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );

    // Internal lock object is acquired if return status is STATUS_PENDING
    _Analysis_suppress_lock_checking_(Fcb->Resource);

    if (TypeOfOpen != UserVolumeOpen) {

        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
        return STATUS_INVALID_DEVICE_REQUEST;
    }

    //
    //  Examine our input parameters to determine if this is noncached and/or
    //  a paging io operation.
    //

    Wait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
    SynchronousIo = FlagOn( IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO );


    //
    //  Extract the range of the Io.
    //

    StartingOffset = IrpSp->Parameters.Write.ByteOffset.QuadPart;
    OriginalByteCount = ByteCount = IrpSp->Parameters.Write.Length;

    ByteRange = StartingOffset + ByteCount;

    //
    //  Acquire the file shared to perform the write.
    //

    CdAcquireFileShared( IrpContext, Fcb );

    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {

        //
        //  Verify the Fcb.  Allow writes if this is a DASD handle that is 
        //  dismounting the volume.
        //

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

            CdVerifyFcbOperation( IrpContext, Fcb );
        }

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

            //
            //  Complete the request if it begins beyond the end of file.
            //

            if (StartingOffset >= Fcb->FileSize.QuadPart) {

                try_return( Status = STATUS_END_OF_FILE );
            }

            //
            //  Truncate the write if it extends beyond the end of the file.
            //

            if (ByteRange > Fcb->FileSize.QuadPart) {

                ByteCount = (ULONG) (Fcb->FileSize.QuadPart - StartingOffset);
                ByteRange = Fcb->FileSize.QuadPart;
            }
        }

        //
        //  If we have an unaligned transfer then post this request if
        //  we can't wait.  Unaligned means that the starting offset
        //  is not on a sector boundary or the write is not integral
        //  sectors.
        //

        WriteByteCount = BlockAlign( Fcb->Vcb, ByteCount );

        if (SectorOffset( StartingOffset ) ||
            SectorOffset( WriteByteCount ) ||
            (WriteByteCount > OriginalByteCount)) {

            if (!Wait) {

                CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
            }

            //
            //  Make sure we don't overwrite the buffer.
            //

            WriteByteCount = ByteCount;
        }

        //
        //  Initialize the IoContext for the write.
        //  If there is a context pointer, we need to make sure it was
        //  allocated and not a stale stack pointer.
        //

        if (IrpContext->IoContext == NULL ||
            !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {

            //
            //  If we can wait, use the context on the stack.  Otherwise
            //  we need to allocate one.
            //

            if (Wait) {

                IrpContext->IoContext = &LocalIoContext;
                ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );

            } else {

                IrpContext->IoContext = CdAllocateIoContext();
                SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
            }
        }

        RtlZeroMemory( IrpContext->IoContext, sizeof( CD_IO_CONTEXT ) );

        //
        //  Store whether we allocated this context structure in the structure
        //  itself.
        //

        IrpContext->IoContext->AllocatedContext =
            BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );

        if (Wait) {

            KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
                               NotificationEvent,
                               FALSE );

        } else {

            IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread();
            IrpContext->IoContext->Resource = Fcb->Resource;
            IrpContext->IoContext->RequestedByteCount = ByteCount;
        }

        Irp->IoStatus.Information = WriteByteCount;

        //
        //  Set the FO_MODIFIED flag here to trigger a verify when this
        //  handle is closed.  Note that we can err on the conservative
        //  side with no problem, i.e. if we accidently do an extra
        //  verify there is no problem.
        //

        SetFlag( IrpSp->FileObject->Flags, FO_FILE_MODIFIED );

        //
        //  Dasd access is always non-cached. Call the Dasd write routine to
        //  perform the actual write.
        //

        Status = CdVolumeDasdWrite( IrpContext, Fcb, StartingOffset, WriteByteCount );

        //
        //  Don't complete this request now if STATUS_PENDING was returned.
        //

        if (Status == STATUS_PENDING) {

            Irp = NULL;
            ReleaseFile = FALSE;

        //
        //  Test is we should zero part of the buffer or update the
        //  synchronous file position.
        //

        } else {

            //
            //  Convert any unknown error code to IO_ERROR.
            //

            if (!NT_SUCCESS( Status )) {

                //
                //  Set the information field to zero.
                //

                Irp->IoStatus.Information = 0;

                //
                //  Raise if this is a user induced error.
                //

                if (IoIsErrorUserInduced( Status )) {

                    CdRaiseStatus( IrpContext, Status );
                }

                Status = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR );

            //
            //  Check if there is any portion of the user's buffer to zero.
            //

            } else if (WriteByteCount != ByteCount) {

                CdMapUserBuffer( IrpContext, &UserBuffer );
                
                SafeZeroMemory( IrpContext,
                                Add2Ptr( UserBuffer,
                                         ByteCount,
                                         PVOID ),
                                WriteByteCount - ByteCount );

                Irp->IoStatus.Information = ByteCount;
            }

            //
            //  Update the file position if this is a synchronous request.
            //

            if (SynchronousIo && NT_SUCCESS( Status )) {

                IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
            }
        }

    try_exit:  NOTHING;
    } finally {

        //
        //  Release the Fcb.
        //

        if (ReleaseFile) {

            CdReleaseFile( IrpContext, Fcb );
        }
    }

    //
    //  Post the request if we got CANT_WAIT.
    //

    if (Status == STATUS_CANT_WAIT) {

        Status = CdFsdPostRequest( IrpContext, Irp );

    //
    //  Otherwise complete the request.
    //

    } else {

        CdCompleteRequest( IrpContext, Irp, Status );
    }

    return Status;
}
Beispiel #6
0
VOID
LfsFindLogRecord (
    IN PLFCB Lfcb,
    IN OUT PLCB Lcb,
    IN LSN Lsn,
    OUT PLFS_RECORD_TYPE RecordType,
    OUT TRANSACTION_ID *TransactionId,
    OUT PLSN UndoNextLsn,
    OUT PLSN PreviousLsn,
    OUT PULONG BufferLength,
    OUT PVOID *Buffer
    )

/*++

Routine Description:

    This routine is called recover a log record for a client.

Arguments:

    Lfcb - Log file control block for this file.

    Lcb - Pointer to the context block to update.

    Lsn - This is the Lsn for the log record.

    RecordType - Supplies the address to store the record type of this
                 log record.

    TransactionId - Supplies the address to store the transaction Id of
                    this log record.

    UndoNextLsn - Supplies the address to store the Undo Next Lsn for this
                  log record.

    PreviousLsn - Supplies the address to store the Previous Lsn for this
                  log record.

    BufferLength - Pointer to address to store the length in bytes of the
                   log record.

    Buffer - Pointer to store the address where the log record data begins.

Return Value:

    None

--*/

{
    PCHAR NewBuffer;
    BOOLEAN UsaError;
    LONGLONG LogRecordLength;
    ULONG PageOffset;

    PAGED_CODE();

    DebugTrace( +1, Dbg, "LfsFindLogRecord:  Entered\n", 0 );
    DebugTrace(  0, Dbg, "Lfcb          -> %08lx\n", Lfcb );
    DebugTrace(  0, Dbg, "Context Block -> %08lx\n", Lcb );
    DebugTrace(  0, Dbg, "Lsn (Low)     -> %08lx\n", Lsn.LowPart );

    NewBuffer = NULL;

    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {

        //
        //  Map the record header for this Lsn if we haven't already.
        //

        if (Lcb->RecordHeader == NULL) {

            LfsPinOrMapLogRecordHeader( Lfcb,
                                        Lsn,
                                        FALSE,
                                        FALSE,
                                        &UsaError,
                                        &Lcb->RecordHeader,
                                        &Lcb->RecordHeaderBcb );
        }

        //
        //  We now have the log record desired.  If the Lsn in the
        //  log record doesn't match the desired Lsn then the disk is
        //  corrupt.
        //

        if ( Lsn.QuadPart != Lcb->RecordHeader->ThisLsn.QuadPart ) {                                                   //**** xxNeq( Lsn, Lcb->RecordHeader->ThisLsn )

            ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
        }

        //
        //  Check that the length field isn't greater than the total available space
        //  in the log file.
        //

        LogRecordLength = Lcb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength;                              //**** xxFromUlong( Lcb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength );

        if ( LogRecordLength >= Lfcb->TotalAvailable ) {                                                               //**** xxGeq( LogRecordLength, Lfcb->TotalAvailable )

            ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
        }

        //
        //  If the entire log record is on this log page, put a pointer to
        //  the log record in the context block.
        //

        if (!FlagOn( Lcb->RecordHeader->Flags, LOG_RECORD_MULTI_PAGE )) {

            //
            //  If client size indicates that we have to go beyond the end of the current
            //  page, we raise an error.
            //

            PageOffset = LfsLsnToPageOffset( Lfcb, Lsn );

            if ((PageOffset + Lcb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength)
                > (ULONG)Lfcb->LogPageSize) {

                ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
            }

            Lcb->CurrentLogRecord = Add2Ptr( Lcb->RecordHeader, LFS_RECORD_HEADER_SIZE, PVOID );
            Lcb->AuxilaryBuffer = FALSE;

        //
        //  Else we copy the data and remember that we allocated a buffer.
        //

        } else {

            NewBuffer = FsRtlAllocatePool( PagedPool, Lcb->RecordHeader->ClientDataLength );

            LfsCopyReadLogRecord( Lfcb,
                                  Lcb->RecordHeader,
                                  NewBuffer );

            Lcb->CurrentLogRecord = NewBuffer;

            Lcb->AuxilaryBuffer = TRUE;

            NewBuffer = NULL;
        }

        //
        //  We need to update the caller's parameters and the context block.
        //

        *RecordType = Lcb->RecordHeader->RecordType;
        *TransactionId = Lcb->RecordHeader->TransactionId;

        *UndoNextLsn = Lcb->RecordHeader->ClientUndoNextLsn;
        *PreviousLsn = Lcb->RecordHeader->ClientPreviousLsn;

        *Buffer = Lcb->CurrentLogRecord;
        *BufferLength = Lcb->RecordHeader->ClientDataLength;

    } finally {

        DebugUnwind( LfsFindLogRecord );

        //
        //  If an error occurred we unpin the record header and the log
        //  We also free the buffer if allocated by us.
        //

        if (NewBuffer != NULL) {

            ExFreePool( NewBuffer );
        }

        DebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
        DebugTrace(  0, Dbg, "Buffer        -> %08lx\n", *Buffer );
        DebugTrace( -1, Dbg, "LfsFindLogRecord:  Exit\n", 0 );
    }

    return;
}
Beispiel #7
0
//
// get acpi table
//
PACPI_DESCRIPTION_HEADER BlFindACPITable(__in ULONG Signature,__in ULONG Length)
{
	//
	// get rsdt first
	//
	if(!BlRsdt)
		BlFindRsdp();

	//
	// bios did not support acpi,give up
	//
	if(!BlRsdt)
		return 0;

	if(Signature == ACPI_RSDT_SIGNATURE)
		return &BlRsdt->Header;

	if(Signature == ACPI_XSDT_SIGNATURE)
		return &BlXsdt->Header;

	if(Signature == ACPI_DSDT_SIGNATURE)
	{
		//
		// get fadt
		//
		PACPI_FADT Fadt									= CONTAINING_RECORD(BlFindACPITable(ACPI_FADT_SIGNATURE,sizeof(ACPI_FADT)),ACPI_FADT,Header);
		if(!Fadt)
			return 0;

		//
		// if bios gave us a 64bit dsdt,return it
		// otherwise return the 32bit one
		//
		PHYSICAL_ADDRESS MapAddress;
		if(BlXsdt)
			MapAddress.QuadPart							= Fadt->Dsdt64;
		else
			MapAddress.QuadPart							= Fadt->Dsdt;

		//
		// map it
		//
		return static_cast<PACPI_DESCRIPTION_HEADER>(MmMapIoSpace(MapAddress,Length,MmNonCached));
	}

	//
	// search in rsdt
	//
	ULONG Count											= BlXsdt ? BlXsdt->Header.Length : BlRsdt->Header.Length;
	if(Count < sizeof(ACPI_DESCRIPTION_HEADER))
		Count											= sizeof(ACPI_DESCRIPTION_HEADER);

	Count												= (Count - sizeof(ACPI_DESCRIPTION_HEADER)) / (BlXsdt ? sizeof(LONGLONG) : sizeof(ULONG));

	//
	// too big
	//
	if(Count > 0x100)
		return 0;

	for(ULONG i = 0; i < Count; i ++)
	{
		PHYSICAL_ADDRESS MapAddress;

		//
		// if bios gave us an extended system description table,use it
		// otherwise use rdst
		//
		if(BlXsdt)
			MapAddress.QuadPart							= BlXsdt->Tables[i];
		else
			MapAddress.QuadPart							= BlRsdt->Tables[i];

		//
		// map header
		//
		PACPI_DESCRIPTION_HEADER Header					= static_cast<PACPI_DESCRIPTION_HEADER>(MmMapIoSpace(MapAddress,sizeof(ACPI_DESCRIPTION_HEADER),MmNonCached));

		//
		// check signature
		//
		if(Header && Header->Signature == Signature)
		{
			//
			// the whole table fit in the same page?
			//
			if(PAGE_ALIGN(Add2Ptr(Header,Length,PVOID)) <= PAGE_ALIGN(Add2Ptr(Header,sizeof(ACPI_DESCRIPTION_HEADER),PVOID)))
				return Header;

			//
			// more pages are needed
			//
			return static_cast<PACPI_DESCRIPTION_HEADER>(MmMapIoSpace(MapAddress,Length,MmNonCached));
		}
	}

	return 0;
}
Beispiel #8
0
BOOLEAN
NcSkipName (
    _In_ PDIRECTORY_CONTROL_OFFSETS Offsets,
    _In_ PNC_DIR_QRY_CONTEXT Context, 
    _In_ NC_PATH_OVERLAP RealOverlap,
    _In_ PNC_MAPPING Mapping,
    _In_ BOOLEAN IgnoreCase
    )
/*++

Routine Description:

    Determines if the next entry is for the real mapping.  If it is, we want
    to "skip" returning this entry and proceed to the next.

Arguments:

    Offsets - Offset information for this enumeration class.

    Context - Pointer to directory query context (on the stream handle.)
        This is used to obtain the entry we are contemplating returning.

    RealOverlap - Relationship of the object that enumeration is being
        requested on to the real mapping.  This routine will only skip
        entries if we are enumerating the parent of the real mapping.

Return Value:

    TRUE if this entry should be skipped/suppressed; FALSE if it should be
    returned to the user.

--*/
{
    BOOLEAN Result = FALSE;
    PVOID CacheEntry;
    UNICODE_STRING CacheString;
    PUNICODE_STRING IgnoreString = &Mapping->RealMapping.LongNamePath.FinalComponentName;
    ULONG ElementSize;
    BOOLEAN LastElement;

    PAGED_CODE();

    if (RealOverlap.Parent) {

        //
        //  We have to check for a match.
        //

        CacheEntry = Add2Ptr( Context->Cache.Buffer, Context->Cache.CurrentOffset);
        ElementSize = NcGetEntrySize( CacheEntry, Offsets );
        LastElement = (BOOLEAN)(NcGetNextEntryOffset( CacheEntry, Offsets ) == 0);

        CacheString.Buffer = NcGetFileName( CacheEntry, Offsets );
        CacheString.Length = (USHORT) NcGetFileNameLength( CacheEntry, Offsets );
        CacheString.MaximumLength = CacheString.Length;


        if (RtlCompareUnicodeString( &CacheString, 
                                     IgnoreString,
                                     IgnoreCase ) == 0) {

            //
            //  We need to ignore this name.
            //

            Result = TRUE;

            //
            //  skip
            //

            if (LastElement) {

                //
                //  This was the last element in the entry, so we should clean the entry.
                //

                ExFreePoolWithTag(Context->Cache.Buffer, NC_DIR_QRY_CACHE_TAG);
                Context->Cache.Buffer = NULL;
                Context->Cache.CurrentOffset = 0;

            } else {

                //
                //  Entry has more elements, update offset counter.
                //

                Context->Cache.CurrentOffset += ElementSize;
            }
        } 
    }

    return Result;
}
Beispiel #9
0
VOID
LfsWriteLfsRestart (
    IN PLFCB Lfcb,
    IN ULONG ThisRestartSize,
    IN BOOLEAN WaitForIo
    )

/*++

Routine Description:

    This routine puts the Lfs restart area on the queue of operations to
    write to the file.  We do this by allocating a second restart area
    and attaching it to the Lfcb.  We also allocate a buffer control
    block to use for this write.  We look at the WaitForIo boolean to
    determine whether this thread can perform the I/O.  This also indicates
    whether this thread gives up the Lfcb.

Arguments:

    Lfcb - A pointer to the log file control block for this operation.

    ThisRestartSize - This is the size to use for the restart area.

    WaitForIo - Indicates if this thread is to perform the work.

Return Value:

    None.

--*/

{
    PLBCB NewLbcb = NULL;
    PLFS_RESTART_AREA NewRestart = NULL;

    PAGED_CODE();

    DebugTrace( +1, Dbg, "LfsWriteLfsRestart:  Entered\n", 0 );
    DebugTrace(  0, Dbg, "Lfcb          -> %08lx\n", Lfcb );
    DebugTrace(  0, Dbg, "Write Chkdsk  -> %04x\n", WriteChkdsk );
    DebugTrace(  0, Dbg, "Restart Size  -> %08lx\n", ThisRestartSize );
    DebugTrace(  0, Dbg, "WaitForIo     -> %08lx\n", WaitForIo );

    //
    //  We'd absolutely hate for this to happen on a read only volume.
    //

    ASSERT(!(FlagOn( Lfcb->Flags, LFCB_READ_ONLY )));

    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {

        PLBCB ActiveLbcb;

        //
        //  We allocate another restart area and
        //  copy the current area into it.  Attach the new area to the Lfcb.
        //

        LfsAllocateRestartArea( &NewRestart, ThisRestartSize );

        //
        //  We allocate a Lbcb structure and update the values to
        //  reflect this restart area.
        //

        LfsAllocateLbcb( Lfcb, &NewLbcb );
        SetFlag( NewLbcb->LbcbFlags, LBCB_RESTART_LBCB );

        //
        //  If this is the second page, then add a page to the offset.
        //

        if (!Lfcb->InitialRestartArea) {

            NewLbcb->FileOffset = Lfcb->LogPageSize + NewLbcb->FileOffset;
        }

        (ULONG)NewLbcb->Length = ThisRestartSize;

        NewLbcb->PageHeader = (PVOID) Lfcb->RestartArea;

        //
        //  Lets put the current lsn in the Lbcb.
        //

        NewLbcb->LastEndLsn = NewLbcb->LastLsn = Lfcb->NextRestartLsn;
        Lfcb->NextRestartLsn.QuadPart = 1 + Lfcb->NextRestartLsn.QuadPart;

        //
        //  Copy the existing restart area into the new area.
        //

        RtlCopyMemory( NewRestart, Lfcb->RestartArea, ThisRestartSize );
        Lfcb->RestartArea = NewRestart;

        Lfcb->ClientArray = Add2Ptr( NewRestart, Lfcb->ClientArrayOffset, PLFS_CLIENT_RECORD );

        NewRestart = NULL;

        //
        //  Update the Lfcb to indicate that the other restart area
        //  on the disk is to be used.
        //

        Lfcb->InitialRestartArea = !Lfcb->InitialRestartArea;

        //
        //  Add this Lbcb to the end of the workque and flush to that point.
        //

        InsertTailList( &Lfcb->LbcbWorkque, &NewLbcb->WorkqueLinks );

        //
        //  If we don't support a packed log file then we need to make
        //  sure that all file records written out ahead of this
        //  restart area make it out to disk and we don't add anything
        //  to this page.
        //

        if (!FlagOn( Lfcb->Flags, LFCB_PACK_LOG )
            && !IsListEmpty( &Lfcb->LbcbActive )) {

            ActiveLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink,
                                            LBCB,
                                            ActiveLinks );

            if (FlagOn( ActiveLbcb->LbcbFlags, LBCB_NOT_EMPTY )) {

                RemoveEntryList( &ActiveLbcb->ActiveLinks );
                ClearFlag( ActiveLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE );
            }
        }

        if (WaitForIo) {

            LfsFlushLbcb( Lfcb, NewLbcb );
        }

    } finally {

        DebugUnwind( LfsWriteLfsRestart );

        if (NewRestart != NULL) {

            ExFreePool( NewRestart );
        }

        DebugTrace( -1, Dbg, "LfsWriteLfsRestart:  Exit\n", 0 );
    }

    return;
}
Beispiel #10
0
    ULONG                   dataSize;
    ULONG                   data;
    PUCHAR                  SA;
    PUCHAR                  DA;
    ULONG                   headerSize;
    PDOT11_DATA_LONG_HEADER dataHeader;

    // 
    // Note: only the first MDL is guaranteed to be mapped to system virtual space.
    //

    //
    // Find data header.
    //
    mdl = NET_BUFFER_CURRENT_MDL(NetBuffer);
    dataHeader = Add2Ptr(mdl->MappedSystemVa, NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer));

    //
    // Find SA, DA and header size.
    //
    if (dataHeader->FrameControl.ToDS)
    {
        DA = dataHeader->Address3;
        if (dataHeader->FrameControl.FromDS) 
        {
            headerSize = sizeof(DOT11_DATA_LONG_HEADER);
            SA = dataHeader->Address4;
        } 
        else 
        {
            headerSize = sizeof(DOT11_DATA_SHORT_HEADER);
Beispiel #11
0
VOID
CdConvertNameToCdName (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PCD_NAME CdName
    )

/*++

Routine Description:

    This routine is called to convert a string of bytes into a CdName.

    The full name is already in the CdName structure in the FileName field.
    We split this into the filename and version strings.

Arguments:

    CdName - Pointer to CdName structure to update.

Return Value:

    None.

--*/

{
    ULONG NameLength = 0;
    PWCHAR CurrentCharacter = CdName->FileName.Buffer;

    PAGED_CODE();

    UNREFERENCED_PARAMETER( IrpContext );

    //
    //  Look for a separator character.
    //

    while ((NameLength < CdName->FileName.Length) &&
           (*CurrentCharacter != L';')) {

        CurrentCharacter += 1;
        NameLength += 2;
    }

    //
    //  If there is at least one more character after a possible separator then it
    //  and all following characters are part of the version string.
    //

    CdName->VersionString.Length = 0;
    if (NameLength + sizeof( WCHAR ) < CdName->FileName.Length) {

        CdName->VersionString.MaximumLength =
        CdName->VersionString.Length = (USHORT) (CdName->FileName.Length - NameLength - sizeof( WCHAR ));
        CdName->VersionString.Buffer = Add2Ptr( CdName->FileName.Buffer,
                                                NameLength + sizeof( WCHAR ),
                                                PWCHAR );
    }

    //
    //  Now update the filename portion of the name.
    //

    CdName->FileName.Length = (USHORT) NameLength;

    return;
}
Beispiel #12
0
VOID
CdGenerate8dot3Name (
    IN PIRP_CONTEXT IrpContext,
    IN PUNICODE_STRING FileName,
    IN ULONG DirentOffset,
    OUT PWCHAR ShortFileName,
    OUT PUSHORT ShortByteCount
    )

/*++

Routine Description:

    This routine is called to generate a short name from the given long name.  We will
    generate a short name from the given long name.

    We go through the following steps to make this conversion.

        1 - Generate the generic short name.  This will also be in unicode format.

        2 - Build the string representation of the dirent offset.

        3 - Build the biased short name string by combining the generic short name with
            the dirent offset string.

        4 - Copy the final unicode string back to our caller's buffer.

Arguments:

    FileName - String of bytes containing the name.

    DirentOffset - Offset in the directory for this filename.  We incorporate the offset into
        the short name by dividing this by 32 and prepending a tilde character to the
        digit character.  We then append this to the base of the generated short name.

    ShortFileName - Pointer to the buffer to store the short name into.

    ShortByteCount - Address to store the number of bytes in the short name.

Return Value:

    None.

--*/

{
    NTSTATUS Status;

    UNICODE_STRING ShortName;
    UNICODE_STRING BiasedShortName;
    WCHAR ShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof( WCHAR ) ];
    WCHAR BiasedShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof( WCHAR ) ];

    GENERATE_NAME_CONTEXT NameContext;

    ULONG BiasedDirentOffset;

    ULONG MaximumBaseBytes;
    ULONG BaseNameOffset;

    PWCHAR NextWchar;
    WCHAR ThisWchar;
    USHORT Length;

    BOOLEAN FoundTilde = FALSE;

    PAGED_CODE();

    //
    //  Initialize the short string to use the input buffer.
    //

    ShortName.Buffer = ShortNameBuffer;
    ShortName.MaximumLength = BYTE_COUNT_8_DOT_3;

    //
    //  Initialize the name context.
    //

    RtlZeroMemory( &NameContext, sizeof( GENERATE_NAME_CONTEXT ));

    //
    //  We now have the unicode name for the input string.  Go ahead and generate
    //  the short name.
    //

    RtlGenerate8dot3Name( FileName, TRUE, &NameContext, &ShortName );

    //
    //  We now have the generic short name.  We want incorporate the dirent offset
    //  into the name in order to reduce the chance of name conflicts.  We will use
    //  a tilde character followed by a character representation of the dirent offset.
    //  This will be the hexadecimal representation of the dirent offset in the directory.
    //  It is actuall this offset divided by 32 since we don't need the full
    //  granularity.
    //

    BiasedDirentOffset = DirentOffset >> SHORT_NAME_SHIFT;

    //
    //  Point to a local buffer to store the offset string.  We start
    //  at the end of the buffer and work backwards.
    //

    NextWchar = Add2Ptr( BiasedShortNameBuffer,
                         BYTE_COUNT_8_DOT_3,
                         PWCHAR );

    BiasedShortName.MaximumLength = BYTE_COUNT_8_DOT_3;

    Length = 0;

    //
    //  Now add the characters for the dirent offset.  We need to start
    //  from the least significant digit and work backwards.
    //

    do {

        NextWchar -= 1;

        ThisWchar = (WCHAR) (BiasedDirentOffset & 0x0000000f);

        //
        //  Store in the next character.  Bias against either '0' or 'A'
        //

        if (ThisWchar <= 9) {

            *NextWchar = ThisWchar + L'0';

        } else {

            *NextWchar = ThisWchar + L'A' - 0xA;
        }

        Length += sizeof( WCHAR );

        //
        //  Shift out the low 4 bits of the offset.
        //

        BiasedDirentOffset >>= 4;

    } while (BiasedDirentOffset != 0);

    //
    //  Now store in the tilde character.
    //

    NextWchar -= 1;
    *NextWchar = L'~';
    Length += sizeof( WCHAR );

    //
    //  Set the length of this string.
    //

    BiasedShortName.Length = Length;
    BiasedShortName.Buffer = NextWchar;

    //
    //  Figure out the maximum number of characters we can copy of the base
    //  name.  We subract the number of characters in the dirent string from 8.
    //  We will copy this many characters or stop when we reach a '.' character
    //  or a '~' character in the name.
    //

    MaximumBaseBytes = 16 - Length;

    BaseNameOffset = 0;

    //
    //  Keep copying from the base name until we hit a '.', '~'  or the end of
    //  the short name.
    //

    NextWchar = ShortFileName;
    Length = 0;

    while ((BaseNameOffset < ShortName.Length) &&
           (ShortName.Buffer[BaseNameOffset / 2] != L'.')) {

        //
        //  Remember if we found a tilde character in the short name.
        //

        if (ShortName.Buffer[BaseNameOffset / 2] == L'~') {

            FoundTilde = TRUE;
        }

        //
        //  Only copy the bytes if we still have space for the dirent string.
        //

        if (!FoundTilde && (BaseNameOffset < MaximumBaseBytes)) {

            *NextWchar = ShortName.Buffer[BaseNameOffset / 2];
            Length += sizeof( WCHAR );
            NextWchar += 1;
        }

        BaseNameOffset += 2;
    }

    //
    //  Now copy the dirent string into the biased name buffer.
    //

    RtlCopyMemory( NextWchar,
                   BiasedShortName.Buffer,
                   BiasedShortName.Length );

    Length += BiasedShortName.Length;
    NextWchar += (BiasedShortName.Length / sizeof( WCHAR ));

    //
    //  Now copy any remaining bytes over to the biased short name.
    //

    if (BaseNameOffset != ShortName.Length) {

        RtlCopyMemory( NextWchar,
                       &ShortName.Buffer[BaseNameOffset / 2],
                       ShortName.Length - BaseNameOffset );

        Length += (ShortName.Length - (USHORT) BaseNameOffset);
    }

    //
    //  The final short name is stored in the user's buffer.
    //

    *ShortByteCount = Length;

    return;
}
Beispiel #13
0
VOID
CdDissectName (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PUNICODE_STRING RemainingName,
    OUT PUNICODE_STRING FinalName
    )

/*++

Routine Description:

    This routine is called to strip off leading components of the name strings.  We search
    for either the end of the string or separating characters.  The input remaining
    name strings should have neither a trailing or leading backslash.

Arguments:

    RemainingName - Remaining name.

    FinalName - Location to store next component of name.

Return Value:

    None.

--*/

{
    ULONG NameLength;
    PWCHAR NextWchar;

    PAGED_CODE();

    //
    //  Find the offset of the next component separators.
    //

    for (NameLength = 0, NextWchar = RemainingName->Buffer;
         (NameLength < RemainingName->Length) && (*NextWchar != L'\\');
         NameLength += sizeof( WCHAR) , NextWchar += 1);

    //
    //  Adjust all the strings by this amount.
    //

    FinalName->Buffer = RemainingName->Buffer;

    FinalName->MaximumLength = FinalName->Length = (USHORT) NameLength;

    //
    //  If this is the last component then set the RemainingName lengths to zero.
    //

    if (NameLength == RemainingName->Length) {

        RemainingName->Length = 0;

    //
    //  Otherwise we adjust the string by this amount plus the separating character.
    //

    } else {

        RemainingName->MaximumLength -= (USHORT) (NameLength + sizeof( WCHAR ));
        RemainingName->Length -= (USHORT) (NameLength + sizeof( WCHAR ));
        RemainingName->Buffer = Add2Ptr( RemainingName->Buffer,
                                         NameLength + sizeof( WCHAR ),
                                         PWCHAR );
    }

    return;
}
Beispiel #14
0
ULONG
NcCopyDirEnumEntry (
    _Out_ PVOID UserBuffer,
    _In_ ULONG UserOffset,
    _In_ ULONG UserSize,
    _Inout_ PNC_CACHE_ENTRY Entry,
    _In_ PDIRECTORY_CONTROL_OFFSETS Offsets,
    _Out_ PBOOLEAN Copied 
    )
/*++

Routine Description:

    This routine copies a single enumeration result into the caller's
    buffer.

Arguments:

    UserBuffer - Pointer to the caller's buffer.

    UserOffset - Offset within the caller's buffer that we intend to write new
        results.

    UserSize - Size of the caller's buffer, in bytes.

    Entry - Pointer to the directory entry that we intend to return.

    Offsets - Information describing the offsets for this enumeration class.

    Copied - Pointer to a boolean value indicating whether this routine copied
        a new entry or not.

Return Value:

    The new offset in the user buffer that any future copies should use.

--*/
{
    PVOID Element =        Add2Ptr( Entry->Buffer, Entry->CurrentOffset );
    PVOID Dest =           Add2Ptr( UserBuffer, UserOffset );
    ULONG ElementSize =    NcGetEntrySize( Element, Offsets );
    BOOLEAN LastElement =  (BOOLEAN)(NcGetNextEntryOffset( Element, Offsets ) == 0);

    PAGED_CODE();

    if (UserSize - UserOffset >= ElementSize) {

        //
        //  There is enough room for this element, so copy it.
        //

        RtlCopyMemory( Dest, Element, ElementSize );
        UserOffset += ElementSize;
        *Copied = TRUE;

        //
        //  Update Entry's Offset
        //

        if (LastElement) {

            //
            //  This was the last element in the entry, so we should clean the
            //  entry.
            //

            ExFreePoolWithTag( Entry->Buffer, NC_TAG );
            Entry->Buffer = NULL;
            Entry->CurrentOffset = 0;

            //
            //  The last element in cached entries have a NextEntryOffset of 0,
            //  make sure that we report the actual next entry offset.
            //

            NcSetNextEntryOffset( Dest, Offsets, FALSE );

        } else {

            //
            //  Entry has more elements, update offset counter.
            //

            Entry->CurrentOffset += ElementSize;
        }

    } else {

        //
        //  User buffer does not have enough space.
        //

        *Copied = FALSE;
    }

    return UserOffset;
}
Beispiel #15
0
//
// get redirection info
//
BOOLEAN BlRetrieveBIOSRedirectionInformation(__inout PLOADER_REDIRECTION_INFORMATION Info)
{
	//
	// find spcr table
	//
	PACPI_SPCR Spcr										= CONTAINING_RECORD(BlFindACPITable(ACPI_SPCR_SIGNATURE,sizeof(ACPI_SPCR)),ACPI_SPCR,Header);
	if(!Spcr)
		return FALSE;

	//
	// calc checksum
	//
	UCHAR CheckSum										= 0;
	for(ULONG i = 0; i < Spcr->Header.Length; i ++)
		CheckSum										+= *Add2Ptr(Spcr,i,PUCHAR);

	//
	// checksum should be zero
	//
	if(CheckSum)
		return FALSE;

	//
	// if the lower part is zero,it means spcr is disabled
	//
	if(!Spcr->BaseAddress.Address.LowPart)
		return FALSE;

	Info->Valid											= TRUE;
	Info->MemorySpace									= Spcr->BaseAddress.AddressSpaceID == 0;
	Info->PortNum										= 3;
	Info->PortAddress									= Spcr->BaseAddress.Address.LowPart;
	switch(Spcr->Baudrate)
	{
	case 7:
		Info->Baudrate									= 115200;
		break;

	case 6:
		Info->Baudrate									= 57600;
		break;

	case 4:
		Info->Baudrate									= 19200;
		break;

	default:
	case 3:
		Info->Baudrate									= 9600;
		break;
	}

	Info->StopBits										= Spcr->StopBits;
	Info->Parity										= Spcr->Parity;
	Info->TerminalType									= Spcr->TerminalType;

	if(Spcr->Header.Length >= sizeof(ACPI_SPCR))
	{
		Info->PciDeviceId								= Spcr->DeviceId;
		Info->PciVendorId								= Spcr->VendorId;
		Info->BusNumber									= Spcr->BusNumber;
		Info->DeviceNumber								= Spcr->DeviceNumber;
		Info->FunctionNumber							= Spcr->FunctionNumber;
		Info->Flags										= Spcr->Flags;
	}
	else
	{
		Info->PciDeviceId								= 0xffff;
		Info->PciVendorId								= 0xffff;
		Info->BusNumber									= 0;
		Info->DeviceNumber								= 0;
		Info->FunctionNumber							= 0;
		Info->Flags										= 0;
	}

	return TRUE;
}
Beispiel #16
0
FLT_PREOP_CALLBACK_STATUS
NcEnumerateDirectory (
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
    )
/*++

Routine Description:

    Routine is invoked when a directory enumeration is issued by the
    user.

Arguments:

    Data - Pointer to the filter CallbackData that is passed to us.

    FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
        opaque handles to this filter, instance, its associated volume and
        file object.

    CompletionContext - The context for the completion routine for this
        operation.

Return Value:

    The return value is the Status of the operation.

--*/
{
    //TODO WE SHOULD CONSIDER MOVING THIS TO POST BECAUSE NTFS WILL TAKE CARE
    //     OF SYNC.
    FLT_PREOP_CALLBACK_STATUS ReturnValue;
    NTSTATUS Status;

    PNC_INSTANCE_CONTEXT InstanceContext = NULL;
    PNC_STREAM_HANDLE_CONTEXT HandleContext = NULL;
    PNC_DIR_QRY_CONTEXT DirCtx = NULL;

    PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL;

    NC_PATH_OVERLAP RealOverlap;
    NC_PATH_OVERLAP UserOverlap;

    BOOLEAN Reset = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RESTART_SCAN );
    BOOLEAN FirstQuery;
    BOOLEAN Single = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RETURN_SINGLE_ENTRY );
    BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags,
                                         FO_OPENED_CASE_SENSITIVE );
    
    FILE_INFORMATION_CLASS InformationClass = 
        Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass;

    PVOID UserBuffer;
    ULONG BufferSize; //size for user and system buffers.

    BOOLEAN Unlock = FALSE;

    //Vars for moving data into user buffer.
    ULONG NumEntriesCopied;
    ULONG UserBufferOffset;
    ULONG LastEntryStart;
    BOOLEAN MoreRoom;
    PNC_CACHE_ENTRY NextEntry;

    DIRECTORY_CONTROL_OFFSETS Offsets;

    BOOLEAN FoundStructureOffsets;

    UNREFERENCED_PARAMETER( CompletionContext );

    PAGED_CODE();

    FLT_ASSERT( IoGetTopLevelIrp() == NULL );

    FoundStructureOffsets = NcDetermineStructureOffsets( &Offsets,
                                                         InformationClass );

    if (!FoundStructureOffsets) {

        Status = STATUS_INVALID_PARAMETER;
        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    //
    //  Get our instance context.
    //

    Status = FltGetInstanceContext( FltObjects->Instance,
                                    &InstanceContext );

    if (!NT_SUCCESS( Status )) {

        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    //
    //  Get the directory's name.
    //

    Status = NcGetFileNameInformation( Data,
                                       NULL,
                                       NULL,
                                       FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT,
                                       &FileNameInformation ); 

    if (!NT_SUCCESS( Status )) {

        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    Status = FltParseFileNameInformation( FileNameInformation );

    if (!NT_SUCCESS( Status )) {

        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    //
    //  See if the directory is parent of either mapping.
    //

    NcComparePath( &FileNameInformation->Name,
                   &InstanceContext->Mapping.UserMapping,
                   NULL,
                   IgnoreCase,
                   TRUE,
                   &UserOverlap );

    NcComparePath( &FileNameInformation->Name,
                   &InstanceContext->Mapping.RealMapping,
                   NULL,
                   IgnoreCase,
                   TRUE,
                   &RealOverlap );

    if (!(UserOverlap.Parent || RealOverlap.Parent )) {

        //
        //  We are not interested in this directory
        //  because it is not the parent of either
        //  mapping. This means we can just passthrough.
        //

        Status = STATUS_SUCCESS;
        ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
        goto NcEnumerateDirectoryCleanup;
    }

    Status = NcStreamHandleContextAllocAndAttach( FltObjects->Filter,
                                                  FltObjects->Instance,
                                                  FltObjects->FileObject,
                                                  &HandleContext );

    if (!NT_SUCCESS( Status )) {

        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    FLT_ASSERT( HandleContext != NULL );

    DirCtx = &HandleContext->DirectoryQueryContext;
    _Analysis_assume_( DirCtx != NULL );

    //
    //  Before looking at the context, we have to acquire the lock.
    //
    
    NcLockStreamHandleContext( HandleContext );
    Unlock = TRUE;

    //
    //  We don't allow multiple outstanding enumeration requests on
    //  a single handle.
    //
    //  TODO: This needs to change.
    //

    if (DirCtx->EnumerationOutstanding) {

        Status = STATUS_UNSUCCESSFUL;
        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;

    }

    DirCtx->EnumerationOutstanding = TRUE;

    //
    //  Now drop the lock.  We're protected by the EnumerationOutstanding
    //  flag; nobody else can muck with the enumeration context structure.
    //

    NcUnlockStreamHandleContext( HandleContext );
    Unlock = FALSE;

    //
    //  Now we need to initialize or clear the cache and query options.
    //
    
    Status = NcStreamHandleContextEnumSetup( DirCtx,
                                             InstanceContext,
                                             &Offsets,
                                             Data,
                                             FltObjects,
                                             UserOverlap,
                                             &FirstQuery );

    if (!NT_SUCCESS( Status )) {

        ReturnValue = FLT_PREOP_COMPLETE;
        goto NcEnumerateDirectoryCleanup;
    }

    //
    //  Prepare to populate the user buffer.
    //

    UserBuffer = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;

    BufferSize = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length;

    //
    //  Lets copy data into the user buffer.
    //

    NumEntriesCopied = 0;
    UserBufferOffset = 0;

    do {

        //
        //  If there is no cache entry, populate it.
        //

        if (DirCtx->Cache.Buffer == NULL) {

            Status = NcPopulateCacheEntry( FltObjects->Instance,
                                           FltObjects->FileObject,
                                           Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length,
                                           Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass,
                                           Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName,
                                           Reset,
                                           &DirCtx->Cache);

            //
            //  We only want to reset the cache once.
            //

            Reset = FALSE;

            //
            //  There was a problem populating cache, pass up to user.
            //

            if (!NT_SUCCESS( Status )) {

                ReturnValue = FLT_PREOP_COMPLETE;
                goto NcEnumerateDirectoryCleanup;
            }

        }

        NextEntry = NcDirEnumSelectNextEntry( DirCtx, &Offsets, IgnoreCase );

        if (NextEntry == NULL) {

            //
            //  There are no more entries.
            //

            break;
        }

        if (NcSkipName( &Offsets, 
                        DirCtx, 
                        RealOverlap, 
                        &InstanceContext->Mapping,
                        IgnoreCase )) {

            //
            //  This entry is the real mapping path. That means we have to mask it...
            //  We will say there is more room and continue.
            //

            MoreRoom = TRUE;

        } else {

            //
            //  We are keeping this entry!
            //

            try {

                LastEntryStart = UserBufferOffset;
                UserBufferOffset = NcCopyDirEnumEntry( UserBuffer,
                                                       UserBufferOffset,
                                                       BufferSize,
                                                       NextEntry,
                                                       &Offsets,
                                                       &MoreRoom );

            } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) {

                Status = STATUS_INVALID_USER_BUFFER;
                ReturnValue = FLT_PREOP_COMPLETE;
                goto NcEnumerateDirectoryCleanup;
            }

            if (MoreRoom) {

                NumEntriesCopied++;
            }

        }// end of "we are copying entry"

    } while (MoreRoom && 
             (Single ? (NumEntriesCopied < 1) : TRUE));

    if (NumEntriesCopied > 0) {

        //
        //  Now we know what the last entry in the user buffer is going to be.
        //  Set its NextEntryOffset to 0, so that the user knows its the last element.
        //

        try {

            NcSetNextEntryOffset( Add2Ptr(UserBuffer, LastEntryStart),
                                  &Offsets, 
                                  TRUE );

        } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) {

            Status = STATUS_INVALID_USER_BUFFER;
            ReturnValue = FLT_PREOP_COMPLETE;
            goto NcEnumerateDirectoryCleanup;
        }
    }

    //
    //  We finished copying data.
    //

    ReturnValue = FLT_PREOP_COMPLETE;

    if (NumEntriesCopied == 0) {

        if (FirstQuery) {

            Status = STATUS_NO_SUCH_FILE;

        } else {

            Status = STATUS_NO_MORE_FILES;
        }

    } else {

        Status = STATUS_SUCCESS;
    }

    ReturnValue = FLT_PREOP_COMPLETE;
    goto NcEnumerateDirectoryCleanup;

NcEnumerateDirectoryCleanup:

    if (ReturnValue == FLT_PREOP_COMPLETE) {
 
        //
        //  We need to write back results of query.
        //
 
        Data->IoStatus.Status = Status;
 
        if (NT_SUCCESS( Status )) {
 
            //success
            Data->IoStatus.Information = UserBufferOffset;

        } else {
 
            //failure
            Data->IoStatus.Information = 0;
        }
    }
 
    if (InstanceContext != NULL) {

        FltReleaseContext( InstanceContext );
    }
 
    if (DirCtx != NULL) {
        
        if (!Unlock) {
            NcLockStreamHandleContext( HandleContext );
            Unlock = TRUE;
        }

        FLT_ASSERT( DirCtx->EnumerationOutstanding );
        DirCtx->EnumerationOutstanding = FALSE;

        NcUnlockStreamHandleContext( HandleContext );
        Unlock = FALSE;

        FltReleaseContext( HandleContext );
    }

    FLT_ASSERT( !Unlock );
 
    if (FileNameInformation != NULL) {

        FltReleaseFileNameInformation( FileNameInformation );
    }
 
    return ReturnValue;
}
Beispiel #17
0
//
// find rsdp
//
VOID BlFindRsdp()
{
	for(ULONG i = 0; i < 2; i ++)
	{
		PULONGLONG Start								= 0;
		PULONGLONG End									= 0;
		PHYSICAL_ADDRESS MapStart;

		//
		// search Extended BIOS Data Area segment first
		//
		if(i == 0)
		{
			MapStart.QuadPart							= 0;
			PUSHORT FirstPage							= static_cast<PUSHORT>(MmMapIoSpace(MapStart,0x1000,MmNonCached));

			//
			// 0x40e is the Extended BIOS Data Area Segment
			//
			if(FirstPage[0x40e / sizeof(USHORT)])
			{
				//
				// get flat address by left-shifting 4 bit
				//
				MapStart.QuadPart						= FirstPage[0x40e / sizeof(USHORT)] << 4;
				Start									= static_cast<PULONGLONG>(MmMapIoSpace(MapStart,0x2000,MmNonCached));
				End										= Start + 0x400 / sizeof(ULONGLONG);
			}
		}
		else
		{
			MapStart.QuadPart							= 0xe0000;
			Start										= static_cast<PULONGLONG>(MmMapIoSpace(MapStart,0x1ffff,MmNonCached));
			End											= Start + 0x1ffff / sizeof(ULONGLONG);
		}

		//
		// search rsdp
		//
		for(; Start < End; Start ++)
		{
			if(*Start == ACPI_RSDP_SIGNATURE)
			{
				//
				// found it,checksum must be zero
				//
				UCHAR Checksum							= 0;
				for(ULONG i = 0; i < sizeof(ACPI_RSDP); i ++)
					Checksum							+= *Add2Ptr(Start,i,PUCHAR);

				//
				// valid rsdp found,save it
				//
				if(!Checksum)
				{
					BlRsdp								= Add2Ptr(Start,0,PACPI_RSDP);

					//
					// map header
					//
					MapStart.QuadPart					= BlRsdp->RsdtAddress;
					BlRsdt								= static_cast<PACPI_RSDT>(MmMapIoSpace(MapStart,sizeof(ACPI_DESCRIPTION_HEADER),MmNonCached));

					//
					// map the whole table
					//
					BlRsdt								= static_cast<PACPI_RSDT>(MmMapIoSpace(MapStart,BlRsdt->Header.Length,MmNonCached));

					return;
				}
			}
		}
	}

	BlRsdp												= 0;
	BlRsdt												= 0;
}
Beispiel #18
0
PNC_CACHE_ENTRY
NcDirEnumSelectNextEntry( 
    _Inout_ PNC_DIR_QRY_CONTEXT Context, 
    _In_ PDIRECTORY_CONTROL_OFFSETS Offsets,
    _In_ BOOLEAN IgnoreCase
    )
/*++

Routine Description:

    This routine determines whether the cached entry (returned from the
    filesystem) should be returned now or whether the injected entry (as a
    result of our mapping) should be returned now.

Arguments:

    Context - The enumeration context of this handle.

    Offsets - Information describing the offsets for this enumeration class.

    IgnoreCase - TRUE if we are case insensitive, FALSE if case sensitive.

Return Value:

    A pointer to the entry we should return, or NULL if there is nothing
    remaining to return.

--*/
{
    PNC_CACHE_ENTRY NextEntry;
    UNICODE_STRING CacheString;
    UNICODE_STRING InsertString;
    PVOID CacheEntry;
    PVOID InjectEntry;

    PAGED_CODE();

    //
    //  Figure out which name comes first
    //

    if ((Context->Cache.Buffer == NULL) && 
        (Context->InjectionEntry.Buffer == NULL)) {

        //
        //  There are no names left, return STATUS_NO_MORE_FILES
        //

        NextEntry = NULL;

    } else if (Context->Cache.Buffer == NULL) {

        //
        //  The cache is empty, so inject.
        //

        NextEntry = &Context->InjectionEntry;

    } else if (Context->InjectionEntry.Buffer == NULL) {

        //
        //  The injection entry is empty, drain the cache.
        //

        NextEntry = &Context->Cache;

    } else {

        //
        //  We have to seek in the entry buffer to the current entry within the buffer.
        //

        CacheEntry = Add2Ptr( Context->Cache.Buffer, Context->Cache.CurrentOffset );
        InjectEntry = Add2Ptr( Context->InjectionEntry.Buffer, Context->InjectionEntry.CurrentOffset );

        //
        //  Find names within the entries.
        //

        CacheString.Buffer = NcGetFileName( CacheEntry, Offsets );
        CacheString.Length = (USHORT) NcGetFileNameLength( CacheEntry, Offsets );
        CacheString.MaximumLength = CacheString.Length;

        InsertString.Buffer = NcGetFileName( InjectEntry, Offsets );
        InsertString.Length = (USHORT) NcGetFileNameLength( InjectEntry, Offsets );
        InsertString.MaximumLength = InsertString.Length;

        //
        //  Compare the names
        //

        if (RtlCompareUnicodeString( &CacheString,
                                     &InsertString,
                                     IgnoreCase ) < 0) {

            //
            //  Cache string comes first
            //

            NextEntry = &Context->Cache;

        } else {

            //
            //  insert string comes first
            //

            NextEntry = &Context->InjectionEntry;
        }
    }
    return NextEntry;
}
Beispiel #19
0
BOOLEAN
NtfsCheckAttributeRecord (
    IN PVCB Vcb,
    IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
    IN PATTRIBUTE_RECORD_HEADER Attribute,
    IN ULONG CheckHeaderOnly,
    IN PULONG CorruptionHint
    )

{
    PVOID NextAttribute;
    PVOID EndOfFileRecord;
    PVOID FirstFreeByte;
    PVOID Data;
    ULONG Length;
    ULONG BytesPerFileRecordSegment = Vcb->BytesPerFileRecordSegment;

    PAGED_CODE();

    EndOfFileRecord = Add2Ptr( FileRecord, BytesPerFileRecordSegment );
    FirstFreeByte = Add2Ptr( FileRecord, FileRecord->FirstFreeByte );

    //
    //  Do an alignment check before creating a ptr based on this value
    //

    if (!IsQuadAligned( Attribute->RecordLength )) {

        *CorruptionHint = Attribute->TypeCode + 0xc;
        ASSERTMSG( "Misaligned attribute length\n", FALSE );
        return FALSE;
    }

    NextAttribute = NtfsGetNextRecord(Attribute);

    //
    //  Check the fixed part of the attribute record header.
    //

    if ((Attribute->RecordLength >= BytesPerFileRecordSegment)

            ||

        (NextAttribute >= EndOfFileRecord)

            ||

        (FlagOn(Attribute->NameOffset, 1) != 0)

            ||

        ((Attribute->NameLength != 0) &&
         (((ULONG)Attribute->NameOffset + (ULONG)Attribute->NameLength) >
           Attribute->RecordLength))) {

        DebugTrace( 0, 0, ("Invalid attribute record header: %08lx\n", Attribute) );

        *CorruptionHint = Attribute->TypeCode + 1;
        ASSERTMSG( "Invalid attribute record header\n", FALSE );
        return FALSE;
    }

    if (NextAttribute > FirstFreeByte) {
        *CorruptionHint = Attribute->TypeCode + 2;
        ASSERTMSG( "Attributes beyond first free byte\n", FALSE );
        return FALSE;
    }

    //
    //  Check the resident attribute fields.
    //

    if (Attribute->FormCode == RESIDENT_FORM) {

        if ((Attribute->Form.Resident.ValueLength >= Attribute->RecordLength) ||

            (((ULONG)Attribute->Form.Resident.ValueOffset +
              Attribute->Form.Resident.ValueLength) > Attribute->RecordLength) ||

            (!IsQuadAligned( Attribute->Form.Resident.ValueOffset ))) {

            DebugTrace( 0, 0, ("Invalid resident attribute record header: %08lx\n", Attribute) );

            *CorruptionHint = Attribute->TypeCode + 3;
            ASSERTMSG( "Invalid resident attribute record header\n", FALSE );
            return FALSE;
        }

    //
    //  Check the nonresident attribute fields
    //

    } else if (Attribute->FormCode == NONRESIDENT_FORM) {

        VCN CurrentVcn, NextVcn;
        LCN CurrentLcn;
        LONGLONG Change;
        PCHAR ch;
        ULONG VcnBytes;
        ULONG LcnBytes;

        if ((Attribute->Form.Nonresident.LowestVcn >
                (Attribute->Form.Nonresident.HighestVcn + 1))

                ||

            ((ULONG)Attribute->Form.Nonresident.MappingPairsOffset >=
                Attribute->RecordLength)

                ||

            (Attribute->Form.Nonresident.ValidDataLength < 0) ||
            (Attribute->Form.Nonresident.FileSize < 0) ||
            (Attribute->Form.Nonresident.AllocatedLength < 0)

                ||

            (Attribute->Form.Nonresident.ValidDataLength >
                Attribute->Form.Nonresident.FileSize)

                ||

            (Attribute->Form.Nonresident.FileSize >
                Attribute->Form.Nonresident.AllocatedLength)) {

            DebugTrace( 0, 0, ("Invalid nonresident attribute record header: %08lx\n", Attribute) );

            *CorruptionHint = Attribute->TypeCode + 4;
            ASSERTMSG( "Invalid nonresident attribute record header\n", FALSE );
            return FALSE;
        }

        if (CheckHeaderOnly) { return TRUE; }

        //
        //  Implement the decompression algorithm, as defined in ntfs.h.
        //  (This code should look remarkably similar to what goes on in
        //  NtfsLookupAllocation!)
        //

        NextVcn = Attribute->Form.Nonresident.LowestVcn;
        CurrentLcn = 0;
        ch = (PCHAR)Attribute + Attribute->Form.Nonresident.MappingPairsOffset;

        //
        //  Loop to process mapping pairs, insuring we do not run off the end
        //  of the attribute, and that we do not map to nonexistant Lcns.
        //

        while (!IsCharZero(*ch)) {

            //
            // Set Current Vcn from initial value or last pass through loop.
            //

            CurrentVcn = NextVcn;

            //
            //  Extract the counts from the two nibbles of this byte.
            //

            VcnBytes = *ch & 0xF;
            LcnBytes = *ch++ >> 4;

            //
            //  Neither of these should be larger than a VCN.
            //

            if ((VcnBytes > sizeof( VCN )) ||
                (LcnBytes > sizeof( VCN ))) {

                DebugTrace( 0, 0, ("Invalid maping pair byte count: %08lx\n", Attribute) );

                *CorruptionHint = Attribute->TypeCode + 5;
                ASSERTMSG( "Invalid maping pair byte count\n", FALSE );
                return FALSE;
            }

            //
            //  Extract the Vcn change (use of RtlCopyMemory works for little-Endian)
            //  and update NextVcn.
            //

            Change = 0;

            //
            //  Make sure we are not going beyond the end of the attribute
            //  record, and that the Vcn change is not negative or zero.
            //

            if (((ULONG_PTR)(ch + VcnBytes + LcnBytes + 1) > (ULONG_PTR)NextAttribute)

                    ||

                IsCharLtrZero(*(ch + VcnBytes - 1))) {

                DebugTrace( 0, 0, ("Invalid maping pairs array: %08lx\n", Attribute) );

                *CorruptionHint = Attribute->TypeCode + 6;
                ASSERTMSG( "Invalid maping pairs array\n", FALSE );
                return FALSE;
            }

            RtlCopyMemory( &Change, ch, VcnBytes );
            ch += VcnBytes;
            NextVcn = NextVcn + Change;

            //
            //  Extract the Lcn change and update CurrentLcn.
            //

            Change = 0;
            if (IsCharLtrZero(*(ch + LcnBytes - 1))) {
                Change = Change - 1;
            }
            RtlCopyMemory( &Change, ch, LcnBytes );
            ch += LcnBytes;
            CurrentLcn = CurrentLcn + Change;

            if ((LcnBytes != 0) &&
                ((CurrentLcn + (NextVcn - CurrentVcn) - 1) > Vcb->TotalClusters)) {

                DebugTrace( 0, 0, ("Invalid Lcn: %08lx\n", Attribute) );

                *CorruptionHint = Attribute->TypeCode + 7;
                ASSERTMSG( "Invalid Lcn\n", FALSE );
                return FALSE;
            }
        }

        //
        //  Finally, check HighestVcn.
        //

        if (NextVcn != (Attribute->Form.Nonresident.HighestVcn + 1)) {

            DebugTrace( 0, 0, ("Disagreement with mapping pairs: %08lx\n", Attribute) );

            *CorruptionHint = Attribute->TypeCode + 8;
            ASSERTMSG( "Disagreement with mapping pairs\n", FALSE );
            return FALSE;
        }

    } else {
Beispiel #20
0
VOID
LfsReadLogRecord (
    IN LFS_LOG_HANDLE LogHandle,
    IN LSN FirstLsn,
    IN LFS_CONTEXT_MODE ContextMode,
    OUT PLFS_LOG_CONTEXT Context,
    OUT PLFS_RECORD_TYPE RecordType,
    OUT TRANSACTION_ID *TransactionId,
    OUT PLSN UndoNextLsn,
    OUT PLSN PreviousLsn,
    OUT PULONG BufferLength,
    OUT PVOID *Buffer
    )

/*++

Routine Description:

    This routine initiates the query operation.  It returns the log record
    in question and a context structure used by the Lfs to return related
    log records.  The caller specifies what mode of query to use.  He may
    walk backwards through the file by Undo records or all records for
    this client linked through the previous Lsn fields.  He may also look
    forwards through the file for all records for the issuing client.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

    FirstLsn - Starting record for this query operation.

    ContextMode - Method of query.

    Context - Supplies the address to store a pointer to the Lfs created
              context structure.

    RecordType - Supplies the address to store the record type of this
                 log record.

    TransactionId - Supplies the address to store the transaction Id of
                    this log record.

    UndoNextLsn - Supplies the address to store the Undo Next Lsn for this
                  log record.

    PreviousLsn - Supplies the address to store the Previous Lsn for this
                  log record.

    BufferLength - This is the length of the log data.

    Buffer - This is a pointer to the start of the log data.

Return Value:

    None

--*/

{
    volatile NTSTATUS Status = STATUS_SUCCESS;

    PLFS_CLIENT_RECORD ClientRecord;

    PLCH Lch;

    PLFCB Lfcb;

    PLCB Lcb = NULL;

    PAGED_CODE();

    DebugTrace( +1, Dbg, "LfsReadLogRecord:  Entered\n", 0 );
    DebugTrace(  0, Dbg, "Log Handle        -> %08lx\n", LogHandle );
    DebugTrace(  0, Dbg, "First Lsn (Low)   -> %08lx\n", FirstLsn.LowPart );
    DebugTrace(  0, Dbg, "First Lsn (High)  -> %08lx\n", FirstLsn.HighPart );
    DebugTrace(  0, Dbg, "Context Mode      -> %08lx\n", ContextMode );

    Lch = (PLCH) LogHandle;

    //
    //  Check that the context mode is valid.
    //

    switch (ContextMode) {

    case LfsContextUndoNext :
    case LfsContextPrevious :
    case LfsContextForward :

        break;

    default:

        DebugTrace( 0, Dbg, "Invalid context mode -> %08x\n", ContextMode );
        ExRaiseStatus( STATUS_INVALID_PARAMETER );
    }

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-except to catch errors.
    //

    try {

        //
        //  Use a try-finally to facilitate cleanup.
        //

        try {

            //
            //  Acquire the log file control block for this log file.
            //

            LfsAcquireLch( Lch );
            Lfcb = Lch->Lfcb;

            //
            //  If the Log file has been closed then refuse access.
            //

            if (Lfcb == NULL) {

                ExRaiseStatus( STATUS_ACCESS_DENIED );
            }

            //
            //  Check that the client Id is valid.
            //

            LfsValidateClientId( Lfcb, Lch );

            //
            //  Check that the given Lsn is in the legal range for this client.
            //

            ClientRecord = Add2Ptr( Lfcb->ClientArray,
                                    Lch->ClientArrayByteOffset,
                                    PLFS_CLIENT_RECORD );

            if (!LfsVerifyClientLsnInRange( Lfcb, ClientRecord, FirstLsn )) {

                ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
            }

            //
            //  We can give up the Lfcb as we know the Lsn is within the file.
            //

            LfsReleaseLch( Lch );

            //
            //  Allocate and initialize a context structure.
            //

            LfsAllocateLcb( &Lcb );

            LfsInitializeLcb( Lcb,
                              Lch->ClientId,
                              ContextMode );

            //
            //  Find the log record indicated by the given Lsn.
            //

            LfsFindLogRecord( Lfcb,
                              Lcb,
                              FirstLsn,
                              RecordType,
                              TransactionId,
                              UndoNextLsn,
                              PreviousLsn,
                              BufferLength,
                              Buffer );

            //
            //  Update the client's arguments.
            //

            *Context = Lcb;
            Lcb = NULL;

        } finally {

            DebugUnwind( LfsReadLogRecord );

            //
            //  Release the log file control block if held.
            //

            LfsReleaseLch( Lch );

            //
            //  Deallocate the context block if an error occurred.
            //

            if (Lcb != NULL) {

                LfsDeallocateLcb( Lcb );
            }

            DebugTrace(  0, Dbg, "Context       -> %08lx\n", *Context );
            DebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
            DebugTrace(  0, Dbg, "Buffer        -> %08lx\n", *Buffer );
            DebugTrace( -1, Dbg, "LfsReadLogRecord:  Exit\n", 0 );
        }

    } except (LfsExceptionFilter( GetExceptionInformation() )) {

        Status = GetExceptionCode();
    }

    if (Status != STATUS_SUCCESS) {

        ExRaiseStatus( Status );
    }

    return;
}
Beispiel #21
0
BOOLEAN
NtfsCheckFileRecord (
    IN PVCB Vcb,
    IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
    IN PFILE_REFERENCE FileReference OPTIONAL,
    OUT PULONG CorruptionHint
    )

/*++

Routine Description:

    Consistency check for file records.

Arguments:

    Vcb - the vcb it belongs to

    FileRecord - the filerecord to check

    FileReference - if specified double check the sequence number and self ref.
        fileref against it

    CorruptionHint - hint for debugging on where corruption occured;

Return Value:

    FALSE - if the file record is not valid
    TRUE - if it is

--*/
{
    PATTRIBUTE_RECORD_HEADER Attribute;
    PFILE_RECORD_SEGMENT_HEADER EndOfFileRecord;
    ULONG BytesPerFileRecordSegment = Vcb->BytesPerFileRecordSegment;
    BOOLEAN StandardInformationSeen = FALSE;
    ULONG BytesInOldHeader;

    PAGED_CODE();

    *CorruptionHint = 0;

    EndOfFileRecord = Add2Ptr( FileRecord, BytesPerFileRecordSegment );

    //
    //  Check the file record header for consistency.
    //

    if ((*(PULONG)FileRecord->MultiSectorHeader.Signature != *(PULONG)FileSignature)

            ||

        ((ULONG)FileRecord->MultiSectorHeader.UpdateSequenceArrayOffset >
         (SEQUENCE_NUMBER_STRIDE -
          (PAGE_SIZE / SEQUENCE_NUMBER_STRIDE + 1) * sizeof(USHORT)))

            ||

        ((ULONG)((FileRecord->MultiSectorHeader.UpdateSequenceArraySize - 1) * SEQUENCE_NUMBER_STRIDE) !=
         BytesPerFileRecordSegment)

            ||

        !FlagOn(FileRecord->Flags, FILE_RECORD_SEGMENT_IN_USE)) {

        DebugTrace( 0, 0, ("Invalid file record: %08lx\n", FileRecord) );

        *CorruptionHint = 1;
#if !__NDAS_NTFS_SECONDARY__
        ASSERTMSG( "Invalid resident file record\n", FALSE );
#endif
        return FALSE;
    }

    BytesInOldHeader = QuadAlign( sizeof( FILE_RECORD_SEGMENT_HEADER_V0 ) + (UpdateSequenceArraySize( BytesPerFileRecordSegment ) - 1) * sizeof( USHORT ));

    //
    //  Offset bounds checks
    //

    if ((FileRecord->FirstFreeByte > BytesPerFileRecordSegment) ||
        (FileRecord->FirstFreeByte < BytesInOldHeader) ||

        (FileRecord->BytesAvailable != BytesPerFileRecordSegment) ||

        (((ULONG)FileRecord->FirstAttributeOffset < BytesInOldHeader)   ||
         ((ULONG)FileRecord->FirstAttributeOffset >
                 BytesPerFileRecordSegment - SIZEOF_RESIDENT_ATTRIBUTE_HEADER)) ||

        (!IsQuadAligned( FileRecord->FirstAttributeOffset ))) {

        *CorruptionHint = 2;
        ASSERTMSG( "Out of bound offset in frs\n", FALSE );
        return FALSE;
    }

    //
    //  Optional fileref number check
    //

    if (ARGUMENT_PRESENT( FileReference )) {

        if ((FileReference->SequenceNumber != FileRecord->SequenceNumber) ||
            ((FileRecord->FirstAttributeOffset > BytesInOldHeader) &&
             ((FileRecord->SegmentNumberHighPart != FileReference->SegmentNumberHighPart) ||
              (FileRecord->SegmentNumberLowPart != FileReference->SegmentNumberLowPart)))) {

            *CorruptionHint = 3;
            ASSERTMSG( "Filerecord fileref doesn't match expected value\n", FALSE );
            return FALSE;
        }
    }

    //
    //  Loop to check all of the attributes.
    //

    for (Attribute = NtfsFirstAttribute(FileRecord);
         Attribute->TypeCode != $END;
         Attribute = NtfsGetNextRecord(Attribute)) {

//      if (!StandardInformationSeen &&
//          (Attribute->TypeCode != $STANDARD_INFORMATION) &&
//          XxEqlZero(FileRecord->BaseFileRecordSegment)) {
//
//          DebugTrace( 0, 0, ("Standard Information missing: %08lx\n", Attribute) );
//
//          ASSERTMSG( "Standard Information missing\n", FALSE );
//          return FALSE;
//      }

        StandardInformationSeen = TRUE;

        if (!NtfsCheckAttributeRecord( Vcb,
                                       FileRecord,
                                       Attribute,
                                       FALSE,
                                       CorruptionHint )) {

            return FALSE;
        }
    }
    return TRUE;
}
Beispiel #22
0
VOID
LfsWriteRestartArea (
    IN LFS_LOG_HANDLE LogHandle,
    IN ULONG BufferLength,
    IN PVOID Buffer,
    OUT PLSN Lsn
    )

/*++

Routine Description:

    This routine is called by the client to write a restart area to the
    disk.  This routine will not return to the caller until the client
    restart area and all prior Lsn's have been flushed and the Lfs
    restart area on the disk has been updated.

    On return, all log records up to and including 'Lsn' have been flushed
    to the disk.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

    BufferLength - On entry it is the length of the user buffer.

    Buffer - Pointer to the buffer where the client restart data resides.

    Lsn - This is the Lsn for this write operation.  On input, this will be the
          new Base Lsn for this client.

          ****  This was used to prevent adding an interface change to
                the Beta release.

Return Value:

    None

--*/

{
    volatile NTSTATUS Status = STATUS_SUCCESS;

    PLCH Lch;

    PLFCB Lfcb;

    PLFS_CLIENT_RECORD ClientRecord;

    LFS_WRITE_ENTRY WriteEntry;

    PAGED_CODE();

    DebugTrace( +1, Dbg, "LfsWriteRestartArea:  Entered\n", 0 );
    DebugTrace(  0, Dbg, "Log Handle    -> %08lx\n", LogHandle );
    DebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", BufferLength );
    DebugTrace(  0, Dbg, "Buffer        -> %08lx\n", Buffer );

    Lch = (PLCH) LogHandle;

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-except to catch errors.
    //

    try {

        //
        //  Use a try-finally to facilitate cleanup.
        //

        try {

            //
            //  Acquire the log file control block for this log file.
            //

            LfsAcquireLch( Lch );
            Lfcb = Lch->Lfcb;

            //
            //  If the Log file has been closed then refuse access.
            //

            if (Lfcb == NULL) {

                ExRaiseStatus( STATUS_ACCESS_DENIED );
            }

            //
            //  Check that the client Id is valid.
            //

            LfsValidateClientId( Lfcb, Lch );

            ClientRecord = Add2Ptr( Lfcb->ClientArray,
                                    Lch->ClientArrayByteOffset,
                                    PLFS_CLIENT_RECORD );

            //
            //  Go ahead and update the Base Lsn in the client area if the value
            //  given is not zero.
            //

            if ( Lsn->QuadPart != 0 ) {                                                                                //**** xxNeqZero( *Lsn )

                LfsSetBaseLsnPriv( Lfcb,
                                   ClientRecord,
                                   *Lsn );
            }

            //
            //  Write this restart area as a log record into a log page.
            //

            WriteEntry.Buffer = Buffer;
            WriteEntry.ByteLength = BufferLength;

            LfsWriteLogRecordIntoLogPage( Lfcb,
                                          Lch,
                                          1,
                                          &WriteEntry,
                                          LfsClientRestart,
                                          NULL,
                                          LfsZeroLsn,
                                          LfsZeroLsn,
                                          0,
                                          TRUE,
                                          Lsn );

            //
            //  Update the restart area for the client.
            //

            ClientRecord->ClientRestartLsn = *Lsn;

            //
            //  Write the restart area to the disk.
            //

            LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, TRUE );

        } finally {

            DebugUnwind( LfsWriteRestartArea );

            //
            //  Release the log file control block if still held.
            //

            LfsReleaseLch( Lch );

            DebugTrace(  0, Dbg, "Lsn (Low)     -> %08lx\n", Lsn->LowPart );
            DebugTrace(  0, Dbg, "Log (High)    -> %08lx\n", Lsn->HighPart );
            DebugTrace( -1, Dbg, "LfsWriteRestartArea:  Exit\n", 0 );
        }

    } except (LfsExceptionFilter( GetExceptionInformation() )) {

        Status = GetExceptionCode();
    }

    if (Status != STATUS_SUCCESS) {

        ExRaiseStatus( Status );
    }

    return;
}
Beispiel #23
0
DWORD
WINAPI
RetrieveLogRecords(
    __in LPVOID lpParameter
    )
/*++

Routine Description:

    This runs as a separate thread.  Its job is to retrieve log records
    from the filter and then output them

Arguments:

    lpParameter - Contains context structure for synchronizing with the
        main program thread.

Return Value:

    The thread successfully terminated

--*/
{
    PLOG_CONTEXT context = (PLOG_CONTEXT)lpParameter;
    DWORD bytesReturned = 0;
    DWORD used;
    PVOID alignedBuffer[BUFFER_SIZE/sizeof( PVOID )];
    PCHAR buffer = (PCHAR) alignedBuffer;
    HRESULT hResult;
    PLOG_RECORD pLogRecord;
    PRECORD_DATA pRecordData;
    COMMAND_MESSAGE commandMessage;

    //printf("Log: Starting up\n");

    while (TRUE) {

        //
        //  Check to see if we should shut down.
        //

        if (context->CleaningUp) {

            break;
        }

        //
        //  Request log data from MiniSpy.
        //

        commandMessage.Command = GetMiniSpyLog;

        hResult = FilterSendMessage( context->Port,
                                     &commandMessage,
                                     sizeof( COMMAND_MESSAGE ),
                                     buffer,
                                     sizeof(alignedBuffer),
                                     &bytesReturned );

        if (IS_ERROR( hResult )) {

            if (HRESULT_FROM_WIN32( ERROR_INVALID_HANDLE ) == hResult) {

                printf( "The kernel component of minispy has unloaded. Exiting\n" );
                ExitProcess( 0 );
            } else {

                if (hResult != HRESULT_FROM_WIN32( ERROR_NO_MORE_ITEMS )) {

                    printf( "UNEXPECTED ERROR received: %x\n", hResult );
                }

                Sleep( POLL_INTERVAL );
            }

            continue;
        }

        //
        //  Buffer is filled with a series of LOG_RECORD structures, one
        //  right after another.  Each LOG_RECORD says how long it is, so
        //  we know where the next LOG_RECORD begins.
        //

        pLogRecord = (PLOG_RECORD) buffer;
        used = 0;

        //
        //  Logic to write record to screen and/or file
        //

        for (;;) {

            if (used+FIELD_OFFSET(LOG_RECORD,Name) > bytesReturned) {

                break;
            }

            if (pLogRecord->Length < (sizeof(LOG_RECORD)+sizeof(WCHAR))) {

                printf( "UNEXPECTED LOG_RECORD->Length: length=%d expected>=%d\n",
                        pLogRecord->Length,
                        (sizeof(LOG_RECORD)+sizeof(WCHAR)));

                break;
            }

            used += pLogRecord->Length;

            if (used > bytesReturned) {

                printf( "UNEXPECTED LOG_RECORD size: used=%d bytesReturned=%d\n",
                        used,
                        bytesReturned);

                break;
            }

            pRecordData = &pLogRecord->Data;

            //
            //  See if a reparse point entry
            //

            if (FlagOn(pLogRecord->RecordType,RECORD_TYPE_FILETAG)) {

                if (!TranslateFileTag( pLogRecord )){

                    //
                    // If this is a reparse point that can't be interpreted, move on.
                    //

                    pLogRecord = (PLOG_RECORD)Add2Ptr(pLogRecord,pLogRecord->Length);
                    continue;
                }
            }

            if (context->LogToScreen) {

                ScreenDump( pLogRecord->SequenceNumber,
                            pLogRecord->Name,
                            pRecordData );
            }

            if (context->LogToFile) {

                FileDump( pLogRecord->SequenceNumber,
                          pLogRecord->Name,
                          pRecordData,
                          context->OutputFile );
            }

            //
            //  The RecordType could also designate that we are out of memory
            //  or hit our program defined memory limit, so check for these
            //  cases.
            //

            if (FlagOn(pLogRecord->RecordType,RECORD_TYPE_FLAG_OUT_OF_MEMORY)) {

                if (context->LogToScreen) {

                    printf( "M %08X SYSTEM OUT OF MEMORY\n",
                            pLogRecord->SequenceNumber );
                }

                if (context->LogToFile) {

                    fprintf( context->OutputFile,
                             "M:\t%u",
                             pLogRecord->SequenceNumber );
                }

            } else if (FlagOn(pLogRecord->RecordType,RECORD_TYPE_FLAG_EXCEED_MEMORY_ALLOWANCE)) {

                if (context->LogToScreen) {

                    printf( "M %08X EXCEEDED MEMORY ALLOWANCE\n",
                            pLogRecord->SequenceNumber );
                }

                if (context->LogToFile) {

                    fprintf( context->OutputFile,
                             "M:\t%u",
                             pLogRecord->SequenceNumber );
                }
            }

            //
            // Move to next LOG_RECORD
            //

            pLogRecord = (PLOG_RECORD)Add2Ptr(pLogRecord,pLogRecord->Length);
        }

        //
        //  If we didn't get any data, pause for 1/2 second
        //

        if (bytesReturned == 0) {

            Sleep( POLL_INTERVAL );
        }
    }

    printf( "Log: Shutting down\n" );
    ReleaseSemaphore( context->ShutDown, 1, NULL );
    printf( "Log: All done\n" );
    return 0;
}
Beispiel #24
0
VOID
LfsSetBaseLsn (
    IN LFS_LOG_HANDLE LogHandle,
    IN LSN BaseLsn
    )

/*++

Routine Description:

    This routine is called by the client to notify the log service of the
    oldest Lsn he expects to need during restart.  The Lfs is allowed to
    reuse any part of the circular log file which logically precedes
    this Lsn.  A client may only specify a Lsn which follows the previous
    Lsn specified by this client.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

    BaseLsn - This is the oldest Lsn the client may require during a
              restart.

Return Value:

    None

--*/

{
    volatile NTSTATUS Status = STATUS_SUCCESS;

    PLCH Lch;

    PLFCB Lfcb;

    PLFS_CLIENT_RECORD ClientRecord;

    PAGED_CODE();

    DebugTrace( +1, Dbg, "LfsSetBaseLsn:  Entered\n", 0 );
    DebugTrace(  0, Dbg, "Log Handle        -> %08lx\n", LogHandle );
    DebugTrace(  0, Dbg, "Base Lsn (Low)    -> %08lx\n", BaseLsn.LowPart );
    DebugTrace(  0, Dbg, "Base Lsn (High)   -> %08lx\n", BaseLsn.HighPart );

    Lch = (PLCH) LogHandle;

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-except to catch errors.
    //

    try {

        //
        //  Use a try-finally to facilitate cleanup.
        //

        try {

            //
            //  Acquire the log file control block for this log file.
            //

            LfsAcquireLch( Lch );
            Lfcb = Lch->Lfcb;

            //
            //  If the Log file has been closed then refuse access.
            //

            if (Lfcb == NULL) {

                ExRaiseStatus( STATUS_ACCESS_DENIED );
            }

            //
            //  Check that the client Id is valid.
            //

            LfsValidateClientId( Lfcb, Lch );

            ClientRecord = Add2Ptr( Lfcb->ClientArray,
                                    Lch->ClientArrayByteOffset,
                                    PLFS_CLIENT_RECORD );

            //
            //  We simply call the worker routine to advance the base lsn.
            //  If we moved forward in the file, we will put our restart area in the
            //  queue.
            //

            LfsSetBaseLsnPriv( Lfcb,
                               ClientRecord,
                               BaseLsn );

            LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, FALSE );

        } finally {

            DebugUnwind( LfsSetBaseLsn );

            //
            //  Release the log file control block if held.
            //

            LfsReleaseLch( Lch );

            DebugTrace( -1, Dbg, "LfsSetBaseLsn:  Exit\n", 0 );
        }

    } except (LfsExceptionFilter( GetExceptionInformation() )) {

        Status = GetExceptionCode();
    }

    if (Status != STATUS_SUCCESS) {

        ExRaiseStatus( Status );
    }

    return;
}
Beispiel #25
0
// BSS list lock acquired & called at Dispatch
NDIS_STATUS 
HelperPortUpdateBSSEntry(
    __in  PMP_HELPER_PORT        HelperPort,
    __in  PMP_BSS_ENTRY  pBSSEntry,
    __in  PMP_RX_MPDU        pFragment,
    __in  PDOT11_BEACON_FRAME pDot11BeaconPRFrame,
    __in  ULONG           BeaconPRDataLength
    )
{
    NDIS_STATUS         ndisStatus = NDIS_STATUS_SUCCESS;
    PDOT11_MGMT_HEADER  pMgmtPktHeader;
    ULONGLONG           ullHostTimeStamp;
    PVOID               pSavedBeaconPRBuffer = NULL;
    ULONG               uOffsetOfInfoElemBlob = FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements);
    UCHAR               channel;
    DOT11_PHY_TYPE      PhyType;

    pMgmtPktHeader = (PDOT11_MGMT_HEADER)MP_RX_MPDU_DATA(pFragment);
    NdisGetCurrentSystemTime((PLARGE_INTEGER)&ullHostTimeStamp);
    
    do
    {
        // 
        // Modifying data in the AP entry
        //
        NdisDprAcquireSpinLock(&(pBSSEntry->Lock));

        if (pDot11BeaconPRFrame->Capability.IBSS)
        {
            pBSSEntry->Dot11BSSType = dot11_BSS_type_independent;
        }
        else
        {   
            pBSSEntry->Dot11BSSType = dot11_BSS_type_infrastructure;
        }
        
        //
        // Adhoc station can leave adhoc cell and create a new cell. SoftAPs
        // can move. This means the BSSID can change
        //
        NdisMoveMemory(
            pBSSEntry->Dot11BSSID,
            pMgmtPktHeader->BSSID,
            sizeof(DOT11_MAC_ADDRESS)
            );

        pBSSEntry->HostTimestamp = ullHostTimeStamp;
        pBSSEntry->BeaconTimestamp = pDot11BeaconPRFrame->Timestamp;
        pBSSEntry->BeaconInterval = pDot11BeaconPRFrame->BeaconInterval;
        pBSSEntry->Dot11Capability = pDot11BeaconPRFrame->Capability;
        pBSSEntry->RSSI = pFragment->Msdu->RecvContext.lRSSI;
        pBSSEntry->LinkQuality = pFragment->Msdu->LinkQuality;
        pBSSEntry->ChannelCenterFrequency 
            = pFragment->Msdu->RecvContext.uChCenterFrequency;

        //
        // If signal strength was below our threshold, catch that
        //
        if (pBSSEntry->LinkQuality < HelperPort->RegInfo->RSSILinkQualityThreshold)
        {
            pBSSEntry->LowQualityCount++;
        }
        else
        {
            pBSSEntry->LowQualityCount = 0;
        }

#if 0
        if (pBSSEntry->AssocState == dot11_assoc_state_auth_assoc)
        {
            MpTrace(COMP_ASSOC, DBG_LOUD, ("Received beacon from associated AP: %02X-%02X-%02X-%02X-%02X-%02X\n",
                pMgmtPktHeader->SA[0], pMgmtPktHeader->SA[1], pMgmtPktHeader->SA[2], 
                pMgmtPktHeader->SA[3], pMgmtPktHeader->SA[4], pMgmtPktHeader->SA[5]));
        }
#endif

        //
        // Get channel number at which the frame was received.
        //
        if (Dot11GetChannelForDSPhy(Add2Ptr(pDot11BeaconPRFrame, uOffsetOfInfoElemBlob),
                                    BeaconPRDataLength - uOffsetOfInfoElemBlob, 
                                    &channel) != NDIS_STATUS_SUCCESS)
        {
            channel = pFragment->Msdu->Channel;
        }

        if (channel != 0)
        {
            pBSSEntry->Channel = channel;
        }

        //
        // Get PhyType and PhyId
        //
        PhyType = VNic11DeterminePHYType(HELPPORT_GET_VNIC(HelperPort), 
                                       pBSSEntry->Dot11Capability,
                                       pBSSEntry->Channel);
        if (pBSSEntry->Dot11PhyType != PhyType)
        {
            pBSSEntry->Dot11PhyType = PhyType;
            pBSSEntry->PhyId = BasePortGetPhyIdFromType(HELPPORT_GET_MP_PORT(HelperPort), PhyType);
        }

        if (pMgmtPktHeader->FrameControl.Subtype == DOT11_MGMT_SUBTYPE_BEACON)
        {
            //
            // Increase the beacon frame size if necessary
            //
            if (pBSSEntry->MaxBeaconFrameSize < BeaconPRDataLength)
            {
                MP_ALLOCATE_MEMORY(HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle, 
                    &pSavedBeaconPRBuffer, 
                    BeaconPRDataLength,
                    PORT_MEMORY_TAG
                    );
                    
                if (pSavedBeaconPRBuffer == NULL)
                {
                    //
                    // Unable to allocate memory for information elements.
                    // If this is a new AP entry, we wont be adding it to the list.
                    // For existing entries, we end up ignoring the new IE blob
                    //
                    ndisStatus = NDIS_STATUS_RESOURCES;
                    NdisDprReleaseSpinLock(&(pBSSEntry->Lock));
                    break;
                }
                //
                // Delete any old blob buffer
                //
                if (pBSSEntry->pDot11BeaconFrame != NULL)
                {
                    MP_FREE_MEMORY(pBSSEntry->pDot11BeaconFrame);
                }

                pBSSEntry->pDot11BeaconFrame = pSavedBeaconPRBuffer;
                pBSSEntry->MaxBeaconFrameSize = BeaconPRDataLength;
            }

            // Update the beacon
            pBSSEntry->BeaconFrameSize = BeaconPRDataLength;
            
            // Also save this as the IE blob pointer
            pBSSEntry->InfoElemBlobSize = BeaconPRDataLength - uOffsetOfInfoElemBlob;
            pBSSEntry->pDot11InfoElemBlob = (PUCHAR)pBSSEntry->pDot11BeaconFrame + uOffsetOfInfoElemBlob;
            
            //
            // Update/Save the beacon information element block
            //
            NdisMoveMemory(
                pBSSEntry->pDot11BeaconFrame,
                pDot11BeaconPRFrame,
                BeaconPRDataLength
                );
        }
    
        if (pMgmtPktHeader->FrameControl.Subtype == DOT11_MGMT_SUBTYPE_PROBE_RESPONSE)
        {
            //
            // Increase the probe response frame size if necessary
            //
            if (pBSSEntry->MaxProbeFrameSize < BeaconPRDataLength)
            {
                MP_ALLOCATE_MEMORY(HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle, 
                    &pSavedBeaconPRBuffer, 
                    BeaconPRDataLength,
                    PORT_MEMORY_TAG
                    );
                    
                if (pSavedBeaconPRBuffer == NULL)
                {
                    //
                    // Unable to allocate memory for information elements.
                    // If this is a new AP entry, we wont be adding it to the list.
                    // For existing entries, we end up ignoring the new IE blob
                    //
                    ndisStatus = NDIS_STATUS_RESOURCES;
                    NdisDprReleaseSpinLock(&(pBSSEntry->Lock));
                    break;
                }
                //
                // Delete any old blob buffer
                //
                if (pBSSEntry->pDot11ProbeFrame != NULL)
                {
                    MP_FREE_MEMORY(pBSSEntry->pDot11ProbeFrame);
                }

                pBSSEntry->pDot11ProbeFrame = pSavedBeaconPRBuffer;
                pBSSEntry->MaxProbeFrameSize = BeaconPRDataLength;
            }
            
            pBSSEntry->ProbeFrameSize = BeaconPRDataLength;

            // Also save this as the IE blob pointer
            pBSSEntry->InfoElemBlobSize = BeaconPRDataLength - uOffsetOfInfoElemBlob;
            pBSSEntry->pDot11InfoElemBlob = (PUCHAR)pBSSEntry->pDot11ProbeFrame + uOffsetOfInfoElemBlob;

            //
            // Update/Save the beacon information element block
            //
            NdisMoveMemory(
                pBSSEntry->pDot11ProbeFrame,
                pDot11BeaconPRFrame,
                BeaconPRDataLength
                );

        }

#if 0
        if (pBSSEntry->AssocState == dot11_assoc_state_auth_assoc)
        {
            MpTrace(COMP_SCAN, DBG_LOUD, ("Received %d for AP %02X-%02X-%02X-%02X-%02X-%02X \n", 
                    pMgmtPktHeader->FrameControl.Subtype,
                    pBSSEntry->Dot11BSSID[0], pBSSEntry->Dot11BSSID[1], pBSSEntry->Dot11BSSID[2], 
                    pBSSEntry->Dot11BSSID[3], pBSSEntry->Dot11BSSID[4], pBSSEntry->Dot11BSSID[5]));
        }
#endif

        //
        // Done with our modification of the AP entry
        //
        NdisDprReleaseSpinLock(&(pBSSEntry->Lock));
        
    } while (FALSE);

    return ndisStatus;
Beispiel #26
0
//
// standard printf function with a subset of formating features supported.
//
// supported
//	%d, %ld - signed short, signed long
//	%u, %lu - unsigned short, unsigned long
//	%c, %s  - character, string
//	%x, %lx - unsigned print in hex, unsigned long print in hex
//	%wS,%wZ	- unicode string
//
//	does not do:
//
//	- field width specification
//	- floating point.
//
VOID BlPrint(__in PCHAR cp,...)
{
	PVOID ap											= Add2Ptr(&cp,sizeof(PCHAR),PVOID);
	USHORT b											= 0;
	ULONG Count											= 0;
	ULONG DeviceId										= BlConsoleOutDeviceId ? BlConsoleOutDeviceId : 1;

	while(b = *cp ++)
	{
		if(b == '%')
		{
			USHORT c									= *cp ++;
			switch(c)
			{
			case 'c':
				ArcWrite(DeviceId,ap,sizeof(UCHAR),&Count);
				ap										= Add2Ptr(ap,sizeof(LONG),PVOID);
				break;

			case 'd':
				puti(*static_cast<PLONG>(ap));
				ap										= Add2Ptr(ap,sizeof(LONG),PVOID);
				break;

			case 'l':
				{
					USHORT d							= *cp ++;
					switch(d)
					{
					case 'd':
						puti(*static_cast<PLONG>(ap));
						ap								= Add2Ptr(ap,sizeof(LONG),PVOID);
						break;

					case 'u':
						putu(*static_cast<PUSHORT>(ap));
						ap								= Add2Ptr(ap,sizeof(LONG),PVOID);
						break;

					case 'x':
						{
							ULONG x						= *static_cast<PULONG>(ap);
							ULONG ZeroLength			= (x < 0x10) + (x < 0x100) + (x < 0x1000) + (x < 0x10000) + (x < 0x100000) + (x < 0x1000000) + (x < 0x10000000);
							while(ZeroLength --)
								ArcWrite(DeviceId,"0",sizeof(UCHAR),&Count);
							putx(x);
							ap							= Add2Ptr(ap,sizeof(LONG),PVOID);
						}
						break;
					}
				}
				break;

			case 's':
				{
					PCHAR String						= *static_cast<PCHAR*>(ap);
					ArcWrite(DeviceId,String,strlen(String),&Count);
					ap									= Add2Ptr(ap,sizeof(PCHAR),PVOID);
				}
				break;

			case 'u':
				putu(*static_cast<PUSHORT>(ap));
				ap										= Add2Ptr(ap,sizeof(LONG),PVOID);
				break;

			case 'w':
				{
					USHORT d							= *cp ++;
					switch(d)
					{
					case 'S':
					case 'W':
						putwS(*static_cast<PUNICODE_STRING*>(ap));
						ap								= Add2Ptr(ap,sizeof(PUNICODE_STRING),PVOID);
						break;
					}
				}
				break;

			case 'x':
				{
					USHORT x							= *static_cast<PUSHORT>(ap);
					ULONG ZeroLength					= (x < 0x10) + (x < 0x100) + (x < 0x1000);
					while(ZeroLength --)
						ArcWrite(DeviceId,"0",sizeof(UCHAR),&Count);
					putx(x);
					ap									= Add2Ptr(ap,sizeof(LONG),PVOID);
				}
				break;

			default:
				ArcWrite(DeviceId,&b,sizeof(UCHAR),&Count);
				ArcWrite(DeviceId,&c,sizeof(UCHAR),&Count);
				break;
			}
		}
		else
		{
			if(!DbcsLangId || !GrIsDBCSLeadByte(cp[-1]))
			{
				ArcWrite(DeviceId,cp - 1,1,&Count);
			}
			else
			{
				ArcWrite(DeviceId,cp - 1,2,&Count);
				cp										+= 1;
			}
		}
	}
}
Beispiel #27
0
//
// send packet
//
VOID BdComSendPacket(__in ULONG PacketType,__in PSTRING MessageHeader,__in PSTRING MessageData)
{
	KD_PACKET PacketHeader;
	ULONG MessageDataLength;

	//
	// if there is a data buffer,calc checksum
	//
	if(MessageData)
	{
		MessageDataLength								= MessageData->Length;
		PacketHeader.Checksum							= BdComputeChecksum(MessageData->Buffer,MessageData->Length);
	}
	else
	{
		MessageDataLength								= 0;
		PacketHeader.Checksum							= 0;
	}

	//
	// and compute header's checksum
	//
	PacketHeader.Checksum								+= BdComputeChecksum(MessageHeader->Buffer,MessageHeader->Length);

	//
	// initialize and send the packet header.
	//
	PacketHeader.PacketLeader							= PACKET_LEADER;
	PacketHeader.ByteCount								= static_cast<USHORT>(MessageHeader->Length + MessageDataLength);
	PacketHeader.PacketType								= static_cast<USHORT>(PacketType);
	BdNumberRetries										= BdRetryCount;
	ULONG ReturnCode									= KDP_PACKET_TIMEOUT;
	do
	{
		if(BdNumberRetries == 0)
		{
			PDBGKD_WAIT_STATE_CHANGE64 StateChange		= Add2Ptr(MessageHeader->Buffer,0,PDBGKD_WAIT_STATE_CHANGE64);
			PDBGKD_DEBUG_IO DebugIo						= Add2Ptr(MessageHeader->Buffer,0,PDBGKD_DEBUG_IO);
			PDBGKD_FILE_IO FileIo						= Add2Ptr(MessageHeader->Buffer,0,PDBGKD_FILE_IO);

			//
			// if the packet is not for reporting exception, we give up and declare debugger not present.
			//
			if( (PacketType == PACKET_TYPE_KD_DEBUG_IO && DebugIo->ApiNumber == DbgKdPrintStringApi) ||
				(PacketType == PACKET_TYPE_KD_STATE_CHANGE64 && StateChange->NewState == DbgKdLoadSymbolsStateChange) ||
				(PacketType == PACKET_TYPE_KD_FILE_IO && FileIo->ApiNumber == DbgKdCreateFileApi))
			{
				BdDebuggerNotPresent				= TRUE;
				BdNextPacketIdToSend				= INITIAL_PACKET_ID | SYNC_PACKET_ID;
				BdPacketIdExpected					= INITIAL_PACKET_ID;
				return;
			}
		}

		//
		// setting PacketId has to be in the do loop in case Packet Id was reset.
		//
		PacketHeader.PacketId							= BdNextPacketIdToSend;
		BdComSendString(&PacketHeader,sizeof(KD_PACKET));

		//
		// output message header.
		//
		BdComSendString(MessageHeader->Buffer,MessageHeader->Length);

		//
		// output message data.
		//
		if(MessageDataLength)
			BdComSendString(MessageData->Buffer,MessageData->Length);

		//
		// output a packet trailing byte
		//
		BdComPutByte(PACKET_TRAILING_BYTE);

		//
		// wait for the Ack Packet
		//
		ReturnCode = BdComReceivePacket(PACKET_TYPE_KD_ACKNOWLEDGE,0,0,0);
		if(ReturnCode == KDP_PACKET_TIMEOUT)
			BdNumberRetries								-= 1;

	}while(ReturnCode != KDP_PACKET_RECEIVED);

	//
	// reset Sync bit in packet id.  The packet we sent may have Sync bit set
	//
	BdNextPacketIdToSend								&= ~SYNC_PACKET_ID;

	//
	// since we are able to talk to debugger, the retrycount is set to maximum value.
	//
	BdRetryCount										= 0x14;
}
Beispiel #28
0
NTSTATUS
CdQueryDirectory (
    _Inout_ PIRP_CONTEXT IrpContext,
    _Inout_ PIRP Irp,
    _In_ PIO_STACK_LOCATION IrpSp,
    _In_ PFCB Fcb,
    _In_ PCCB Ccb
    )

/*++

Routine Description:

    This routine performs the query directory operation.  It is responsible
    for either completing of enqueuing the input Irp.  We store the state of the
    search in the Ccb.

Arguments:

    Irp - Supplies the Irp to process

    IrpSp - Stack location for this Irp.

    Fcb - Fcb for this directory.

    Ccb - Ccb for this directory open.

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG Information = 0;

    ULONG LastEntry = 0;
    ULONG NextEntry = 0;

    ULONG FileNameBytes;
    ULONG SeparatorBytes;
    ULONG VersionStringBytes;

    FILE_ENUM_CONTEXT FileContext;
    PDIRENT ThisDirent = NULL;
    BOOLEAN InitialQuery;
    BOOLEAN ReturnNextEntry = FALSE;
    BOOLEAN ReturnSingleEntry;
    BOOLEAN Found;
    BOOLEAN DoCcbUpdate = FALSE;

    PCHAR UserBuffer;
    ULONG BytesRemainingInBuffer;

    ULONG BaseLength;

    PFILE_BOTH_DIR_INFORMATION DirInfo = NULL;
    PFILE_NAMES_INFORMATION NamesInfo;
    PFILE_ID_FULL_DIR_INFORMATION IdFullDirInfo;
    PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo;

    PAGED_CODE();

    //
    //  Check if we support this search mode.  Also remember the size of the base part of
    //  each of these structures.
    //

    switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {

    case FileDirectoryInformation:

        BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
                                   FileName[0] );
        break;

    case FileFullDirectoryInformation:

        BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
                                   FileName[0] );
        break;

    case FileIdFullDirectoryInformation:

        BaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
                                   FileName[0] );
        break;

    case FileNamesInformation:

        BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
                                   FileName[0] );
        break;

    case FileBothDirectoryInformation:

        BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
                                   FileName[0] );
        break;

    case FileIdBothDirectoryInformation:

        BaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
                                   FileName[0] );
        break;

    default:

        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_INFO_CLASS );
        return STATUS_INVALID_INFO_CLASS;
    }

    //
    //  Get the user buffer.
    //

    CdMapUserBuffer( IrpContext, &UserBuffer);

    //
    //  Initialize our search context.
    //

    CdInitializeFileContext( IrpContext, &FileContext );

    //
    //  Acquire the directory.
    //

    CdAcquireFileShared( IrpContext, Fcb );

    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {

        //
        //  Verify the Fcb is still good.
        //

        CdVerifyFcbOperation( IrpContext, Fcb );

        //
        //  Start by getting the initial state for the enumeration.  This will set up the Ccb with
        //  the initial search parameters and let us know the starting offset in the directory
        //  to search.
        //

        CdInitializeEnumeration( IrpContext,
                                 IrpSp,
                                 Fcb,
                                 Ccb,
                                 &FileContext,
                                 &ReturnNextEntry,
                                 &ReturnSingleEntry,
                                 &InitialQuery );

        //
        //  The current dirent is stored in the InitialDirent field.  We capture
        //  this here so that we have a valid restart point even if we don't
        //  find a single entry.
        //

        ThisDirent = &FileContext.InitialDirent->Dirent;

        //
        //  At this point we are about to enter our query loop.  We have
        //  determined the index into the directory file to begin the
        //  search.  LastEntry and NextEntry are used to index into the user
        //  buffer.  LastEntry is the last entry we've added, NextEntry is
        //  current one we're working on.  If NextEntry is non-zero, then
        //  at least one entry was added.
        //

        while (TRUE) {

            //
            //  If the user had requested only a single match and we have
            //  returned that, then we stop at this point.  We update the Ccb with
            //  the status based on the last entry returned.
            //

            if ((NextEntry != 0) && ReturnSingleEntry) {

                DoCcbUpdate = TRUE;
                try_leave( Status );
            }

            //
            //  We try to locate the next matching dirent.  Our search if based on a starting
            //  dirent offset, whether we should return the current or next entry, whether
            //  we should be doing a short name search and finally whether we should be
            //  checking for a version match.
            //

            Found = CdEnumerateIndex( IrpContext, Ccb, &FileContext, ReturnNextEntry );

            //
            //  Initialize the value for the next search.
            //

            ReturnNextEntry = TRUE;

            //
            //  If we didn't receive a dirent, then we are at the end of the
            //  directory.  If we have returned any files, we exit with
            //  success, otherwise we return STATUS_NO_MORE_FILES.
            //

            if (!Found) {

                if (NextEntry == 0) {

                    Status = STATUS_NO_MORE_FILES;

                    if (InitialQuery) {

                        Status = STATUS_NO_SUCH_FILE;
                    }
                }

                DoCcbUpdate = TRUE;
                try_leave( Status );
            }

            //
            //  Remember the dirent for the file we just found.
            //

            ThisDirent = &FileContext.InitialDirent->Dirent;

            //
            //  Here are the rules concerning filling up the buffer:
            //
            //  1.  The Io system garentees that there will always be
            //      enough room for at least one base record.
            //
            //  2.  If the full first record (including file name) cannot
            //      fit, as much of the name as possible is copied and
            //      STATUS_BUFFER_OVERFLOW is returned.
            //
            //  3.  If a subsequent record cannot completely fit into the
            //      buffer, none of it (as in 0 bytes) is copied, and
            //      STATUS_SUCCESS is returned.  A subsequent query will
            //      pick up with this record.
            //

            //
            //  Let's compute the number of bytes we need to transfer the current entry.
            //

            SeparatorBytes =
            VersionStringBytes = 0;

            //
            //  We can look directly at the dirent that we found.
            //

            FileNameBytes = ThisDirent->CdFileName.FileName.Length;

            //
            //  Compute the number of bytes for the version string if
            //  we will return this. Allow directories with illegal ";".
            //

            if (((Ccb->SearchExpression.VersionString.Length != 0) ||
                 (FlagOn(ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY))) &&
                (ThisDirent->CdFileName.VersionString.Length != 0)) {

                SeparatorBytes = 2;

                VersionStringBytes = ThisDirent->CdFileName.VersionString.Length;
            }

            //
            //  If the slot for the next entry would be beyond the length of the
            //  user's buffer just exit (we know we've returned at least one entry
            //  already). This will happen when we align the pointer past the end.
            //

            if (NextEntry > IrpSp->Parameters.QueryDirectory.Length) {

                ReturnNextEntry = FALSE;
                DoCcbUpdate = TRUE;
                try_leave( Status = STATUS_SUCCESS );
            }

            //
            //  Compute the number of bytes remaining in the buffer.  Round this
            //  down to a WCHAR boundary so we can copy full characters.
            //

            BytesRemainingInBuffer = IrpSp->Parameters.QueryDirectory.Length - NextEntry;
            ClearFlag( BytesRemainingInBuffer, 1 );

            //
            //  If this won't fit and we have returned a previous entry then just
            //  return STATUS_SUCCESS.
            //

            if ((BaseLength + FileNameBytes + SeparatorBytes + VersionStringBytes) > BytesRemainingInBuffer) {

                //
                //  If we already found an entry then just exit.
                //

                if (NextEntry != 0) {

                    ReturnNextEntry = FALSE;
                    DoCcbUpdate = TRUE;
                    try_leave( Status = STATUS_SUCCESS );
                }

                //
                //  Don't even try to return the version string if it doesn't all fit.
                //  Reduce the FileNameBytes to just fit in the buffer.
                //

                if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) {

                    FileNameBytes = BytesRemainingInBuffer - BaseLength;
                }

                //
                //  Don't return any version string bytes.
                //

                VersionStringBytes =
                SeparatorBytes = 0;

                //
                //  Use a status code of STATUS_BUFFER_OVERFLOW.  Also set
                //  ReturnSingleEntry so that we will exit the loop at the top.
                //

                Status = STATUS_BUFFER_OVERFLOW;
                ReturnSingleEntry = TRUE;
            }

            //
            //  Protect access to the user buffer with an exception handler.
            //  Since (at our request) IO doesn't buffer these requests, we have
            //  to guard against a user messing with the page protection and other
            //  such trickery.
            //
            
            try {
            
                //
                //  Zero and initialize the base part of the current entry.
                //

                RtlZeroMemory( Add2Ptr( UserBuffer, NextEntry, PVOID ),
                               BaseLength );
    
                //
                //  Now we have an entry to return to our caller.
                //  We'll case on the type of information requested and fill up
                //  the user buffer if everything fits.
                //

                switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
    
                case FileBothDirectoryInformation:
                case FileFullDirectoryInformation:
                case FileIdBothDirectoryInformation:
                case FileIdFullDirectoryInformation:
                case FileDirectoryInformation:
    
                    DirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_BOTH_DIR_INFORMATION );
    
                    //
                    //  Use the create time for all the time stamps.
                    //
    
                    CdConvertCdTimeToNtTime( IrpContext,
                                             FileContext.InitialDirent->Dirent.CdTime,
                                             &DirInfo->CreationTime );
    
                    DirInfo->LastWriteTime = DirInfo->ChangeTime = DirInfo->CreationTime;
    
                    //
                    //  Set the attributes and sizes separately for directories and
                    //  files.
                    //
    
                    if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {
    
                        DirInfo->EndOfFile.QuadPart = DirInfo->AllocationSize.QuadPart = 0;
    
                        SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
                        
                    } else {
    
                        DirInfo->EndOfFile.QuadPart = FileContext.FileSize;
                        DirInfo->AllocationSize.QuadPart = LlSectorAlign( FileContext.FileSize );
                        
                        SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_READONLY);
                    }

                    if (FlagOn( ThisDirent->DirentFlags,
                                CD_ATTRIBUTE_HIDDEN )) {
    
                        SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
                    }
    
                    DirInfo->FileIndex = ThisDirent->DirentOffset;
    
                    DirInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
    
                    break;
    
                case FileNamesInformation:
    
                    NamesInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_NAMES_INFORMATION );
    
                    NamesInfo->FileIndex = ThisDirent->DirentOffset;
    
                    NamesInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
    
                    break;
                }

                //
                //  Fill in the FileId
                //

                switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {

                case FileIdBothDirectoryInformation:

                    IdBothDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_BOTH_DIR_INFORMATION );
                    CdSetFidFromParentAndDirent( IdBothDirInfo->FileId, Fcb, ThisDirent );
                    break;

                case FileIdFullDirectoryInformation:

                    IdFullDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_FULL_DIR_INFORMATION );
                    CdSetFidFromParentAndDirent( IdFullDirInfo->FileId, Fcb, ThisDirent );
                    break;

                default:
                    break;
                }
    
                //
                //  Now copy as much of the name as possible.  We also may have a version
                //  string to copy.
                //
    
                if (FileNameBytes != 0) {
    
                    //
                    //  This is a Unicode name, we can copy the bytes directly.
                    //
    
                    RtlCopyMemory( Add2Ptr( UserBuffer, NextEntry + BaseLength, PVOID ),
                                   ThisDirent->CdFileName.FileName.Buffer,
                                   FileNameBytes );
    
                    if (SeparatorBytes != 0) {
    
                        *(Add2Ptr( UserBuffer,
                                   NextEntry + BaseLength + FileNameBytes,
                                   PWCHAR )) = L';';
    
                        if (VersionStringBytes != 0) {
    
                            RtlCopyMemory( Add2Ptr( UserBuffer,
                                                    NextEntry + BaseLength + FileNameBytes + sizeof( WCHAR ),
                                                    PVOID ),
                                           ThisDirent->CdFileName.VersionString.Buffer,
                                           VersionStringBytes );
                        }
                    }
                }

                //
                //  Fill in the short name if we got STATUS_SUCCESS.  The short name
                //  may already be in the file context.  Otherwise we will check
                //  whether the long name is 8.3.  Special case the self and parent
                //  directory names.
                //

                if ((Status == STATUS_SUCCESS) &&
                    (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation ||
                     IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation) &&
                    (Ccb->SearchExpression.VersionString.Length == 0) &&
                    !FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) {
    
                    //
                    //  If we already have the short name then copy into the user's buffer.
                    //
    
                    if (FileContext.ShortName.FileName.Length != 0) {
    
                        RtlCopyMemory( DirInfo->ShortName,
                                       FileContext.ShortName.FileName.Buffer,
                                       FileContext.ShortName.FileName.Length );
    
                        DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.Length;
    
                    //
                    //  If the short name length is currently zero then check if
                    //  the long name is not 8.3.  We can copy the short name in
                    //  unicode form directly into the caller's buffer.
                    //
    
                    } else {
    
                        if (!CdIs8dot3Name( IrpContext,
                                            ThisDirent->CdFileName.FileName )) {
    
                            CdGenerate8dot3Name( IrpContext,
                                                 &ThisDirent->CdCaseFileName.FileName,
                                                 ThisDirent->DirentOffset,
                                                 DirInfo->ShortName,
                                                 &FileContext.ShortName.FileName.Length );
    
                            DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.Length;
                        }
                    }
    
                }

                //
                //  Sum the total number of bytes for the information field.
                //

                FileNameBytes += SeparatorBytes + VersionStringBytes;

                //
                //  Update the information with the number of bytes stored in the
                //  buffer.  We quad-align the existing buffer to add any necessary
                //  pad bytes.
                //

                Information = NextEntry + BaseLength + FileNameBytes;

                //
                //  Go back to the previous entry and fill in the update to this entry.
                //

                *(Add2Ptr( UserBuffer, LastEntry, PULONG )) = NextEntry - LastEntry;

                //
                //  Set up our variables for the next dirent.
                //

                InitialQuery = FALSE;

                LastEntry = NextEntry;
                NextEntry = QuadAlign( Information );
            
#pragma warning(suppress: 6320)
            } except (EXCEPTION_EXECUTE_HANDLER) {

                  //
                  //  We had a problem filling in the user's buffer, so stop and
                  //  fail this request.  This is the only reason any exception
                  //  would have occured at this level.
                  //
                  
                  Information = 0;
                  try_leave( Status = GetExceptionCode());
            }
        }
        
        DoCcbUpdate = TRUE;

    } finally {

        //
        //  Cleanup our search context - *before* aquiring the FCB mutex exclusive,
        //  else can block on threads in cdcreateinternalstream/purge which 
        //  hold the FCB but are waiting for all maps in this stream to be released.
        //

        CdCleanupFileContext( IrpContext, &FileContext );

        //
        //  Now we can safely aqure the FCB mutex if we need to.
        //

        if (DoCcbUpdate && !NT_ERROR( Status )) {
        
            //
            //  Update the Ccb to show the current state of the enumeration.
            //

            CdLockFcb( IrpContext, Fcb );
            
            Ccb->CurrentDirentOffset = ThisDirent->DirentOffset;

            ClearFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );

            if (ReturnNextEntry) {

                SetFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
            }

            CdUnlockFcb( IrpContext, Fcb );
        }

        //
        //  Release the Fcb.
        //

        CdReleaseFile( IrpContext, Fcb );
    }

    //
    //  Complete the request here.
    //

    Irp->IoStatus.Information = Information;

    CdCompleteRequest( IrpContext, Irp, Status );
    return Status;
}
Beispiel #29
0
VOID
CdInitializeEnumeration (
    __in PIRP_CONTEXT IrpContext,
    __in PIO_STACK_LOCATION IrpSp,
    __in PFCB Fcb,
    __inout PCCB Ccb,
    __inout PFILE_ENUM_CONTEXT FileContext,
    __out PBOOLEAN ReturnNextEntry,
    __out PBOOLEAN ReturnSingleEntry,
    __out PBOOLEAN InitialQuery
    )

/*++

Routine Description:

    This routine is called to initialize the enumeration variables and structures.
    We look at the state of a previous enumeration from the Ccb as well as any
    input values from the user.  On exit we will position the FileContext at
    a file in the directory and let the caller know whether this entry or the
    next entry should be returned.

Arguments:

    IrpSp - Irp stack location for this request.

    Fcb - Fcb for this directory.

    Ccb - Ccb for the directory handle.

    FileContext - FileContext to use for this enumeration.

    ReturnNextEntry - Address to store whether we should return the entry at
        the FileContext position or the next entry.

    ReturnSingleEntry - Address to store whether we should only return
        a single entry.

    InitialQuery - Address to store whether this is the first enumeration
        query on this handle.

Return Value:

    None.

--*/

{
    NTSTATUS Status;

    PUNICODE_STRING FileName;
    CD_NAME WildCardName;
    CD_NAME SearchExpression;

    ULONG CcbFlags;

    ULONG DirentOffset;
    ULONG LastDirentOffset;
    BOOLEAN KnownOffset;

    BOOLEAN Found;

    PAGED_CODE();

    //
    //  If this is the initial query then build a search expression from the input
    //  file name.
    //

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

        FileName = IrpSp->Parameters.QueryDirectory.FileName;

        CcbFlags = 0;

        //
        //  If the filename is not specified or is a single '*' then we will
        //  match all names.
        //

        if ((FileName == NULL) ||
            (FileName->Buffer == NULL) ||
            (FileName->Length == 0) ||
            ((FileName->Length == sizeof( WCHAR )) &&
             (FileName->Buffer[0] == L'*'))) {

            SetFlag( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL );
            RtlZeroMemory( &SearchExpression, sizeof( SearchExpression ));

        //
        //  Otherwise build the CdName from the name in the stack location.
        //  This involves building both the name and version portions and
        //  checking for wild card characters.  We also upcase the string if
        //  this is a case-insensitive search.
        //

        } else {

            //
            //  Create a CdName to check for wild cards.
            //

            WildCardName.FileName = *FileName;

            CdConvertNameToCdName( IrpContext, &WildCardName );

            //
            //  The name better have at least one character.
            //

            if (WildCardName.FileName.Length == 0) {

                CdRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER );
            }

            //
            //  Check for wildcards in the separate components.
            //

            if (FsRtlDoesNameContainWildCards( &WildCardName.FileName)) {

                SetFlag( CcbFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD );
            }

            if ((WildCardName.VersionString.Length != 0) &&
                (FsRtlDoesNameContainWildCards( &WildCardName.VersionString ))) {

                SetFlag( CcbFlags, CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD );

                //
                //  Check if this is a wild card only and match all version
                //  strings.
                //

                if ((WildCardName.VersionString.Length == sizeof( WCHAR )) &&
                    (WildCardName.VersionString.Buffer[0] == L'*')) {

                    SetFlag( CcbFlags, CCB_FLAG_ENUM_VERSION_MATCH_ALL );
                }
            }

            //
            //  Now create the search expression to store in the Ccb.
            //

            SearchExpression.FileName.Buffer = FsRtlAllocatePoolWithTag( CdPagedPool,
                                                                         FileName->Length,
                                                                         TAG_ENUM_EXPRESSION );

            SearchExpression.FileName.MaximumLength = FileName->Length;

            //
            //  Either copy the name directly or perform the upcase.
            //

            if (FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE )) {

                Status = RtlUpcaseUnicodeString( (PUNICODE_STRING) &SearchExpression.FileName,
                                                 FileName,
                                                 FALSE );

                //
                //  This should never fail.
                //

                ASSERT( Status == STATUS_SUCCESS );

            } else {

                RtlCopyMemory( SearchExpression.FileName.Buffer,
                               FileName->Buffer,
                               FileName->Length );
            }

            //
            //  Now split into the separate name and version components.
            //

            SearchExpression.FileName.Length = WildCardName.FileName.Length;
            SearchExpression.VersionString.Length = WildCardName.VersionString.Length;
            SearchExpression.VersionString.MaximumLength = WildCardName.VersionString.MaximumLength;

            SearchExpression.VersionString.Buffer = Add2Ptr( SearchExpression.FileName.Buffer,
                                                             SearchExpression.FileName.Length + sizeof( WCHAR ),
                                                             PWCHAR );
        }

        //
        //  But we do not want to return the constant "." and ".." entries for
        //  the root directory, for consistency with the rest of Microsoft's
        //  filesystems.
        //

        if (Fcb == Fcb->Vcb->RootIndexFcb) {

            SetFlag( CcbFlags, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY );
        }

        //
        //  Now lock the Fcb in order to update the Ccb with the inital
        //  enumeration values.
        //

        CdLockFcb( IrpContext, Fcb );

        //
        //  Check again that this is the initial search.
        //

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

            //
            //  Update the values in the Ccb.
            //

            Ccb->CurrentDirentOffset = Fcb->StreamOffset;
            Ccb->SearchExpression = SearchExpression;

            //
            //  Set the appropriate flags in the Ccb.
            //

            SetFlag( Ccb->Flags, CcbFlags | CCB_FLAG_ENUM_INITIALIZED );

        //
        //  Otherwise cleanup any buffer allocated here.
        //

        } else {

            if (!FlagOn( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL )) {

                CdFreePool( &SearchExpression.FileName.Buffer );
            }
        }

    //
    //  Otherwise lock the Fcb so we can read the current enumeration values.
    //

    } else {

        CdLockFcb( IrpContext, Fcb );
    }

    //
    //  Capture the current state of the enumeration.
    //
    //  If the user specified an index then use his offset.  We always
    //  return the next entry in this case.
    //

    if (FlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED )) {

        KnownOffset = FALSE;
        DirentOffset = IrpSp->Parameters.QueryDirectory.FileIndex;
        *ReturnNextEntry = TRUE;

    //
    //  If we are restarting the scan then go from the self entry.
    //

    } else if (FlagOn( IrpSp->Flags, SL_RESTART_SCAN )) {

        KnownOffset = TRUE;
        DirentOffset = Fcb->StreamOffset;
        *ReturnNextEntry = FALSE;

    //
    //  Otherwise use the values from the Ccb.
    //

    } else {

        KnownOffset = TRUE;
        DirentOffset = Ccb->CurrentDirentOffset;
        *ReturnNextEntry = BooleanFlagOn( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
    }

    //
    //  Unlock the Fcb.
    //

    CdUnlockFcb( IrpContext, Fcb );

    //
    //  We have the starting offset in the directory and whether to return
    //  that entry or the next.  If we are at the beginning of the directory
    //  and are returning that entry, then tell our caller this is the
    //  initial query.
    //

    *InitialQuery = FALSE;

    if ((DirentOffset == Fcb->StreamOffset) &&
        !(*ReturnNextEntry)) {

        *InitialQuery = TRUE;
    }

    //
    //  If there is no file object then create it now.
    //

    CdVerifyOrCreateDirStreamFile( IrpContext, Fcb);

    //
    //  Determine the offset in the stream to position the FileContext and
    //  whether this offset is known to be a file offset.
    //
    //  If this offset is known to be safe then go ahead and position the
    //  file context.  This handles the cases where the offset is the beginning
    //  of the stream, the offset is from a previous search or this is the
    //  initial query.
    //

    if (KnownOffset) {

        CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, DirentOffset );

    //
    //  Otherwise we walk through the directory from the beginning until
    //  we reach the entry which contains this offset.
    //

    } else {

        LastDirentOffset = Fcb->StreamOffset;
        Found = TRUE;

        CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, LastDirentOffset );

        //
        //  If the requested offset is prior to the beginning offset in the stream
        //  then don't return the next entry.
        //

        if (DirentOffset < LastDirentOffset) {

            *ReturnNextEntry = FALSE;

        //
        //  Else look for the last entry which ends past the desired index.
        //

        } else {

            //
            //  Keep walking through the directory until we run out of
            //  entries or we find an entry which ends beyond the input
            //  index value.
            //

            do {

                //
                //  If we have passed the index value then exit.
                //

                if (FileContext->InitialDirent->Dirent.DirentOffset > DirentOffset) {

                    Found = FALSE;
                    break;
                }

                //
                //  Remember the current position in case we need to go back.
                //

                LastDirentOffset = FileContext->InitialDirent->Dirent.DirentOffset;

                //
                //  Exit if the next entry is beyond the desired index value.
                //

                if (LastDirentOffset + FileContext->InitialDirent->Dirent.DirentLength > DirentOffset) {

                    break;
                }

                Found = CdLookupNextInitialFileDirent( IrpContext, Fcb, FileContext );

            } while (Found);

            //
            //  If we didn't find the entry then go back to the last known entry.
            //  This can happen if the index lies in the unused range at the
            //  end of a sector.
            //

            if (!Found) {

                CdCleanupFileContext( IrpContext, FileContext );
                CdInitializeFileContext( IrpContext, FileContext );

                CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, LastDirentOffset );
            }
        }
    }

    //
    //  Only update the dirent name if we will need it for some reason.
    //  Don't update this name if we are returning the next entry and
    //  the search string has a version component.
    //

    FileContext->ShortName.FileName.Length = 0;

    if (!(*ReturnNextEntry) ||
        (Ccb->SearchExpression.VersionString.Length == 0)) {

        //
        //  Update the name in the dirent into filename and version components.
        //

        CdUpdateDirentName( IrpContext,
                            &FileContext->InitialDirent->Dirent,
                            FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE ));
    }

    //
    //  Look at the flag in the IrpSp indicating whether to return just
    //  one entry.
    //

    *ReturnSingleEntry = FALSE;

    if (FlagOn( IrpSp->Flags, SL_RETURN_SINGLE_ENTRY )) {

        *ReturnSingleEntry = TRUE;
    }

    return;
}