dirctrl.c

来自「windows 2000中的UDF文件系统的驱动程序.只有读的功能,不支持未关闭」· C语言 代码 · 共 1,926 行 · 第 1/4 页

C
1,926
字号
/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    DirCtrl.c

Abstract:

    This module implements the File Directory Control routines for Udfs called
    by the Fsd/Fsp dispatch drivers.

Author:

    Dan Lovinger    [DanLo]     27-Nov-1996

Revision History:

--*/

#include "UdfProcs.h"

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

#define BugCheckFileId                   (UDFS_BUG_CHECK_DIRCTRL)

//
//  The local debug trace level
//

#define Dbg                              (UDFS_DEBUG_LEVEL_DIRCTRL)

//
//  Local structures
//

//
//  The following is used for the more complete enumeration required in the DirectoryControl path
//  and encapsulates the structures for enumerating both directories and ICBs, as well as converted
//  data from the ICB.
//

typedef struct _COMPOUND_DIR_ENUM_CONTEXT {

    //
    //  Standard enumeration contexts.  For this enumeration we walk the directory and lift the
    //  associated ICB for each entry.
    //
    
    DIR_ENUM_CONTEXT DirContext;
    ICB_SEARCH_CONTEXT IcbContext;

    //
    //  Timestamps converted from the ICB into NT-native form.
    //

    TIMESTAMP_BUNDLE Timestamps;

    //
    //  File index corresponding to the current position in the enumeration.
    //

    LARGE_INTEGER FileIndex;

} COMPOUND_DIR_ENUM_CONTEXT, *PCOMPOUND_DIR_ENUM_CONTEXT;

//
//  Local macros
//

//
//  Constants defining the space of FileIndices for directory enumeration.
//

//
//  The virtual (synthesized) file indices
//

#define UDF_FILE_INDEX_VIRTUAL_SELF         0

//
//  The file index where the physical directory entries begin
//

#define UDF_FILE_INDEX_PHYSICAL             1

//
//  Provide initialization and cleanup for compound enumeration contexts.
//

INLINE
VOID
UdfInitializeCompoundDirContext (
    IN PIRP_CONTEXT IrpContext,
    IN PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext
    )
{

    UdfInitializeDirContext( IrpContext, &CompoundDirContext->DirContext );
    UdfFastInitializeIcbContext( IrpContext, &CompoundDirContext->IcbContext );

    RtlZeroMemory( &CompoundDirContext->Timestamps, sizeof( TIMESTAMP_BUNDLE ));

    CompoundDirContext->FileIndex.QuadPart = 0;
}

INLINE
VOID
UdfCleanupCompoundDirContext (
    IN PIRP_CONTEXT IrpContext,
    IN PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext
    )
{

    UdfCleanupDirContext( IrpContext, &CompoundDirContext->DirContext );
    UdfCleanupIcbContext( IrpContext, &CompoundDirContext->IcbContext );
}

//
//  UDF directories are unsorted (UDF 1.0.1 2.3.5.3) and do not contain self
//  entries.  For directory enumeration we must provide a way for a restart to
//  occur at a random entry (SL_INDEX_SPECIFIED), but the key used is only
//  32bits.  Since the directory is unsorted, the filename is unsuitable for
//  quickly finding a restart point (even assuming that it was sorted,
//  discovering a directory entry is still not fast).  Additionally, we must
//  synthesize the self-entry.  So, here is how we map the space of file
//  indices to directory entries:
//
//    File Index              Directory Entry
//  
//    0                       self ('.')
//    1                       at byte offset 0 in the stream
//    N                       at byte offset N-1 in the stream
//  
//  The highest 32bit FileIndex returned will be stashed in the Ccb.
//  
//  For FileIndex > 2^32, we will return FileIndex 0 in the query structure.
//  On a restart, we will notice a FileIndex of zero and use the saved high
//  32bit FileIndex as the starting point for a linear scan to find the named
//  directory entry in the restart request.  In this way we only penalize the
//  improbable case of a directory stream > 2^32 bytes.
//
//  The following inline routines assist with this mapping.
//

INLINE
LONGLONG
UdfFileIndexToPhysicalOffset(
    LONGLONG FileIndex
    )
{

    return FileIndex - UDF_FILE_INDEX_PHYSICAL;
}

INLINE
LONGLONG
UdfPhysicalOffsetToFileIndex(
    LONGLONG PhysicalOffset
    )
{

    return PhysicalOffset + UDF_FILE_INDEX_PHYSICAL;
}

INLINE
BOOLEAN
UdfIsFileIndexVirtual(
   LONGLONG FileIndex
   )
{

    return FileIndex < UDF_FILE_INDEX_PHYSICAL;
}

//
//  Local support routines
//

NTSTATUS
UdfQueryDirectory (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp,
    IN PIO_STACK_LOCATION IrpSp,
    IN PFCB Fcb,
    IN PCCB Ccb
    );

NTSTATUS
UdfNotifyChangeDirectory (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp,
    IN PIO_STACK_LOCATION IrpSp,
    IN PCCB Ccb
    );

VOID
UdfInitializeEnumeration (
    IN PIRP_CONTEXT IrpContext,
    IN PIO_STACK_LOCATION IrpSp,
    IN PFCB Fcb,
    IN OUT PCCB Ccb,
    IN OUT PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext,
    OUT PBOOLEAN ReturnNextEntry,
    OUT PBOOLEAN ReturnSingleEntry,
    OUT PBOOLEAN InitialQuery
    );

BOOLEAN
UdfEnumerateIndex (
    IN PIRP_CONTEXT IrpContext,
    IN PCCB Ccb,
    IN OUT PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext,
    IN BOOLEAN ReturnNextEntry
    );

VOID
UdfLookupFileEntryInEnumeration (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext
    );

BOOLEAN
UdfLookupInitialFileIndex (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext,
    IN PLONGLONG InitialIndex
    );

BOOLEAN
UdfLookupNextFileIndex (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, UdfCommonDirControl)
#pragma alloc_text(PAGE, UdfEnumerateIndex)
#pragma alloc_text(PAGE, UdfInitializeEnumeration)
#pragma alloc_text(PAGE, UdfLookupFileEntryInEnumeration)
#pragma alloc_text(PAGE, UdfLookupInitialFileIndex)
#pragma alloc_text(PAGE, UdfLookupNextFileIndex)
#pragma alloc_text(PAGE, UdfNotifyChangeDirectory)
#pragma alloc_text(PAGE, UdfQueryDirectory)
#endif


NTSTATUS
UdfCommonDirControl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine is the entry point for the directory control operations.  These
    are directory enumerations and directory notify calls.  We verify the
    user's handle is for a directory and then call the appropriate routine.

Arguments:

    Irp - Irp for this request.

Return Value:

    NTSTATUS - Status returned from the lower level routines.

--*/

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

    PFCB Fcb;
    PCCB Ccb;

    PAGED_CODE();

    //
    //  Decode the user file object and fail this request if it is not
    //  a user directory.
    //

    if (UdfDecodeFileObject( IrpSp->FileObject,
                             &Fcb,
                             &Ccb ) != UserDirectoryOpen) {

        UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
        return STATUS_INVALID_PARAMETER;
    }

    //
    //  We know this is a directory control so we'll case on the
    //  minor function, and call a internal worker routine to complete
    //  the irp.
    //

    switch (IrpSp->MinorFunction) {

    case IRP_MN_QUERY_DIRECTORY:

        Status = UdfQueryDirectory( IrpContext, Irp, IrpSp, Fcb, Ccb );
        break;

    case IRP_MN_NOTIFY_CHANGE_DIRECTORY:

        Status = UdfNotifyChangeDirectory( IrpContext, Irp, IrpSp, Ccb );
        break;

    default:

        UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
        Status = STATUS_INVALID_DEVICE_REQUEST;
        break;
    }

    return Status;
}


//
//  Local support routines
//

NTSTATUS
UdfQueryDirectory (
    IN PIRP_CONTEXT IrpContext,
    IN 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 BytesConverted;

    COMPOUND_DIR_ENUM_CONTEXT CompoundDirContext;

    PNSR_FID ThisFid;
    PICBFILE ThisFe;
    
    BOOLEAN InitialQuery;
    BOOLEAN ReturnNextEntry;
    BOOLEAN ReturnSingleEntry;
    BOOLEAN Found;

    PCHAR UserBuffer;
    ULONG BytesRemainingInBuffer;

    ULONG BaseLength;

    PFILE_BOTH_DIR_INFORMATION DirInfo;
    PFILE_NAMES_INFORMATION NamesInfo;

    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 FileNamesInformation:

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

    case FileBothDirectoryInformation:

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

    default:

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

    //
    //  Get the user buffer.
    //

    UdfMapUserBuffer( IrpContext, &UserBuffer);

    //
    //  Initialize our search context.
    //

    UdfInitializeCompoundDirContext( IrpContext, &CompoundDirContext );
    
    //
    //  Acquire the directory.
    //

    UdfAcquireFileShared( IrpContext, Fcb );

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

    try {

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

        UdfVerifyFcbOperation( 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.
        //

        UdfInitializeEnumeration( IrpContext,
                                  IrpSp,
                                  Fcb,
                                  Ccb,
                                  &CompoundDirContext,
                                  &ReturnNextEntry,
                                  &ReturnSingleEntry,
                                  &InitialQuery );

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

⌨️ 快捷键说明

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