dirctrl.c

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

C
1,926
字号
        //  only deals with memory matching.
        //

        FsRtlNotifyFullChangeDirectory( IrpContext->Vcb->NotifySync,
                                        &IrpContext->Vcb->DirNotifyList,
                                        Ccb,
                                        (PSTRING) &IrpSp->FileObject->FileName,
                                        BooleanFlagOn( IrpSp->Flags, SL_WATCH_TREE ),
                                        FALSE,
                                        IrpSp->Parameters.NotifyDirectory.CompletionFilter,
                                        Irp,
                                        NULL,
                                        NULL );

    } finally {

        //
        //  Release the Vcb.
        //

        UdfReleaseVcb( IrpContext, IrpContext->Vcb );
    }

    //
    //  Cleanup the IrpContext.
    //

    UdfCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );

    return STATUS_PENDING;
}


//
//  Local support routine
//

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
    )

/*++

Routine Description:

    This routine is called to initialize the enumeration variables and structures.
    We look at the state of a previous enumeration from the Ccb as well as any
    input values from the user.  On exit we will position the DirContext at
    a file in the directory and let the caller know whether this entry or the
    next entry should be returned.

Arguments:

    IrpSp - Irp stack location for this request.

    Fcb - Fcb for this directory.

    Ccb - Ccb for the directory handle.

    CompoundDirContext - Context to use for this enumeration.

    ReturnNextEntry - Address to store whether we should return the entry at
        the context position or the next entry.

    ReturnSingleEntry - Address to store whether we should only return
        a single entry.

    InitialQuery - Address to store whether this is the first enumeration
        query on this handle.

Return Value:

    None.

--*/

