📄 dirctrl.c
字号:
//
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 FileIdBothDirectoryInformation:
case FileIdFullDirectoryInformation:
case FileDirectoryInformation:
DirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_BOTH_DIR_INFORMATION );
//
// Use the create time for all the time stamps.
//
CdConvertCdTimeToNtTime( IrpContext,
FileContext.InitialDirent->Dirent.CdTime,
&DirInfo->CreationTime );
DirInfo->LastWriteTime = DirInfo->ChangeTime = DirInfo->CreationTime;
//
// Set the attributes and sizes separately for directories and
// files.
//
if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {
DirInfo->EndOfFile.QuadPart = DirInfo->AllocationSize.QuadPart = 0;
SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
} else {
DirInfo->EndOfFile.QuadPart = FileContext.FileSize;
DirInfo->AllocationSize.QuadPart = LlSectorAlign( FileContext.FileSize );
SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_READONLY);
}
if (FlagOn( ThisDirent->DirentFlags,
CD_ATTRIBUTE_HIDDEN )) {
SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
}
DirInfo->FileIndex = ThisDirent->DirentOffset;
DirInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
break;
case FileNamesInformation:
NamesInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_NAMES_INFORMATION );
NamesInfo->FileIndex = ThisDirent->DirentOffset;
NamesInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
break;
}
//
// Fill in the FileId
//
switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
case FileIdBothDirectoryInformation:
IdBothDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_BOTH_DIR_INFORMATION );
CdSetFidFromParentAndDirent( IdBothDirInfo->FileId, Fcb, ThisDirent );
break;
case FileIdFullDirectoryInformation:
IdFullDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_FULL_DIR_INFORMATION );
CdSetFidFromParentAndDirent( IdFullDirInfo->FileId, Fcb, ThisDirent );
break;
default:
break;
}
//
// Now copy as much of the name as possible. We also may have a version
// string to copy.
//
if (FileNameBytes != 0) {
//
// This is a Unicode name, we can copy the bytes directly.
//
RtlCopyMemory( Add2Ptr( UserBuffer, NextEntry + BaseLength, PVOID ),
ThisDirent->CdFileName.FileName.Buffer,
FileNameBytes );
if (SeparatorBytes != 0) {
*(Add2Ptr( UserBuffer,
NextEntry + BaseLength + FileNameBytes,
PWCHAR )) = L';';
if (VersionStringBytes != 0) {
RtlCopyMemory( Add2Ptr( UserBuffer,
NextEntry + BaseLength + FileNameBytes + sizeof( WCHAR ),
PVOID ),
ThisDirent->CdFileName.VersionString.Buffer,
VersionStringBytes );
}
}
}
//
// 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 ||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation) &&
(Ccb->SearchExpression.VersionString.Length == 0) &&
!FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) {
//
// If we already have the short name then copy into the user's buffer.
//
if (FileContext.ShortName.FileName.Length != 0) {
RtlCopyMemory( DirInfo->ShortName,
FileContext.ShortName.FileName.Buffer,
FileContext.ShortName.FileName.Length );
DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.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 (!CdIs8dot3Name( IrpContext,
ThisDirent->CdFileName.FileName )) {
CdGenerate8dot3Name( IrpContext,
&ThisDirent->CdCaseFileName.FileName,
ThisDirent->DirentOffset,
DirInfo->ShortName,
&FileContext.ShortName.FileName.Length );
DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.Length;
}
}
}
//
// Sum the total number of bytes for the information field.
//
FileNameBytes += SeparatorBytes + VersionStringBytes;
//
// 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 (EXCEPTION_EXECUTE_HANDLER) {
//
// We had a problem filling in the user's buffer, so stop and
// fail this request. This is the only reason any exception
// would have occured at this level.
//
Information = 0;
try_leave( Status = GetExceptionCode());
}
}
DoCcbUpdate = TRUE;
} finally {
//
// Cleanup our search context - *before* aquiring the FCB mutex exclusive,
// else can block on threads in cdcreateinternalstream/purge which
// hold the FCB but are waiting for all maps in this stream to be released.
//
CdCleanupFileContext( IrpContext, &FileContext );
//
// Now we can safely aqure the FCB mutex if we need to.
//
if (DoCcbUpdate && !NT_ERROR( Status )) {
//
// Update the Ccb to show the current state of the enumeration.
//
CdLockFcb( IrpContext, Fcb );
Ccb->CurrentDirentOffset = ThisDirent->DirentOffset;
ClearFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
if (ReturnNextEntry) {
SetFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
}
CdUnlockFcb( IrpContext, Fcb );
}
//
// Release the Fcb.
//
CdReleaseFile( IrpContext, Fcb );
}
//
// Complete the request here.
//
Irp->IoStatus.Information = Information;
CdCompleteRequest( IrpContext, Irp, Status );
return Status;
}
//
// Local support routines
//
NTSTATUS
CdNotifyChangeDirectory (
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 CDROM 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.
//
CdAcquireVcbShared( IrpContext, IrpContext->Vcb, FALSE );
//
// Use a try-finally to facilitate cleanup.
//
try {
//
// Verify the Vcb.
//
CdVerifyVcb( IrpContext, IrpContext->Vcb );
//
// Call the Fsrtl package to process the request. We cast the
// unicode strings to ansi strings as the dir notify package
// 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.
//
CdReleaseVcb( IrpContext, IrpContext->Vcb );
}
//
// Cleanup the IrpContext.
//
CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
return STATUS_PENDING;
}
//
// Local support routine
//
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
)
/*++
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 FileContext 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.
FileContext - FileContext to use for this enumeration.
ReturnNextEntry - Address to store whether we should return the entry at
the FileContext 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;
CD_NAME WildCardName;
CD_NAME SearchExpression;
ULONG CcbFlags;
ULONG DirentOffset;
ULONG LastDirentOffset;
BOOLEAN KnownOffset;
BOOLEAN Found;
PAGED_CODE();
//
// 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 = 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 );
RtlZeroMemory( &SearchExpression, sizeof( SearchExpression ));
//
// Otherwise build the CdName from the name in the stack location.
// This involves building both the name and version portions and
// checking for wild card characters. We also upcase the string if
// this is a case-insensitive search.
//
} else {
//
// Create a CdName to check for wild cards.
//
WildCardName.FileName = *FileName;
CdConvertNameToCdName( IrpContext, &WildCardName );
//
// The name better have at least one character.
//
if (WildCardName.FileName.Length == 0) {
CdRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER );
}
//
// Check for wildcards in the separate components.
//
if (FsRtlDoesNameContainWildCards( &WildCardName.FileName)) {
SetFlag( CcbFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD );
}
if ((WildCardName.VersionString.Length != 0) &&
(FsRtlDoesNameContainWildCards( &WildCardName.VersionString ))) {
SetFlag( CcbFlags, CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD );
//
// Check if this is a wild card only and match all version
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -