⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dirsup.c

📁 winddk src目录下的文件系统驱动源码压缩!
💻 C
📖 第 1 页 / 共 4 页
字号:
/*++

Copyright (c) 1989-2000 Microsoft Corporation

Module Name:

    DirSup.c

Abstract:

    This module implements the dirent support routines for Cdfs.

    Directories on a CD consist of a number of contiguous sectors on
    the disk.  File descriptors consist of one or more directory entries
    (dirents) within a directory.  Files may contain version numbers.  If
    present all like-named files will be ordered contiguously in the
    directory by decreasing version numbers.  We will only return the
    first of these on a directory query unless the user explicitly
    asks for version numbers.  Finally dirents will not span sector
    boundaries.  Unused bytes at the end of a sector will be zero
    filled.

    Directory sector:                                                   Offset
                                                                        2048
        +---------------------------------------------------------------+
        |            |          |          |           |          |     |
        | foo;4      | foo;4    | foo;3    |  hat      |  zebra   | Zero|
        |            |          |          |           |          | Fill|
        |            |  final   |  single  |           |          |     |
        |            |  extent  |   extent |           |          |     |
        +---------------------------------------------------------------+

    Dirent operations:

        - Position scan at known offset in directory.  Dirent at this
            offset must exist and is valid.  Used when scanning a directory
            from the beginning when the self entry is known to be valid.
            Used when positioning at the first dirent for an open
            file to scan the allocation information.  Used when resuming
            a directory enumeration from a valid directory entry.

        - Position scan at known offset in directory.  Dirent is known to
            start at this position but must be checked for validity.
            Used to read the self-directory entry.

        - Move to the next dirent within a directory.

        - Given a known starting dirent, collect all the dirents for
            that file.  Scan will finish positioned at the last dirent
            for the file.  We will accumulate the extent lengths to
            find the size of the file.

        - Given a known starting dirent, position the scan for the first
            dirent of the following file.  Used when not interested in
            all of the details for the current file and are looking for
            the next file.

        - Update a common dirent structure with the details of the on-disk
            structure.  This is used to smooth out the differences

        - Build the filename (name and version strings) out of the stream
            of bytes in the file name on disk.  For Joliet disks we will have
            to convert to little endian.


--*/

#include "CdProcs.h"

//
//  The Bug check file id for this module
//

#define BugCheckFileId                   (CDFS_BUG_CHECK_DIRSUP)

//
//  Local macros
//

//
//  PRAW_DIRENT
//  CdRawDirent (
//      IN PIRP_CONTEXT IrpContext,
//      IN PDIR_ENUM_CONTEXT DirContext
//      );
//

#define CdRawDirent(IC,DC)                                      \
    Add2Ptr( (DC)->Sector, (DC)->SectorOffset, PRAW_DIRENT )

//
//  Local support routines
//

ULONG
CdCheckRawDirentBounds (
    IN PIRP_CONTEXT IrpContext,
    IN PDIRENT_ENUM_CONTEXT DirContext
    );

XA_EXTENT_TYPE
CdCheckForXAExtent (
    IN PIRP_CONTEXT IrpContext,
    IN PRAW_DIRENT RawDirent,
    IN OUT PDIRENT Dirent
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, CdCheckForXAExtent)
#pragma alloc_text(PAGE, CdCheckRawDirentBounds)
#pragma alloc_text(PAGE, CdCleanupFileContext)
#pragma alloc_text(PAGE, CdFindFile)
#pragma alloc_text(PAGE, CdFindDirectory)
#pragma alloc_text(PAGE, CdFindFileByShortName)
#pragma alloc_text(PAGE, CdLookupDirent)
#pragma alloc_text(PAGE, CdLookupLastFileDirent)
#pragma alloc_text(PAGE, CdLookupNextDirent)
#pragma alloc_text(PAGE, CdLookupNextInitialFileDirent)
#pragma alloc_text(PAGE, CdUpdateDirentFromRawDirent)
#pragma alloc_text(PAGE, CdUpdateDirentName)
#endif


VOID
CdLookupDirent (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN ULONG DirentOffset,
    OUT PDIRENT_ENUM_CONTEXT DirContext
    )

/*++

Routine Description:

    This routine is called to initiate a walk through a directory.  We will
    position ourselves in the directory at offset DirentOffset.  We know that
    a dirent begins at this boundary but may have to verify the dirent bounds.
    We will call this routine when looking up the first entry of a known
    file or verifying the self entry of a directory.

Arguments:

    Fcb - Fcb for the directory being traversed.

    DirentOffset - This is our target point in the directory.  We will map the
        page containing this entry and possibly verify the dirent bounds at
        this location.

    DirContext - This is the dirent context for this scan.  We update it with
        the location of the dirent we found.  This structure has been initialized
        outside of this call.

Return Value:

    None.

--*/

{
    LONGLONG BaseOffset;

    PAGED_CODE();

    //
    //  Initialize the offset of the first dirent we want to map.
    //

    DirContext->BaseOffset = SectorTruncate( DirentOffset );
    BaseOffset = DirContext->BaseOffset;

    DirContext->DataLength = SECTOR_SIZE;

    DirContext->SectorOffset = SectorOffset( DirentOffset );

    //
    //  Truncate the data length if we are at the end of the file.
    //

    if (DirContext->DataLength > (Fcb->FileSize.QuadPart - BaseOffset)) {

        DirContext->DataLength = (ULONG) (Fcb->FileSize.QuadPart - BaseOffset);
    }

    //
    //  Now map the data at this offset.
    //

    CcMapData( Fcb->FileObject,
               (PLARGE_INTEGER) &BaseOffset,
               DirContext->DataLength,
               TRUE,
               &DirContext->Bcb,
               &DirContext->Sector );

    //
    //  Verify the dirent bounds.
    //

    DirContext->NextDirentOffset = CdCheckRawDirentBounds( IrpContext,
                                                           DirContext );

    return;
}


BOOLEAN
CdLookupNextDirent (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PDIRENT_ENUM_CONTEXT CurrentDirContext,
    OUT PDIRENT_ENUM_CONTEXT NextDirContext
    )

/*++

Routine Description:

    This routine is called to find the next dirent in the directory.  The
    current position is given and we look for the next.  We leave the context
    for the starting position untouched and update the context for the
    dirent we found.  The target context may already be initialized so we
    may already have the sector in memory.

    This routine will position the enumeration context for the next dirent and
    verify the dirent bounds.

    NOTE - This routine can be called with CurrentDirContext and NextDirContext
        pointing to the same enumeration context.

Arguments:

    Fcb - Fcb for the directory being traversed.

    CurrentDirContext - This is the dirent context for this scan.  We update
        it with the location of the dirent we found.  This is currently
        pointing to a dirent location.  The dirent bounds at this location
        have already been verified.

    NextDirContext - This is the dirent context to update with the dirent we
        find.  This may already point to a dirent so we need to check if
        we are in the same sector and unmap any buffer as necessary.

        This dirent is left in an indeterminant state if we don't find a dirent.

Return Value:

    BOOLEAN - TRUE if we find a location for the next dirent, FALSE otherwise.
        This routine can cause a raise if the directory is corrupt.

--*/