{
    NTSTATUS Status;

    PUNICODE_STRING FileName;
    UNICODE_STRING SearchExpression;

    PUNICODE_STRING RestartName = NULL;
    
    ULONG CcbFlags;

    LONGLONG FileIndex;
    ULONG HighFileIndex;
    BOOLEAN KnownIndex;

    BOOLEAN Found;

    PAGED_CODE();

    //
    //  Check inputs.
    //

    ASSERT_IRP_CONTEXT( IrpContext );
    ASSERT_FCB_INDEX( Fcb );
    ASSERT_CCB( Ccb );

    //
    //  If this is the initial query then build a search expression from the input
    //  file name.
    //

    if (!FlagOn( Ccb->Flags, CCB_FLAG_ENUM_INITIALIZED )) {

        FileName = (PUNICODE_STRING) IrpSp->Parameters.QueryDirectory.FileName;

        CcbFlags = 0;

        //
        //  If the filename is not specified or is a single '*' then we will
        //  match all names.
        //

        if ((FileName == NULL) ||
            (FileName->Buffer == NULL) ||
            (FileName->Length == 0) ||
            ((FileName->Length == sizeof( WCHAR )) &&
             (FileName->Buffer[0] == L'*'))) {

            SetFlag( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL );

            SearchExpression.Length =
            SearchExpression.MaximumLength = 0;
            SearchExpression.Buffer = NULL;

        //
        //  Otherwise build the name from the name in the stack location.
        //  This involves checking for wild card characters and upcasing the
        //  string if this is a case-insensitive search.
        //

        } else {

            //
            //  The name better have at least one character.
            //

            if (FileName->Length == 0) {

                UdfRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER );
            }

            //
            //  Check for wildcards in the separate components.
            //

            if (FsRtlDoesNameContainWildCards( FileName)) {

                SetFlag( CcbFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD );
            }
            
            //
            //  Now create the search expression to store in the Ccb.
            //

            SearchExpression.Buffer = FsRtlAllocatePoolWithTag( UdfPagedPool,
                                                                FileName->Length,
                                                                TAG_ENUM_EXPRESSION );

            SearchExpression.MaximumLength = FileName->Length;

            //
            //  Either copy the name directly or perform the upcase.
            //

            if (FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE )) {

                Status = RtlUpcaseUnicodeString( &SearchExpression,
                                                 FileName,
                                                 FALSE );

                //
                //  This should never fail.
                //

                ASSERT( Status == STATUS_SUCCESS );

            } else {

                RtlCopyMemory( SearchExpression.Buffer,
                               FileName->Buffer,
                               FileName->Length );
            }

            SearchExpression.Length = FileName->Length;
        }

        //
        //  But we do not want to return the constant "." and ".." entries for
        //  the root directory, for consistency with the rest of Microsoft's
        //  filesystems.
        //

        if (Fcb == Fcb->Vcb->RootIndexFcb) {

            SetFlag( CcbFlags, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY );
        }

        //
        //  Now lock the Fcb in order to update the Ccb with the inital
        //  enumeration values.
        //

        UdfLockFcb( IrpContext, Fcb );

        //
        //  Check again that this is the initial search.
        //

        if (!FlagOn( Ccb->Flags, CCB_FLAG_ENUM_INITIALIZED )) {

            //
            //  Update the values in the Ccb.
            //

            Ccb->CurrentFileIndex = 0;
            Ccb->SearchExpression = SearchExpression;

            //
            //  Set the appropriate flags in the Ccb.
            //

            SetFlag( Ccb->Flags, CcbFlags | CCB_FLAG_ENUM_INITIALIZED );

        //
        //  Otherwise cleanup any buffer allocated here.
        //

        } else {

            if (!FlagOn( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL )) {

                UdfFreePool( &SearchExpression.Buffer );
            }
        }

    //
    //  Otherwise lock the Fcb so we can read the current enumeration values.
    //

    } else {

        UdfLockFcb( IrpContext, Fcb );
    }

    //
    //  Capture the current state of the enumeration.
    //
    //  If the user specified an index then use his offset.  We always
    //  return the next entry in this case.  If  no name is specified,
    //  then we can't perform the restart.
    //

    if (FlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED ) &&
        IrpSp->Parameters.QueryDirectory.FileName != NULL) {

        KnownIndex = FALSE;
        FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
        RestartName = (PUNICODE_STRING) IrpSp->Parameters.QueryDirectory.FileName;
        *ReturnNextEntry = TRUE;

        //
        //  We will use the highest file index reportable to the caller as a
        //  starting point as required if we cannot directly land at the
        //  specified location.
        //
        
        HighFileIndex = Ccb->HighestReturnableFileIndex;

    //
    //  If we are restarting the scan then go from the self entry.
    //

    } else if (FlagOn( IrpSp->Flags, SL_RESTART_SCAN )) {

        KnownIndex = TRUE;
        FileIndex = 0;
        *ReturnNextEntry = FALSE;

    //
    //  Otherwise use the values from the Ccb.
    //

    } else {

        KnownIndex = TRUE;
        FileIndex = Ccb->CurrentFileIndex;
        *ReturnNextEntry = BooleanFlagOn( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
    }

    //
    //  Unlock the Fcb.
    //

    UdfUnlockFcb( IrpContext, Fcb );

    //
    //  We have the starting offset in the directory and whether to return
    //  that entry or the next.  If we are at the beginning of the directory
    //  and are returning that entry, then tell our caller this is the
    //  initial query.
    //

    *InitialQuery = FALSE;

    if ((FileIndex == 0) &&
        !(*ReturnNextEntry)) {

        *InitialQuery = TRUE;
    }

    //
    //  Determine the offset in the stream to position the context and
    //  whether this offset is known to be a file offset.
    //
    //  If this offset is known to be safe then go ahead and position the
    //  context.  This handles the cases where the offset is the beginning
    //  of the stream, the offset is from a previous search or this is the
    //  initial query.
    //

    if (KnownIndex) {

        Found = UdfLookupInitialFileIndex( IrpContext, Fcb, CompoundDirContext, &FileIndex );

        ASSERT( Found );
        
    //
    //  Try to directly jump to the specified file index.  Otherwise we walk through
    //  the directory from the beginning (or the saved highest known offset if that is
    //  useful) until we reach the entry which contains this offset.
    //

    } else {
        
        //
        //  We need to handle the special case of a restart from a synthesized
        //  entry - this is the one time where the restart index can be zero
        //  without requiring us to search above the 2^32 byte mark.
        //
        
        if (UdfFullCompareNames( IrpContext,
                                 RestartName,
                                 &UdfUnicodeDirectoryNames[SELF_ENTRY] ) == EqualTo) {

            FileIndex = UDF_FILE_INDEX_VIRTUAL_SELF;

            Found = UdfLookupInitialFileIndex( IrpContext, Fcb, CompoundDirContext, &FileIndex );
    
            ASSERT( Found );
            
        //
        //  We are restarting from a physical entry.  If the restart index is zero, we were
        //  unable to inform the caller as to the "real" file index due to the dispartity
        //  between the ULONG FileIndex in the return structures and the LONGLONG offsets
        //  possible in directory streams.  In this case, we will go as high as we were able
        //  to inform the caller of and search linearly from that point forward.
        //
        //  It is also possible (realistic? unknown) that the restart index is somewhere in the
        //  middle of an entry and we won't find anything useable.  In this case we try to find
        //  the entry which contains this index, using it as the real restart point.
        //
        
        } else {

            //
            //  See if we need the high water mark.
            //
            
            if (FileIndex == 0) {

                //
                //  We know that this is good.
                //
                
                FileIndex = Max( Ccb->HighestReturnableFileIndex, UDF_FILE_INDEX_PHYSICAL );;
                KnownIndex = TRUE;
            
            }
            
            //
            //  The file index is now useful, falling into two cases
            //
            //      1) KnownIndex == FALSE - searching by index
            //      2) KnownIndex == TRUE  - searching by name
            //
            //  Go set up our inquiry.
            //

            Found = UdfLookupInitialFileIndex( IrpContext, Fcb, CompoundDirContext, &FileIndex );
            
            if (KnownIndex) {
                
                //
                //  Walk forward to discover an entry named per the caller's expectation.
                //
                
                do {
    
                    UdfUpdateDirNames( IrpContext,
                                       &CompoundDirContext->DirContext,
                                       BooleanFlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE ));
                    
                    if (UdfFullCompareNames( IrpContext,
                                             &CompoundDirContext->DirContext.CaseObjectName,
                                             RestartName ) == EqualTo) {

                        break;
                    }

                    Found = UdfLookupNextFileIndex( IrpContext, Fcb, CompoundDirContext );
    
                } while (Found);
            
            } else if (!Found) {

                LONGLONG LastFileIndex;

                //
                //  Perform the search for the entry by index from the beginning of the physical directory.
                //

                LastFileIndex = UDF_FILE_INDEX_PHYSICAL;

                Found = UdfLookupInitialFileIndex( IrpContext, Fcb, CompoundDirContext, &LastFileIndex );

                ASSERT( Found );

                //
                //  Keep walking through the directory until we run out of
                //  entries or we find an entry which ends beyond the input
                //  index value (index search case) or corresponds to the
                //  name we are looking for (name search case).
                //
    
                do {
    
                    //
                    //  If we have passed the index value then exit.
                    //

                    if (CompoundDirContext->FileIndex.QuadPart > FileIndex) {

                        Found = FALSE;
                        break;
                    }

                    //
                    //  Remember the current position in case we need to go back.
                    //

                    LastFileIndex = CompoundDirContext->FileIndex.QuadPart;

                    //
                    //  Exit if the next entry is beyond the desired index value.
                    //

                    if (LastFileIndex + ISONsrFidSize( CompoundDirContext->DirContext.Fid ) > FileIndex) {

                        break;
                    }
    
                    Found = UdfLookupNextFileIndex( IrpContext, Fcb, CompoundDirContext );
    
                } while (Found);
    
                //
                //  If we didn't find the entry then go back to the last known entry.
                //

⌨️ 快捷键说明

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