Exemplo n.º 1
0
VOID
LfsFindLogRecord (
    IN PLFCB Lfcb,
    IN OUT PLfsLCB 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();

    LfsDebugTrace( +1, Dbg, "LfsFindLogRecord:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Lfcb          -> %08lx\n", Lfcb );
    LfsDebugTrace(  0, Dbg, "Context Block -> %08lx\n", Lcb );
    LfsDebugTrace(  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 = LfsAdd2Ptr( 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 );
        }

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

    return;
}
Exemplo n.º 2
0
VOID
LfsLsnFinalOffset (
    IN PLFCB Lfcb,
    IN LSN Lsn,
    IN ULONG DataLength,
    OUT PLONGLONG FinalOffset
    )

/*++

Routine Description:

    This routine will compute the final offset of the last byte of the log
    record.  It does this by computing how many bytes are on the current
    page and then computing how many more pages will be needed.

Arguments:

    Lfcb - This is the file control block for the log file.

    Lsn - This is the log record being considered.

    DataLength - This is the length of the data for this log record.  We will add the
        header length here.

    FinalOffset - Address to store the result.

Return Value:

    None.

--*/

{
    ULONG RemainingPageBytes;
    ULONG PageOffset;

    PAGED_CODE();

    DebugTrace( +1, Dbg, "LfsLsnFinalOffset:  Entered\n", 0 );
    DebugTrace(  0, Dbg, "Lfcb          ->  %08lx\n", Lfcb );
    DebugTrace(  0, Dbg, "Lsn (Low)     ->  %08lx\n", Lsn.LowPart );
    DebugTrace(  0, Dbg, "Lsn (High)    ->  %08lx\n", Lsn.HighPart );
    DebugTrace(  0, Dbg, "DataLength    ->  %08lx\n", DataLength );

    //
    //  We compute the starting log page file offset, the number of bytes
    //  remaining in the current log page and the position on this page
    //  before any data bytes.
    //

    LfsTruncateLsnToLogPage( Lfcb, Lsn, FinalOffset );

    PageOffset = LfsLsnToPageOffset( Lfcb, Lsn );

    RemainingPageBytes = (ULONG)Lfcb->LogPageSize - PageOffset;

    PageOffset -= 1;

    //
    //  Add the length of the header.
    //

    DataLength += Lfcb->RecordHeaderLength;

    //
    //  If this Lsn is contained in this log page we are done.
    //  Otherwise we need to walk through several log pages.
    //

    if (DataLength > RemainingPageBytes) {

        DataLength -= RemainingPageBytes;

        RemainingPageBytes = (ULONG)Lfcb->LogPageDataSize;

        PageOffset = (ULONG)Lfcb->LogPageDataOffset - 1;

        while (TRUE) {

            BOOLEAN Wrapped;

            LfsNextLogPageOffset( Lfcb, *FinalOffset, FinalOffset, &Wrapped );

            //
            //  We are done if the remaining bytes fit on this page.
            //

            if (DataLength <= RemainingPageBytes) {

                break;
            }

            DataLength -= RemainingPageBytes;
        }
    }

    //
    //  We add the remaining bytes to our starting position on this page
    //  and then add that value to the file offset of this log page.
    //

    *(PULONG)FinalOffset += (DataLength + PageOffset);

    DebugTrace(  0, Dbg, "FinalOffset (Low)     ->  %08lx\n", LogPageFileOffset.LowPart );
    DebugTrace(  0, Dbg, "FinalOffset (High)    ->  %08lx\n", LogPageFileOffset.HighPart );
    DebugTrace( -1, Dbg, "LfsLsnFinalOffset:  Exit\n", 0 );

    return;
}