dirctrl.c

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

C
1,926
字号
        //  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) {

                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 = UdfEnumerateIndex( IrpContext, Ccb, &CompoundDirContext, 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;
                    }
                }

                try_leave( Status );
            }

            //
            //  Remember the dirent/file entry for the file we just found.
            //

            ThisFid = CompoundDirContext.DirContext.Fid;

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

            //
            //  We can look directly at the dirent that we found.
            //

            FileNameBytes = CompoundDirContext.DirContext.CaseObjectName.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;
                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) > BytesRemainingInBuffer) {

                //
                //  If we already found an entry then just exit.
                //

                if (NextEntry != 0) {

                    ReturnNextEntry = FALSE;
                    try_leave( Status = STATUS_SUCCESS );
                }

                //
                //  Reduce the FileNameBytes to just fit in the buffer.
                //

                FileNameBytes = BytesRemainingInBuffer - BaseLength;

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

                RtlZeroMemory( Add2Ptr( UserBuffer, NextEntry, PVOID ),
                               BaseLength );
    
                //
                //  Now we have an entry to return to our caller.
                //  We'll case on the type of information requested and fill up
                //  the user buffer if everything fits.
                //
    
                switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
    
                case FileBothDirectoryInformation:
                case FileFullDirectoryInformation:
                case FileDirectoryInformation:
    
                    DirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_BOTH_DIR_INFORMATION );
    
                    //
                    //  These information types require we look up the file entry.
                    //
                    
                    UdfLookupFileEntryInEnumeration( IrpContext,
                                                     Fcb,
                                                     &CompoundDirContext );
                    //
                    //  Directly reference the file entry we just looked up.
                    //
                    
                    ThisFe = (PICBFILE) CompoundDirContext.IcbContext.Active.View;
                    
                    //
                    //  Now go gather all of the timestamps for this guy.
                    //
            
                    UdfUpdateTimestampsFromIcbContext ( IrpContext,
                                                        &CompoundDirContext.IcbContext,
                                                        &CompoundDirContext.Timestamps );
                    
                    DirInfo->CreationTime = CompoundDirContext.Timestamps.CreationTime;
    
                    DirInfo->LastWriteTime =
                    DirInfo->ChangeTime = CompoundDirContext.Timestamps.ModificationTime;
    
                    DirInfo->LastAccessTime = CompoundDirContext.Timestamps.AccessTime;
    
                    //
                    //  Set the attributes and sizes separately for directories and
                    //  files.
                    //
    
                    if (ThisFe->Icbtag.FileType == ICBTAG_FILE_T_DIRECTORY) {
    
                        DirInfo->EndOfFile.QuadPart = DirInfo->AllocationSize.QuadPart = 0;
    
                        SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY );
    
                    } else {
    
                        DirInfo->EndOfFile.QuadPart = ThisFe->InfoLength;
                        DirInfo->AllocationSize.QuadPart = LlBlockAlign( Fcb->Vcb, ThisFe->InfoLength );
                    }

                    //
                    //  All Cdrom files are readonly.  We also copy the existence
                    //  bit to the hidden attribute, assuming that synthesized FIDs
                    //  are never hidden.
                    //

                    SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_READONLY );
    
                    if (ThisFid && FlagOn( ThisFid->Flags, NSR_FID_F_HIDDEN )) {
    
                        SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
                    }
    
                    //
                    //  The file index for real file indices > 2^32 is zero.  When asked to
                    //  restart at an index of zero, we will know to use a stashed starting
                    //  point to beging to search, by name, for the correct restart point.
                    //
                    
                    if (CompoundDirContext.FileIndex.HighPart == 0) {
                        
                        DirInfo->FileIndex = CompoundDirContext.FileIndex.LowPart;
                    
                    } else {
    
                        DirInfo->FileIndex = 0;
                    }
    
                    DirInfo->FileNameLength = FileNameBytes;
    
                    break;
    
                case FileNamesInformation:
    
                    NamesInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_NAMES_INFORMATION );
    
                    if (CompoundDirContext.FileIndex.HighPart == 0) {
                        
                        NamesInfo->FileIndex = CompoundDirContext.FileIndex.LowPart;
                    
                    } else {
    
                        NamesInfo->FileIndex = 0;
                    }
    
                    NamesInfo->FileNameLength = FileNameBytes;
    
                    break;
                }

                //
                //  Now copy as much of the name as possible.
                //
    
                if (FileNameBytes != 0) {
    
                    //
                    //  This is a Unicode name, we can copy the bytes directly.
                    //
    
                    RtlCopyMemory( Add2Ptr( UserBuffer, NextEntry + BaseLength, PVOID ),
                                   CompoundDirContext.DirContext.ObjectName.Buffer,
                                   FileNameBytes );
                }

                //
                //  Fill in the short name if we got STATUS_SUCCESS.  The short name
                //  may already be in the file context, otherwise we will check
                //  whether the long name is 8.3.  Special case the self and parent
                //  directory names.
                //
    
                if ((Status == STATUS_SUCCESS) &&
                    (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation) &&
                    FlagOn( CompoundDirContext.DirContext.Flags, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT )) {
    
                    //
                    //  If we already have the short name then copy into the user's buffer.
                    //
    
                    if (CompoundDirContext.DirContext.ShortObjectName.Length != 0) {
    
                        RtlCopyMemory( DirInfo->ShortName,
                                       CompoundDirContext.DirContext.ShortObjectName.Buffer,
                                       CompoundDirContext.DirContext.ShortObjectName.Length );
    
                        DirInfo->ShortNameLength = (CCHAR) CompoundDirContext.DirContext.ShortObjectName.Length;
    
                    //
                    //  If the short name length is currently zero then check if
                    //  the long name is not 8.3.  We can copy the short name in
                    //  unicode form directly into the caller's buffer.
                    //
    
                    } else {
    
                        if (!UdfIs8dot3Name( IrpContext,
                                             CompoundDirContext.DirContext.ObjectName )) {
    
                            UNICODE_STRING ShortName;
    
                            ShortName.Buffer = DirInfo->ShortName;
                            ShortName.MaximumLength = BYTE_COUNT_8_DOT_3;
                            
                            UdfGenerate8dot3Name( IrpContext,
                                                  &CompoundDirContext.DirContext.PureObjectName,
                                                  &ShortName );
    
                            DirInfo->ShortNameLength = (CCHAR) ShortName.Length;
                        }
                    }
                }

                //
                //  Update the information with the number of bytes stored in the
                //  buffer.  We quad-align the existing buffer to add any necessary
                //  pad bytes.
                //

                Information = NextEntry + BaseLength + FileNameBytes;

                //
                //  Go back to the previous entry and fill in the update to this entry.
                //

                *(Add2Ptr( UserBuffer, LastEntry, PULONG )) = NextEntry - LastEntry;

                //
                //  Set up our variables for the next dirent.
                //

                InitialQuery = FALSE;

                LastEntry = NextEntry;
                NextEntry = QuadAlign( Information );
            
            } except (!FsRtlIsNtstatusExpected(GetExceptionCode()) ?
                      EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {

                  //
                  //  We must have had a problem filling in the user's buffer, so stop
                  //  and fail this request.
                  //
                  
                  Information = 0;
                  try_leave( Status = GetExceptionCode());
            }
        }

    } finally {

        if (!AbnormalTermination() && !NT_ERROR( Status )) {
        
            //
            //  Update the Ccb to show the current state of the enumeration.
            //
    
            UdfLockFcb( IrpContext, Fcb );
    
            Ccb->CurrentFileIndex = CompoundDirContext.FileIndex.QuadPart;

            //
            //  Update our notion of a high 32bit file index.  We only do this once to avoid the hit
            //  of thrashing the Fcb mutex to do this for every entry.  If it is ever neccesary to use
            //  this information, the difference of a few dozen entries from the optimal pick-up point
            //  will be trivial.
            //
            
            if (CompoundDirContext.FileIndex.HighPart == 0 &&
                CompoundDirContext.FileIndex.LowPart > Ccb->HighestReturnableFileIndex) {

                    Ccb->HighestReturnableFileIndex = CompoundDirContext.FileIndex.LowPart;
            }
            
            ClearFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
    
            if (ReturnNextEntry) {
    
                SetFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
            }
    
            UdfUnlockFcb( IrpContext, Fcb );
        }

        //
        //  Cleanup our search context.
        //

        UdfCleanupCompoundDirContext( IrpContext, &CompoundDirContext );

        //
        //  Release the Fcb.
        //

        UdfReleaseFile( IrpContext, Fcb );
    }

    //
    //  Complete the request here.
    //

    Irp->IoStatus.Information = Information;

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


//
//  Local support routines
//

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

/*++

Routine Description:

    This routine performs the notify change directory operation.  It is
    responsible for either completing of enqueuing the input Irp.  Although there
    will never be a notify signalled on a readonly disk we still support this call.

    We have already checked that this is not an OpenById handle.

Arguments:

    Irp - Supplies the Irp to process

    IrpSp - Io stack location for this request.

    Ccb - Handle to the directory being watched.

Return Value:

    NTSTATUS - STATUS_PENDING, any other error will raise.

--*/

{
    PAGED_CODE();

    //
    //  Always set the wait bit in the IrpContext so the initial wait can't fail.
    //

    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );

    //
    //  Acquire the Vcb shared.
    //

    UdfAcquireVcbShared( IrpContext, IrpContext->Vcb, FALSE );

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

    try {

        //
        //  Verify the Vcb.
        //

        UdfVerifyVcb( IrpContext, IrpContext->Vcb );

        //
        //  Call the Fsrtl package to process the request.  We cast the
        //  unicode strings to ansi strings as the dir notify package

⌨️ 快捷键说明

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