📄 dirsup.c
字号:
//
if (!FlagOn( DirContext->Flags, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT )) {
continue;
}
DebugTrace(( 0, Dbg,
"\"%wZ\" (pure \"%wZ\") @ +%08x\n",
&DirContext->ObjectName,
&DirContext->PureObjectName,
DirContext->ViewOffset ));
//
// If we are searching for generated shortnames, a small subset of the names
// in the directory are actually candidates for a match. Go get the name.
//
if (ShortName) {
//
// Now, only if this Fid's name is non 8.3 is it neccesary to work with it.
//
if (!UdfIs8dot3Name( IrpContext, DirContext->ObjectName )) {
//
// Allocate the shortname if it isn't already done.
//
if (DirContext->ShortObjectName.Buffer == NULL) {
DirContext->ShortObjectName.Buffer = FsRtlAllocatePoolWithTag( UdfPagedPool,
BYTE_COUNT_8_DOT_3,
TAG_SHORT_FILE_NAME );
DirContext->ShortObjectName.MaximumLength = BYTE_COUNT_8_DOT_3;
}
UdfGenerate8dot3Name( IrpContext,
&DirContext->PureObjectName,
&DirContext->ShortObjectName );
DebugTrace(( 0, Dbg,
"built shortname \"%wZ\"\n", &DirContext->ShortObjectName ));
} else {
//
// As an 8.3 name already, this name will not have caused us to have to generate
// a short name, so it can't be the case that the caller is looking for it.
//
continue;
}
}
if (UdfFullCompareNames( IrpContext,
MatchName,
Name ) == EqualTo) {
//
// Got a match, so give it up.
//
DebugTrace(( 0, Dbg, "HIT\n" ));
DebugTrace(( -1, Dbg, "UdfFindDirEntry -> TRUE\n" ));
return TRUE;
}
} while ( UdfLookupNextDirEntry( IrpContext,
Fcb,
DirContext ));
//
// No match was found.
//
DebugTrace(( -1, Dbg, "UdfFindDirEntry -> FALSE\n" ));
return FALSE;
}
//
// Local support routine
//
BOOLEAN
UdfLookupDirEntryPostProcessing (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb,
IN PDIR_ENUM_CONTEXT DirContext,
IN BOOLEAN ReturnError
)
/*++
Routine Description:
This routine is the core engine of directory stream enumeration. It receives
a context which has been advanced and does the integrity checks and final
extraction of the Fid with respect to file cache granularity restrictions.
NOTE: we assume that a Fid cannot span a cache view. The maximum size of a
Fid is just over 32k, so this is a good and likely permanent assumption.
Arguments:
Fcb - the directory being enumerated.
DirContext - a corresponding context for the enumeration.
ReturnError - whether errors should be returned (or raised)
Return Value:
BOOLEAN according to the successful extraction of the Fid. If ReturnError is
FALSE, then failure will result in a raised status.
--*/
{
BOOLEAN Result = TRUE;
PNSR_FID FidBufferC = NULL;
PNSR_FID FidBuffer = NULL;
PNSR_FID FidC;
PNSR_FID Fid;
ULONG FidBytesInPreviousView = 0;
PAGED_CODE();
//
// Check inputs.
//
ASSERT_IRP_CONTEXT( IrpContext );
ASSERT_FCB_INDEX( Fcb );
try {
//
// First check that the stream can contain another FID.
//
if (DirContext->BaseOffset.QuadPart +
DirContext->ViewOffset +
ISONsrFidConstantSize > Fcb->FileSize.QuadPart) {
DebugTrace(( 0, Dbg,
"UdfLookupDirEntryPostProcessing: DC %p, constant header overlaps end of dir\n",
DirContext ));
try_leave( Result = FALSE );
}
//
// We now build up the constant portion of the FID for use. It may be the case that
// this spans a view boundary and must be buffered, or is entirely in the next view
// and we simply need to advance.
//
if (GenericTruncatePtr( Add2Ptr( DirContext->Fid, ISONsrFidConstantSize - 1, PUCHAR ), VACB_MAPPING_GRANULARITY ) !=
DirContext->View) {
FidBytesInPreviousView = GenericRemainderPtr( DirContext->Fid, VACB_MAPPING_GRANULARITY );
//
// Only buffer if there are really bytes in the previous view.
//
if (FidBytesInPreviousView) {
FidC =
FidBufferC = FsRtlAllocatePoolWithTag( UdfPagedPool,
ISONsrFidConstantSize,
TAG_FID_BUFFER );
RtlCopyMemory( FidBufferC,
DirContext->Fid,
FidBytesInPreviousView );
}
//
// Now advance into the next view to pick up the rest.
//
DirContext->BaseOffset.QuadPart += VACB_MAPPING_GRANULARITY;
DirContext->ViewOffset = 0;
//
// Contain the view length by the size of the stream and map.
//
DirContext->ViewLength = VACB_MAPPING_GRANULARITY;
if (DirContext->BaseOffset.QuadPart + DirContext->ViewLength > Fcb->FileSize.QuadPart) {
DirContext->ViewLength = (ULONG) (Fcb->FileSize.QuadPart - DirContext->BaseOffset.QuadPart);
}
UdfUnpinData( IrpContext, &DirContext->Bcb );
CcMapData( Fcb->FileObject,
&DirContext->BaseOffset,
DirContext->ViewLength,
TRUE,
&DirContext->Bcb,
&DirContext->View );
//
// We are guaranteed that this much lies in the stream. Build the rest of the
// constant header.
//
if (FidBytesInPreviousView) {
RtlCopyMemory( Add2Ptr( FidBufferC, FidBytesInPreviousView, PUCHAR ),
DirContext->View,
ISONsrFidConstantSize - FidBytesInPreviousView );
//
// In fact, this FID is perfectly aligned to the front of this view. No buffering
// is required, and we just set the FID pointer.
//
} else {
DirContext->Fid = DirContext->View;
}
}
//
// If no buffering was required, we can use the cache directly.
//
if (!FidBytesInPreviousView) {
FidC = DirContext->Fid;
}
//
// Now we can check that the Fid data lies within the stream bounds and is sized
// within a logical block (per UDF). This will complete the size-wise integrity
// verification.
//
if (((DirContext->BaseOffset.QuadPart +
DirContext->ViewOffset -
FidBytesInPreviousView +
ISONsrFidSize( FidC ) > Fcb->FileSize.QuadPart) &&
DebugTrace(( 0, Dbg,
"UdfLookupDirEntryPostProcessing: DC %p, FID (FidC %p, FBIPV %u) overlaps end of dir\n",
DirContext,
FidC,
FidBytesInPreviousView )))
||
(ISONsrFidSize( FidC ) > BlockSize( Fcb->Vcb ) &&
DebugTrace(( 0, Dbg,
"UdfLookupDirEntryPostProcessing: DC %p, FID (FidC %p) larger than a logical block\n",
DirContext,
FidC )))) {
try_leave( Result = FALSE );
}
//
// Final Fid rollup.
//
//
// The Fid may span a view boundary and should be buffered. If we already buffered, we know
// we have to do this.
//
if (FidBytesInPreviousView ||
GenericTruncatePtr( Add2Ptr( DirContext->Fid, ISONsrFidSize( FidC ) - 1, PUCHAR ), VACB_MAPPING_GRANULARITY ) !=
DirContext->View) {
Fid =
FidBuffer = FsRtlAllocatePoolWithTag( UdfPagedPool,
ISONsrFidSize( FidC ),
TAG_FID_BUFFER );
//
// If we already buffered and advanced for the header, just prefill
// the final Fid buffer with the bytes that are now unavaliable.
//
if (FidBytesInPreviousView) {
RtlCopyMemory( FidBuffer,
FidBufferC,
FidBytesInPreviousView );
} else {
//
// Buffer and advance the view.
//
FidBytesInPreviousView = GenericRemainderPtr( DirContext->Fid, VACB_MAPPING_GRANULARITY );
RtlCopyMemory( FidBuffer,
DirContext->Fid,
FidBytesInPreviousView );
//
// Now advance into the next view to pick up the rest.
//
DirContext->BaseOffset.QuadPart += VACB_MAPPING_GRANULARITY;
DirContext->ViewOffset = 0;
//
// Contain the view length by the size of the stream and map.
//
DirContext->ViewLength = VACB_MAPPING_GRANULARITY;
if (DirContext->BaseOffset.QuadPart + DirContext->ViewLength > Fcb->FileSize.QuadPart) {
DirContext->ViewLength = (ULONG) (Fcb->FileSize.QuadPart - DirContext->BaseOffset.QuadPart);
}
UdfUnpinData( IrpContext, &DirContext->Bcb );
CcMapData( Fcb->FileObject,
&DirContext->BaseOffset,
DirContext->ViewLength,
TRUE,
&DirContext->Bcb,
&DirContext->View );
}
//
// We are guaranteed that this much lies in the stream.
//
RtlCopyMemory( Add2Ptr( FidBuffer, FidBytesInPreviousView, PUCHAR ),
DirContext->View,
ISONsrFidSize( FidC ) - FidBytesInPreviousView );
} else {
Fid = DirContext->Fid;
}
//
// We finally have the whole Fid safely extracted from the cache, so the
// integrity check is now the last step before success. For simplicity's
// sake we trust the Lbn field.
//
Result = UdfVerifyDescriptor( IrpContext,
&Fid->Destag,
DESTAG_ID_NSR_FID,
ISONsrFidSize( Fid ),
Fid->Destag.Lbn,
ReturnError );
//
// Prepare to return a buffered Fid.
//
if (FidBuffer && Result) {
SetFlag( DirContext->Flags, DIR_CONTEXT_FLAG_FID_BUFFERED );
DirContext->Fid = FidBuffer;
FidBuffer = NULL;
}
} finally {
UdfFreePool( &FidBuffer );
UdfFreePool( &FidBufferC );
}
if (!ReturnError && !Result) {
UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
}
//
// On success update the next Fid information in the context.
// Note that we must drop in a hint as to where the next Fid
// will be found so that the next advance will know how much
// of a buffered Fid isn't in this view.
//
if (Result) {
DirContext->NextFidOffset = DirContext->ViewOffset +
ISONsrFidSize( Fid );
if (FidBytesInPreviousView) {
DirContext->NextFidOffset -= FidBytesInPreviousView;
}
}
return Result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -