📄 dirsup.c
字号:
// Now, mark the dirents deleted, unpin the Bcb, and return to the caller.
// Assert that there isn't any allocation associated with this dirent.
//
// Note that this loop will end with Dirent pointing to the short name.
//
try {
//
// We must acquire our parent exclusive to synchronize with enumerators
// who do not hold the vcb (ex: dirctrl).
//
// This relies on our bottom up lockorder.
//
ExAcquireResourceExclusiveLite( FcbOrDcb->ParentDcb->Header.Resource, TRUE );
for ( Offset = FcbOrDcb->LfnOffsetWithinDirectory;
Offset <= FcbOrDcb->DirentOffsetWithinDirectory;
Offset += sizeof(DIRENT), Dirent += 1 ) {
//
// If we stepped onto a new page, or this is the first iteration,
// unpin the old page, and pin the new one.
//
if ((Offset == FcbOrDcb->LfnOffsetWithinDirectory) ||
((Offset & (PAGE_SIZE - 1)) == 0)) {
FatUnpinBcb( IrpContext, Bcb );
FatPrepareWriteDirectoryFile( IrpContext,
FcbOrDcb->ParentDcb,
Offset,
sizeof(DIRENT),
&Bcb,
(PVOID *)&Dirent,
FALSE,
TRUE,
&DontCare );
}
ASSERT( (Dirent->FirstClusterOfFile == 0) || !DeleteEa );
Dirent->FileName[0] = FAT_DIRENT_DELETED;
}
//
// Back Dirent off by one to point back to the short dirent.
//
Dirent -= 1;
//
// If there are extended attributes for this dirent, we will attempt
// to remove them. We ignore any errors in removing Eas.
//
if (!FatIsFat32(FcbOrDcb->Vcb) &&
DeleteEa && (Dirent->ExtendedAttributes != 0)) {
try {
FatDeleteEa( IrpContext,
FcbOrDcb->Vcb,
Dirent->ExtendedAttributes,
&FcbOrDcb->ShortName.Name.Oem );
} except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
//
// We catch all exceptions that Fat catches, but don't do
// anything with them.
//
}
}
//
// Now clear the bits in the free dirent mask.
//
DirentsToDelete = (FcbOrDcb->DirentOffsetWithinDirectory -
FcbOrDcb->LfnOffsetWithinDirectory) / sizeof(DIRENT) + 1;
ASSERT( (FcbOrDcb->ParentDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) ||
RtlAreBitsSet( &FcbOrDcb->ParentDcb->Specific.Dcb.FreeDirentBitmap,
FcbOrDcb->LfnOffsetWithinDirectory / sizeof(DIRENT),
DirentsToDelete ) );
RtlClearBits( &FcbOrDcb->ParentDcb->Specific.Dcb.FreeDirentBitmap,
FcbOrDcb->LfnOffsetWithinDirectory / sizeof(DIRENT),
DirentsToDelete );
//
// Now, if the caller specified a DeleteContext, use it.
//
if ( ARGUMENT_PRESENT( DeleteContext ) ) {
Dirent->FileSize = DeleteContext->FileSize;
Dirent->FirstClusterOfFile = (USHORT)DeleteContext->FirstClusterOfFile;
}
//
// If this newly deleted dirent is before the DeletedDirentHint, change
// the DeletedDirentHint to point here.
//
if (FcbOrDcb->DirentOffsetWithinDirectory <
FcbOrDcb->ParentDcb->Specific.Dcb.DeletedDirentHint) {
FcbOrDcb->ParentDcb->Specific.Dcb.DeletedDirentHint =
FcbOrDcb->LfnOffsetWithinDirectory;
}
} finally {
FatUnpinBcb( IrpContext, Bcb );
//
// Release our parent.
//
ExReleaseResourceLite( FcbOrDcb->ParentDcb->Header.Resource );
}
DebugTrace(-1, Dbg, "FatDeleteDirent -> (VOID)\n", 0);
return;
}
BOOLEAN
FatLfnDirentExists (
IN PIRP_CONTEXT IrpContext,
IN PDCB Dcb,
IN PUNICODE_STRING Lfn,
IN PUNICODE_STRING LfnTmp
)
/*++
Routine Description:
This routine looks for a given Lfn in a directory
Arguments:
Dcb - The directory to search
Lfn - The Lfn to look for
Lfn - Temporary buffer to use to search for Lfn with (if < MAX_LFN then this
function may cause it to be allocated from pool if not large enough.
Retrn Value:
BOOLEAN TRUE if it exists, FALSE if not
--*/
{
CCB Ccb;
PDIRENT Dirent;
PBCB DirentBcb = NULL;
VBO DirentByteOffset;
BOOLEAN Result = FALSE;
PAGED_CODE();
//
// Pay performance penalty by forcing the compares to be case insensitive as
// opposed to grabbing more pool for a monocased copy of the Lfn. This is slight.
//
Ccb.UnicodeQueryTemplate = *Lfn;
Ccb.ContainsWildCards = FALSE;
Ccb.Flags = CCB_FLAG_SKIP_SHORT_NAME_COMPARE | CCB_FLAG_QUERY_TEMPLATE_MIXED;
try {
FatLocateDirent( IrpContext,
Dcb,
&Ccb,
0,
&Dirent,
&DirentBcb,
&DirentByteOffset,
NULL,
LfnTmp);
} finally {
if (DirentBcb) {
Result = TRUE;
}
FatUnpinBcb(IrpContext, DirentBcb);
}
return Result;
}
VOID
FatLocateDirent (
IN PIRP_CONTEXT IrpContext,
IN PDCB ParentDirectory,
IN PCCB Ccb,
IN VBO OffsetToStartSearchFrom,
OUT PDIRENT *Dirent,
OUT PBCB *Bcb,
OUT PVBO ByteOffset,
OUT PBOOLEAN FileNameDos OPTIONAL,
IN OUT PUNICODE_STRING LongFileName OPTIONAL
)
/*++
Routine Description:
This routine locates on the disk an undeleted dirent matching a given name.
Arguments:
ParentDirectory - Supplies the DCB for the directory to search
Ccb - Contains a context control block with all matching information.
OffsetToStartSearchFrom - Supplies the VBO within the parent directory
from which to start looking for another real dirent.
Dirent - Receives a pointer to the located dirent if one was found
or NULL otherwise.
Bcb - Receives the Bcb for the located dirent if one was found or
NULL otherwise.
ByteOffset - Receives the VBO within the Parent directory for
the located dirent if one was found, or 0 otherwise.
FileNameDos - Receives TRUE if the element of the dirent we hit on
was the short (non LFN) side
LongFileName - If specified, this parameter returns the long file name
associated with the returned dirent. Note that it is the caller's
responsibility to provide the buffer (and set MaximumLength
accordingly) for this unicode string. The Length field is reset
to 0 by this routine on invocation. If the supplied buffer is not
large enough, a new one will be allocated from pool.
Return Value:
None.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
OEM_STRING Name;
UCHAR NameBuffer[12];
UNICODE_STRING UpcasedLfn;
WCHAR LocalLfnBuffer[32];
BOOLEAN LfnInProgress = FALSE;
UCHAR LfnChecksum;
ULONG LfnSize;
ULONG LfnIndex;
UCHAR Ordinal;
VBO LfnByteOffset;
TimerStart(Dbg);
PAGED_CODE();
DebugTrace(+1, Dbg, "FatLocateDirent\n", 0);
DebugTrace( 0, Dbg, " ParentDirectory = %08lx\n", ParentDirectory);
DebugTrace( 0, Dbg, " OffsetToStartSearchFrom = %08lx\n", OffsetToStartSearchFrom);
DebugTrace( 0, Dbg, " Dirent = %08lx\n", Dirent);
DebugTrace( 0, Dbg, " Bcb = %08lx\n", Bcb);
DebugTrace( 0, Dbg, " ByteOffset = %08lx\n", ByteOffset);
//
// We must have acquired the parent or the vcb to synchronize with deletion. This
// is important since we can't survive racing a thread marking a series of lfn
// dirents deleted - we'd get a bogus ordinal, and otherwise get really messed up.
//
// This routine cannot do the acquire since it would be out-of-order with respect
// to the Bcb resources on iterative calls. Our order has Bcbs as the inferior resource.
//
// Deletion always grabs the parent (safely - this used to not be possible until the
// multiple fcb lockorder was fixed to be bottom up!). Deletion always occurs with
// the vcb held exclusive as well, and this will cover the cases where we can't easily
// hold the parent here, see above.
//
ASSERT( ExIsResourceAcquiredSharedLite( ParentDirectory->Header.Resource ) ||
ExIsResourceAcquiredExclusiveLite( ParentDirectory->Header.Resource ) ||
ExIsResourceAcquiredSharedLite( &ParentDirectory->Vcb->Resource ) ||
ExIsResourceAcquiredExclusiveLite( &ParentDirectory->Vcb->Resource ));
//
// The algorithm here is pretty simple. We just walk through the
// parent directory until we:
//
// A) Find a matching entry.
// B) Can't Wait
// C) Hit the End of Directory
// D) Hit Eof
//
// In the first case we found it, in the latter three cases we did not.
//
//
// Set up the strings that receives file names from our search
//
Name.MaximumLength = 12;
Name.Buffer = NameBuffer;
UpcasedLfn.Length = 0;
UpcasedLfn.MaximumLength = sizeof( LocalLfnBuffer);
UpcasedLfn.Buffer = LocalLfnBuffer;
//
// If we were given a non-NULL Bcb, compute the new Dirent address
// from the prior one, or unpin the Bcb if the new Dirent is not pinned.
//
if (*Bcb != NULL) {
if ((OffsetToStartSearchFrom / PAGE_SIZE) == (*ByteOffset / PAGE_SIZE)) {
*Dirent += (OffsetToStartSearchFrom - *ByteOffset) / sizeof(DIRENT);
} else {
FatUnpinBcb( IrpContext, *Bcb );
}
}
//
// Init the Lfn if we were given one.
//
if (ARGUMENT_PRESENT(LongFileName)) {
LongFileName->Length = 0;
}
//
// Init the FileNameDos flag
//
if (FileNameDos) {
*FileNameDos = FALSE;
}
//
// Round up OffsetToStartSearchFrom to the nearest Dirent, and store
// in ByteOffset. Note that this wipes out the prior value.
//
*ByteOffset = (OffsetToStartSearchFrom + (sizeof(DIRENT) - 1))
& ~(sizeof(DIRENT) - 1);
try {
while ( TRUE ) {
BOOLEAN FoundValidLfn;
//
// Try to read in the dirent
//
FatReadDirent( IrpContext,
ParentDirectory,
*ByteOffset,
Bcb,
Dirent,
&Status );
//
// If End Directory dirent or EOF, set all out parameters to
// indicate entry not found and, like, bail.
//
// Note that the order of evaluation here is important since we
// cannot check the first character of the dirent until after we
// know we are not beyond EOF
//
if ((Status == STATUS_END_OF_FILE) ||
((*Dirent)->FileName[0] == FAT_DIRENT_NEVER_USED)) {
DebugTrace( 0, Dbg, "End of directory: entry not found.\n", 0);
//
// If there is a Bcb, unpin it and set it to null
//
FatUnpinBcb( IrpContext, *Bcb );
*Dirent = NULL;
*ByteOffset = 0;
break;
}
//
// If the entry is marked deleted, skip. If there was an Lfn in
// progress we throw it out at this point.
//
if ((*Dirent)->FileName[0] == FAT_DIRENT_DELETED) {
LfnInProgress = FALSE;
goto GetNextDirent;
}
//
// If we have wandered onto an LFN entry, try to interpret it.
//
if (FatData.ChicagoMode &&
ARGUMENT_PRESENT(LongFileName) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -