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

📄 dirctrl.c

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

Copyright (c) 1989-2000 Microsoft Corporation

Module Name:

    DirCtrl.c

Abstract:

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


--*/

#include "CdProcs.h"

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

#define BugCheckFileId                   (CDFS_BUG_CHECK_DIRCTRL)

//
//  Local support routines
//

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

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

VOID
CdInitializeEnumeration (
    IN PIRP_CONTEXT IrpContext,
    IN PIO_STACK_LOCATION IrpSp,
    IN PFCB Fcb,
    IN OUT PCCB Ccb,
    IN OUT PFILE_ENUM_CONTEXT FileContext,
    OUT PBOOLEAN ReturnNextEntry,
    OUT PBOOLEAN ReturnSingleEntry,
    OUT PBOOLEAN InitialQuery
    );

BOOLEAN
CdEnumerateIndex (
    IN PIRP_CONTEXT IrpContext,
    IN PCCB Ccb,
    IN OUT PFILE_ENUM_CONTEXT FileContext,
    IN BOOLEAN ReturnNextEntry
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, CdCommonDirControl)
#pragma alloc_text(PAGE, CdEnumerateIndex)
#pragma alloc_text(PAGE, CdInitializeEnumeration)
#pragma alloc_text(PAGE, CdNotifyChangeDirectory)
#pragma alloc_text(PAGE, CdQueryDirectory)
#endif


NTSTATUS
CdCommonDirControl (
    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 (CdDecodeFileObject( IrpContext,
                            IrpSp->FileObject,
                            &Fcb,
                            &Ccb ) != UserDirectoryOpen) {

        CdCompleteRequest( 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 = CdQueryDirectory( IrpContext, Irp, IrpSp, Fcb, Ccb );
        break;

    case IRP_MN_NOTIFY_CHANGE_DIRECTORY:

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

    default:

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

    return Status;
}


//
//  Local support routines
//

NTSTATUS
CdQueryDirectory (
    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 SeparatorBytes;
    ULONG VersionStringBytes;

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

    PCHAR UserBuffer;
    ULONG BytesRemainingInBuffer;

    ULONG BaseLength;

    PFILE_BOTH_DIR_INFORMATION DirInfo;
    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.

⌨️ 快捷键说明

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