📄 cachesup.c
字号:
Status - Returns the status of the operation.
--*/
{
LARGE_INTEGER Vbo;
ULONG InitialAllocation;
BOOLEAN UnwindWeAllocatedDiskSpace = FALSE;
ULONG ClusterSize;
PVOID LocalBuffer;
PAGED_CODE();
DebugTrace(+1, Dbg, "FatPrepareWriteDirectoryFile\n", 0);
DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb);
DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", (ULONG)StartingVbo);
DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
DebugTrace( 0, Dbg, "Zero = %08lx\n", Zero);
*Bcb = NULL;
*Buffer = NULL;
//
// If we need to create a directory file and initialize the
// cachemap, do so.
//
FatOpenDirectoryFile( IrpContext, Dcb );
//
// If the transfer is beyond the allocation size we need to
// extend the directory's allocation. The call to
// AddFileAllocation will raise a condition if
// it runs out of disk space. Note that the root directory
// cannot be extended.
//
Vbo.QuadPart = StartingVbo;
try {
if (StartingVbo + ByteCount > Dcb->Header.AllocationSize.LowPart) {
if (NodeType(Dcb) == FAT_NTC_ROOT_DCB &&
!FatIsFat32(Dcb->Vcb)) {
FatRaiseStatus( IrpContext, STATUS_DISK_FULL );
}
DebugTrace(0, Dbg, "Try extending normal directory\n", 0);
InitialAllocation = Dcb->Header.AllocationSize.LowPart;
FatAddFileAllocation( IrpContext,
Dcb,
Dcb->Specific.Dcb.DirectoryFile,
StartingVbo + ByteCount );
UnwindWeAllocatedDiskSpace = TRUE;
//
// Inform the cache manager of the new allocation
//
Dcb->Header.FileSize.LowPart =
Dcb->Header.AllocationSize.LowPart;
CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile,
(PCC_FILE_SIZES)&Dcb->Header.AllocationSize );
//
// Set up the Bitmap buffer if it is not big enough already
//
FatCheckFreeDirentBitmap( IrpContext, Dcb );
//
// The newly allocated clusters should be zeroed starting at
// the previous allocation size
//
Zero = TRUE;
Vbo.QuadPart = InitialAllocation;
ByteCount = Dcb->Header.AllocationSize.LowPart - InitialAllocation;
}
//
// Call the Cache Manager to attempt the transfer, going one cluster
// at a time to avoid pinning across a page boundary.
//
ClusterSize =
1 << Dcb->Vcb->AllocationSupport.LogOfBytesPerCluster;
while (ByteCount > 0) {
ULONG BytesToPin;
*Bcb = NULL;
if (ByteCount > ClusterSize) {
BytesToPin = ClusterSize;
} else {
BytesToPin = ByteCount;
}
ASSERT( (Vbo.QuadPart / ClusterSize) ==
(Vbo.QuadPart + BytesToPin - 1)/ClusterSize );
if (!CcPinRead( Dcb->Specific.Dcb.DirectoryFile,
&Vbo,
BytesToPin,
BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
Bcb,
&LocalBuffer )) {
//
// Could not read the data without waiting (cache miss).
//
FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
}
//
// Update our caller with the beginning of their request.
//
if (*Buffer == NULL) {
*Buffer = LocalBuffer;
}
DbgDoit( IrpContext->PinCount += 1 )
if (Zero) {
//
// We set this guy dirty right now so that we can raise CANT_WAIT when
// it needs to be done. It'd be beautiful if we could noop the read IO
// since we know we don't care about it.
//
RtlZeroMemory( LocalBuffer, BytesToPin );
CcSetDirtyPinnedData( *Bcb, NULL );
}
ByteCount -= BytesToPin;
Vbo.QuadPart += BytesToPin;
if (ByteCount > 0) {
FatUnpinBcb( IrpContext, *Bcb );
}
}
//
// This lets us get the data pinned until we complete the request
// and writes the dirty bit through to the disk.
//
FatSetDirtyBcb( IrpContext, *Bcb, Dcb->Vcb, Reversible );
*Status = STATUS_SUCCESS;
} finally {
DebugUnwind( FatPrepareWriteDirectoryFile );
if (AbnormalTermination()) {
//
// These steps are carefully arranged - FatTruncateFileAllocation can raise.
// Make sure we unpin the buffer. If FTFA raises, the effect should be benign.
//
FatUnpinBcb(IrpContext, *Bcb);
if (UnwindWeAllocatedDiskSpace == TRUE) {
//
// Inform the cache manager of the change.
//
FatTruncateFileAllocation( IrpContext, Dcb, InitialAllocation );
Dcb->Header.FileSize.LowPart =
Dcb->Header.AllocationSize.LowPart;
CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile,
(PCC_FILE_SIZES)&Dcb->Header.AllocationSize );
}
}
DebugTrace(-1, Dbg, "FatPrepareWriteDirectoryFile -> (VOID), *Bcb = %08lx\n", *Bcb);
}
return;
}
#if DBG
BOOLEAN FatDisableParentCheck = 0;
BOOLEAN
FatIsCurrentOperationSynchedForDcbTeardown (
IN PIRP_CONTEXT IrpContext,
IN PDCB Dcb
)
{
PIRP Irp = IrpContext->OriginatingIrp;
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation( Irp ) ;
PFILE_OBJECT FileObject = Stack->FileObject;
PVCB Vcb;
PFCB Fcb;
PCCB Ccb;
PFILE_OBJECT ToCheck[3];
ULONG Index = 0;
PAGED_CODE();
//
// While mounting, we're OK without having to own anything.
//
if (Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
Stack->MinorFunction == IRP_MN_MOUNT_VOLUME) {
return TRUE;
}
//
// With the Vcb held, the close path is blocked out.
//
if (ExIsResourceAcquiredSharedLite( &Dcb->Vcb->Resource ) ||
ExIsResourceAcquiredExclusiveLite( &Dcb->Vcb->Resource )) {
return TRUE;
}
//
// Accept this assertion at face value. It comes from GetDirentForFcbOrDcb,
// and is reliable.
//
if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_PARENT_BY_CHILD )) {
return TRUE;
}
//
// Determine which fileobjects are around on this operation.
//
if (Stack->MajorFunction == IRP_MJ_SET_INFORMATION &&
Stack->Parameters.SetFile.FileObject) {
ToCheck[Index++] = Stack->Parameters.SetFile.FileObject;
}
if (Stack->FileObject) {
ToCheck[Index++] = Stack->FileObject;
}
ToCheck[Index] = NULL;
//
// If the fileobjects we have are for this dcb or a child of it, we are
// also guaranteed that this dcb isn't going anywhere (even without
// the Vcb).
//
for (Index = 0; ToCheck[Index] != NULL; Index++) {
(VOID) FatDecodeFileObject( ToCheck[Index], &Vcb, &Fcb, &Ccb );
while ( Fcb ) {
if (Fcb == Dcb) {
return TRUE;
}
Fcb = Fcb->ParentDcb;
}
}
return FatDisableParentCheck;
}
#endif // DBG
VOID
FatOpenDirectoryFile (
IN PIRP_CONTEXT IrpContext,
IN PDCB Dcb
)
/*++
Routine Description:
This routine opens a new directory file if one is not already open.
Arguments:
Dcb - Pointer to the DCB for the directory
Return Value:
None.
--*/
{
PAGED_CODE();
DebugTrace(+1, Dbg, "FatOpenDirectoryFile\n", 0);
DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb);
//
// If we don't have some hold on this Dcb (there are several ways), there is nothing
// to prevent child files from closing and tearing this branch of the tree down in the
// midst of our slapping this reference onto it.
//
// I really wish we had a proper Fcb synchronization model (like CDFS/UDFS/NTFS).
//
ASSERT( FatIsCurrentOperationSynchedForDcbTeardown( IrpContext, Dcb ));
//
// If we haven't yet set the correct AllocationSize, do so.
//
if (Dcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
FatLookupFileAllocationSize( IrpContext, Dcb );
Dcb->Header.FileSize.LowPart =
Dcb->Header.AllocationSize.LowPart;
}
//
// Setup the Bitmap buffer if it is not big enough already
//
FatCheckFreeDirentBitmap( IrpContext, Dcb );
//
// Check if we need to create a directory file.
//
// We first do a spot check and then synchronize and check again.
//
if (Dcb->Specific.Dcb.DirectoryFile == NULL) {
PFILE_OBJECT DirectoryFileObject = NULL;
FatAcquireDirectoryFileMutex( Dcb->Vcb );
try {
if (Dcb->Specific.Dcb.DirectoryFile == NULL) {
PDEVICE_OBJECT RealDevice;
//
// Create the special file object for the directory file, and set
// up its pointers back to the Dcb and the section object pointer.
// Note that setting the DirectoryFile pointer in the Dcb has
// to be the last thing done.
//
// Preallocate a close context since we have no Ccb for this object.
//
RealDevice = Dcb->Vcb->CurrentDevice;
DirectoryFileObject = IoCreateStreamFileObject( NULL, RealDevice );
FatPreallocateCloseContext( Dcb->Vcb);
FatSetFileObject( DirectoryFileObject,
DirectoryFile,
Dcb,
NULL );
//
// Remember this internal open.
//
InterlockedIncrement( &(Dcb->Vcb->InternalOpenCount) );
//
// If this is the root directory, it is also a residual open.
//
if (NodeType( Dcb ) == FAT_NTC_ROOT_DCB) {
InterlockedIncrement( &(Dcb->Vcb->ResidualOpenCount) );
}
DirectoryFileObject->SectionObjectPointer = &Dcb->NonPaged->SectionObjectPointers;
DirectoryFileObject->ReadAccess = TRUE;
DirectoryFileObject->WriteAccess = TRUE;
DirectoryFileObject->DeleteAccess = TRUE;
InterlockedIncrement( &Dcb->Specific.Dcb.DirectoryFileOpenCount );
Dcb->Specific.Dcb.DirectoryFile = DirectoryFileObject;
//
// Indicate we're happy with the fileobject now.
//
DirectoryFileObject = NULL;
}
} finally {
FatReleaseDirectoryFileMutex( Dcb->Vcb );
//
// Rip the object up if we couldn't get the close context.
//
if (DirectoryFileObject) {
ObDereferenceObject( DirectoryFileObject );
}
}
}
//
// Finally check if we need to initialize the Cache Map for the
// directory file. The size of the section we are going to map
// the current allocation size for the directory. Note that the
// cache manager will provide syncronization for us.
//
if ( Dcb->Specific.Dcb.DirectoryFile->PrivateCacheMap == NULL ) {
Dcb->Header.ValidDataLength = FatMaxLarge;
Dcb->ValidDataToDisk = MAXULONG;
CcInitializeCacheMap( Dcb->Specific.Dcb.DirectoryFile,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -