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

📄 dirsup.c

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

Copyright (c) 1989-2000 Microsoft Corporation

Module Name:

    DirSup.c

Abstract:

    This module implements the dirent support routines for Fat.


--*/

#include "FatProcs.h"

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

#define BugCheckFileId                   (FAT_BUG_CHECK_DIRSUP)

//
//  Local debug trace level
//

#define Dbg                              (DEBUG_TRACE_DIRSUP)

//
//  The following three macro all assume the input dirent has been zeroed.
//

//
//  VOID
//  FatConstructDot (
//      IN PIRP_CONTEXT IrpContext,
//      IN PDCB Directory,
//      IN PDIRENT ParentDirent,
//      IN OUT PDIRENT Dirent
//      );
//
//  The following macro is called to initalize the "." dirent.
//
//  Always setting FirstClusterOfFileHi is OK because it will be zero
//  unless we're working on a FAT 32 disk.
//

#define FatConstructDot(IRPCONTEXT,DCB,PARENT,DIRENT) {                  \
                                                                         \
    RtlCopyMemory( (PUCHAR)(DIRENT), ".          ", 11 );                \
    (DIRENT)->Attributes = FAT_DIRENT_ATTR_DIRECTORY;                    \
    (DIRENT)->LastWriteTime = (PARENT)->LastWriteTime;                   \
    if (FatData.ChicagoMode) {                                           \
        (DIRENT)->CreationTime = (PARENT)->CreationTime;                 \
        (DIRENT)->CreationMSec = (PARENT)->CreationMSec;                 \
        (DIRENT)->LastAccessDate = (PARENT)->LastAccessDate;             \
    }                                                                    \
    (DIRENT)->FirstClusterOfFile =                                       \
            (USHORT)(DCB)->FirstClusterOfFile;                           \
    (DIRENT)->FirstClusterOfFileHi =                                     \
            (USHORT)((DCB)->FirstClusterOfFile/0x10000);                 \
}

//
//  VOID
//  FatConstructDotDot (
//      IN PIRP_CONTEXT IrpContext,
//      IN PDCB Directory,
//      IN PDIRENT ParentDirent,
//      IN OUT PDIRENT Dirent
//      );
//
//  The following macro is called to initalize the ".." dirent.
//
//  Always setting FirstClusterOfFileHi is OK because it will be zero
//  unless we're working on a FAT 32 disk.
//

#define FatConstructDotDot(IRPCONTEXT,DCB,PARENT,DIRENT) {   \
                                                             \
    RtlCopyMemory( (PUCHAR)(DIRENT), "..         ", 11 );    \
    (DIRENT)->Attributes = FAT_DIRENT_ATTR_DIRECTORY;        \
    (DIRENT)->LastWriteTime = (PARENT)->LastWriteTime;       \
    if (FatData.ChicagoMode) {                               \
        (DIRENT)->CreationTime = (PARENT)->CreationTime;     \
        (DIRENT)->CreationMSec = (PARENT)->CreationMSec;     \
        (DIRENT)->LastAccessDate = (PARENT)->LastAccessDate; \
    }                                                        \
    if (NodeType((DCB)->ParentDcb) == FAT_NTC_ROOT_DCB) {    \
        (DIRENT)->FirstClusterOfFile = 0;                    \
        (DIRENT)->FirstClusterOfFileHi = 0;                  \
    } else {                                                 \
        (DIRENT)->FirstClusterOfFile = (USHORT)              \
            ((DCB)->ParentDcb->FirstClusterOfFile);          \
        (DIRENT)->FirstClusterOfFileHi = (USHORT)            \
            ((DCB)->ParentDcb->FirstClusterOfFile/0x10000);  \
    }                                                        \
}

//
//  VOID
//  FatConstructEndDirent (
//      IN PIRP_CONTEXT IrpContext,
//      IN OUT PDIRENT Dirent
//      );
//
//  The following macro created the end dirent.  Note that since the
//  dirent was zeroed, the first byte of the name already contains 0x0,
//  so there is nothing to do.
//

#define FatConstructEndDirent(IRPCONTEXT,DIRENT) NOTHING

//
//  VOID
//  FatReadDirent (
//      IN PIRP_CONTEXT IrpContext,
//      IN PDCB Dcb,
//      IN VBO Vbo,
//      OUT PBCB *Bcb,
//      OUT PVOID *Dirent,
//      OUT PNTSTATUS Status
//      );
//

//
//  This macro reads in a page of dirents when we step onto a new page,
//  or this is the first iteration of a loop and Bcb is NULL.
//

#define FatReadDirent(IRPCONTEXT,DCB,VBO,BCB,DIRENT,STATUS)       \
if ((VBO) >= (DCB)->Header.AllocationSize.LowPart) {              \
    *(STATUS) = STATUS_END_OF_FILE;                               \
    FatUnpinBcb( (IRPCONTEXT), *(BCB) );                          \
} else if ( ((VBO) % PAGE_SIZE == 0) || (*(BCB) == NULL) ) {      \
    FatUnpinBcb( (IRPCONTEXT), *(BCB) );                          \
    FatReadDirectoryFile( (IRPCONTEXT),                           \
                          (DCB),                                  \
                          (VBO) & ~(PAGE_SIZE - 1),               \
                          PAGE_SIZE,                              \
                          FALSE,                                  \
                          (BCB),                                  \
                          (PVOID *)(DIRENT),                      \
                          (STATUS) );                             \
    *(DIRENT) = (PVOID)((PUCHAR)*(DIRENT) + ((VBO) % PAGE_SIZE)); \
}

//
//  Internal support routines
//

UCHAR
FatComputeLfnChecksum (
    PDIRENT Dirent
    );

VOID
FatRescanDirectory (
    PIRP_CONTEXT IrpContext,
    PDCB Dcb
    );

ULONG
FatDefragDirectory (
    IN PIRP_CONTEXT IrpContext,
    IN PDCB Dcb,
    IN ULONG DirentsNeeded
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FatComputeLfnChecksum)
#pragma alloc_text(PAGE, FatConstructDirent)
#pragma alloc_text(PAGE, FatConstructLabelDirent)
#pragma alloc_text(PAGE, FatCreateNewDirent)
#pragma alloc_text(PAGE, FatDefragDirectory)
#pragma alloc_text(PAGE, FatDeleteDirent)
#pragma alloc_text(PAGE, FatGetDirentFromFcbOrDcb)
#pragma alloc_text(PAGE, FatInitializeDirectoryDirent)
#pragma alloc_text(PAGE, FatIsDirectoryEmpty)
#pragma alloc_text(PAGE, FatLfnDirentExists)
#pragma alloc_text(PAGE, FatLocateDirent)
#pragma alloc_text(PAGE, FatLocateSimpleOemDirent)
#pragma alloc_text(PAGE, FatLocateVolumeLabel)
#pragma alloc_text(PAGE, FatRescanDirectory)
#pragma alloc_text(PAGE, FatSetFileSizeInDirent)
#pragma alloc_text(PAGE, FatTunnelFcbOrDcb)
#pragma alloc_text(PAGE, FatUpdateDirentFromFcb)
#endif


ULONG
FatCreateNewDirent (
    IN PIRP_CONTEXT IrpContext,
    IN PDCB ParentDirectory,
    IN ULONG DirentsNeeded
    )

/*++

Routine Description:

    This routine allocates on the disk a new dirent inside of the
    parent directory.  If a new dirent cannot be allocated (i.e.,
    because the disk is full or the root directory is full) then
    it raises the appropriate status.  The dirent itself is
    neither initialized nor pinned by this procedure.
    
Arguments:

    ParentDirectory - Supplies the DCB for the directory in which
        to create the new dirent

    DirentsNeeded - This is the number of continginous dirents required

Return Value:

    ByteOffset - Returns the VBO within the Parent directory where
        the dirent has been allocated

--*/

{
    VBO UnusedVbo;
    VBO DeletedHint;
    ULONG ByteOffset;

    PBCB Bcb = NULL;
    PDIRENT Dirent;
    NTSTATUS Status = STATUS_SUCCESS;

    PAGED_CODE();

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

    DebugTrace( 0, Dbg, "  ParentDirectory = %08lx\n", ParentDirectory);

    //
    //  If UnusedDirentVbo is within our current file allocation then we
    //  don't have to search through the directory at all; we know just
    //  where to put it.
    //
    //  If UnusedDirentVbo is beyond the current file allocation then
    //  there are no more unused dirents in the current allocation, though
    //  upon adding another cluster of allocation UnusedDirentVbo
    //  will point to an unused dirent.  Haveing found no unused dirents
    //  we use the DeletedDirentHint to try and find a deleted dirent in
    //  the current allocation.  In this also runs off the end of the file,
    //  we finally have to break down and allocate another sector.  Note
    //  that simply writing beyond the current allocation will automatically
    //  do just this.
    //
    //  We also must deal with the special case where UnusedDirentVbo and
    //  DeletedDirentHint have yet to be initialized.  In this case we must
    //  first walk through the directory looking for the first deleted entry
    //  first unused dirent.  After this point we continue as before.
    //  This virgin state is denoted by the special value of 0xffffffff.
    //

    UnusedVbo = ParentDirectory->Specific.Dcb.UnusedDirentVbo;
    DeletedHint = ParentDirectory->Specific.Dcb.DeletedDirentHint;

    //
    //  Check for our first call to this routine with this Dcb.  If so
    //  we have to correctly set the two hints in the Dcb.
    //

    if (UnusedVbo == 0xffffffff) {

        FatRescanDirectory( IrpContext, ParentDirectory );

        UnusedVbo = ParentDirectory->Specific.Dcb.UnusedDirentVbo;
        DeletedHint = ParentDirectory->Specific.Dcb.DeletedDirentHint;
    }

    //
    //  Now we know that UnusedDirentVbo and DeletedDirentHint are correctly
    //  set so we check if there is already an unused dirent in the the
    //  current allocation.  This is the easy case.
    //

    DebugTrace( 0, Dbg, "  UnusedVbo   = %08lx\n", UnusedVbo);
    DebugTrace( 0, Dbg, "  DeletedHint = %08lx\n", DeletedHint);

    if ( UnusedVbo + (DirentsNeeded * sizeof(DIRENT)) <=
         ParentDirectory->Header.AllocationSize.LowPart ) {

        //
        //  Get this unused dirent for the caller.  We have a
        //  sporting chance that we won't have to wait.
        //

        DebugTrace( 0, Dbg, "There is a never used entry.\n", 0);

        ByteOffset = UnusedVbo;

        UnusedVbo += DirentsNeeded * sizeof(DIRENT);

    } else {

        //
        //  Life is tough.  We have to march from the DeletedDirentHint
        //  looking for a deleted dirent.  If we get to EOF without finding
        //  one, we will have to allocate a new cluster.
        //

        ByteOffset =
            RtlFindClearBits( &ParentDirectory->Specific.Dcb.FreeDirentBitmap,
                              DirentsNeeded,
                              DeletedHint / sizeof(DIRENT) );

        //
        //  Do a quick check for a root directory allocation that failed
        //  simply because of fragmentation.  Also, only attempt to defrag
        //  if the length is less that 0x40000.  This is to avoid
        //  complications arising from crossing a MM view boundary (256kb).
        //  By default on DOS the root directory is only 0x2000 long.
        //
        //  Don't try to defrag fat32 root dirs.
        //

        if (!FatIsFat32(ParentDirectory->Vcb) &&
            (ByteOffset == -1) &&
            (NodeType(ParentDirectory) == FAT_NTC_ROOT_DCB) &&
            (ParentDirectory->Header.AllocationSize.LowPart <= 0x40000)) {

            ByteOffset = FatDefragDirectory( IrpContext, ParentDirectory, DirentsNeeded );
        }

        if (ByteOffset != -1) {

            //
            //  If we consuemed deleted dirents at Deleted Hint, update.
            //  We also may have consumed some un-used dirents as well,
            //  so be sure to check for that as well.
            //

            ByteOffset *= sizeof(DIRENT);

            if (ByteOffset == DeletedHint) {

                DeletedHint += DirentsNeeded * sizeof(DIRENT);
            }

            if (ByteOffset + DirentsNeeded * sizeof(DIRENT) > UnusedVbo) {

                UnusedVbo = ByteOffset + DirentsNeeded * sizeof(DIRENT);
            }

        } else {

            //
            //  We are going to have to allocate another cluster.  Do
            //  so, update both the UnusedVbo and the DeletedHint and bail.
            //

            DebugTrace( 0, Dbg, "We have to allocate another cluster.\n", 0);

            //
            //  A reason why we might fail, unrelated to physical reasons,
            //  is that we constrain to 64k directory entries to match the
            //  restriction on Win95.  There are fundamental reasons to do
            //  this since searching a FAT directory is a linear operation
            //  and to allow FAT32 to toss us over the cliff is not permissable.
            //

            if (ParentDirectory->Header.AllocationSize.LowPart >= (64 * 1024 * sizeof(DIRENT)) ||
                
                //
                //  Make sure we are not trying to expand the root directory on non
                //  FAT32.  FAT16 and FAT12 have fixed size allocations.
                //

                (!FatIsFat32(ParentDirectory->Vcb) &&
                 NodeType(ParentDirectory) == FAT_NTC_ROOT_DCB)) {
                    
                DebugTrace(0, Dbg, "Full root directory or too big on FAT32.  Raise Status.\n", 0);

                FatRaiseStatus( IrpContext, STATUS_CANNOT_MAKE );
            }

            //
            //  Take the last dirent(s) in this cluster.  We will allocate
            //  more clusters below.
            //

            ByteOffset = UnusedVbo;
            UnusedVbo += DirentsNeeded * sizeof(DIRENT);

            //
            //  Touch the directory file to cause space for the new dirents
            //  to be allocated.
            //

            Bcb = NULL;

            try {

                ULONG ClusterSize;
                PVOID Buffer;

                ClusterSize =
                    1 << ParentDirectory->Vcb->AllocationSupport.LogOfBytesPerCluster;

                FatPrepareWriteDirectoryFile( IrpContext,
                                              ParentDirectory,
                                              UnusedVbo,
                                              1,
                                              &Bcb,
                                              &Buffer,
                                              FALSE,
                                              TRUE,
                                              &Status );

            } finally {

                FatUnpinBcb( IrpContext, Bcb );
            }
        }
    }

    //
    //  If we are only requesting a single dirent, and we did not get the
    //  first dirent in a directory, then check that the preceding dirent
    //  is not an orphaned LFN.  If it is, then mark it deleted.  Thus
    //  reducing the possibility of an accidental pairing.

⌨️ 快捷键说明

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