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