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 + -
显示快捷键?