{
    LONGLONG CurrentBaseOffset = CurrentDirContext->BaseOffset;
    ULONG TempUlong;

    BOOLEAN FoundDirent = FALSE;

    PAGED_CODE();

    //
    //  Check if a different sector is mapped.  If so then move our target
    //  enumeration context to the same sector.
    //

    if ((CurrentDirContext->BaseOffset != NextDirContext->BaseOffset) ||
        (NextDirContext->Bcb == NULL)) {

        //
        //  Unpin the current target Bcb and map the next sector.
        //

        CdUnpinData( IrpContext, &NextDirContext->Bcb );

        CcMapData( Fcb->FileObject,
                   (PLARGE_INTEGER) &CurrentBaseOffset,
                   CurrentDirContext->DataLength,
                   TRUE,
                   &NextDirContext->Bcb,
                   &NextDirContext->Sector );

        //
        //  Copy the data length and sector offset.
        //

        NextDirContext->DataLength = CurrentDirContext->DataLength;
        NextDirContext->BaseOffset = CurrentDirContext->BaseOffset;
    }

    //
    //  Now move to the same offset in the sector.
    //

    NextDirContext->SectorOffset = CurrentDirContext->SectorOffset;

    //
    //  If the value is zero then unmap the current sector and set up
    //  the base offset to the beginning of the next sector.
    //

    if (CurrentDirContext->NextDirentOffset == 0) {

        CurrentBaseOffset = NextDirContext->BaseOffset + NextDirContext->DataLength;

        //
        //  Unmap the current sector.  We test the value of the Bcb in the
        //  loop below to see if we need to read in another sector.
        //

        CdUnpinData( IrpContext, &NextDirContext->Bcb );

    //
    //  There is another possible dirent in the current sector.  Update the
    //  enumeration context to reflect this.
    //

    } else {

        NextDirContext->SectorOffset += CurrentDirContext->NextDirentOffset;
    }

    //
    //  Now loop until we find the next possible dirent or walk off the directory.
    //

    while (TRUE) {

        //
        //  If we don't currently have a sector mapped then map the
        //  directory at the current offset.
        //

        if (NextDirContext->Bcb == NULL) {

            TempUlong = SECTOR_SIZE;

            if (TempUlong > (ULONG) (Fcb->FileSize.QuadPart - CurrentBaseOffset)) {

                TempUlong = (ULONG) (Fcb->FileSize.QuadPart - CurrentBaseOffset);

                //
                //  If the length is zero then there is no dirent.
                //

                if (TempUlong == 0) {

                    break;
                }
            }

            CcMapData( Fcb->FileObject,
                       (PLARGE_INTEGER) &CurrentBaseOffset,
                       TempUlong,
                       TRUE,
                       &NextDirContext->Bcb,
                       &NextDirContext->Sector );

            NextDirContext->BaseOffset = (ULONG) CurrentBaseOffset;
            NextDirContext->SectorOffset = 0;
            NextDirContext->DataLength = TempUlong;
        }

        //
        //  The CDFS spec allows for sectors in a directory to contain all zeroes.
        //  In this case we need to move to the next sector.  So look at the
        //  current potential dirent for a zero length.  Move to the next
        //  dirent if length is zero.
        //

        if (*((PCHAR) CdRawDirent( IrpContext, NextDirContext )) != 0) {

            FoundDirent = TRUE;
            break;
        }

        CurrentBaseOffset = NextDirContext->BaseOffset + NextDirContext->DataLength;
        CdUnpinData( IrpContext, &NextDirContext->Bcb );
    }

    //
    //  Check the dirent bounds if we found a dirent.
    //

    if (FoundDirent) {

        NextDirContext->NextDirentOffset = CdCheckRawDirentBounds( IrpContext,
                                                                   NextDirContext );
    }

    return FoundDirent;
}


VOID
CdUpdateDirentFromRawDirent (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PDIRENT_ENUM_CONTEXT DirContext,
    IN OUT PDIRENT Dirent
    )

/*++

Routine Description:

    This routine is called to safely copy the data from the dirent on disk
    to the in-memory dirent.  The fields on disk are unaligned so we
    need to safely copy them to our structure.

Arguments:

    Fcb - Fcb for the directory being scanned.

    DirContext - Enumeration context for the raw disk dirent.

    Dirent - In-memory dirent to update.

Return Value:

    None.

--*/

{
    PRAW_DIRENT RawDirent = CdRawDirent( IrpContext, DirContext );

    PAGED_CODE();

    //
    //  Clear all of the current state flags except the flag indicating that
    //  we allocated a name string.
    //

    ClearFlag( Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT );

    //
    //  The dirent offset is the sum of the start of the sector and the
    //  sector offset.
    //

    Dirent->DirentOffset = DirContext->BaseOffset + DirContext->SectorOffset;

    //
    //  Copy the dirent length from the raw dirent.
    //

    Dirent->DirentLength = RawDirent->DirLen;

    //
    //  The starting offset on disk is computed by finding the starting
    //  logical block and stepping over the Xar block.
    //

    CopyUchar4( &Dirent->StartingOffset, RawDirent->FileLoc );

    Dirent->StartingOffset += RawDirent->XarLen;

    //
    //  Do a safe copy to get the data length.
    //

    CopyUchar4( &Dirent->DataLength, RawDirent->DataLen );

    //

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -