mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-02 04:13:34 +00:00
- Add new CDFS driver.
- Does not compile. svn path=/trunk/; revision=34615
This commit is contained in:
+903
@@ -0,0 +1,903 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1990-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
AllocSup.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the Allocation support routines for Cdfs.
|
||||
|
||||
The data structure used here is the CD_MCB. There is an entry in
|
||||
the Mcb for each dirent for a file. The entry will map the offset
|
||||
within some file to a starting disk offset and number of bytes.
|
||||
The Mcb also contains the interleave information for an extent.
|
||||
An interleave consists of a number of blocks with data and a
|
||||
(possibly different) number of blocks to skip. Any number of
|
||||
data/skip pairs may exist in an extent but the data and skip sizes
|
||||
are the same throughout the extent.
|
||||
|
||||
We store the following information into an Mcb entry for an extent.
|
||||
|
||||
FileOffset Offset in file for start of extent
|
||||
DiskOffset Offset on disk for start of extent
|
||||
ByteCount Number of file bytes in extent, no skip bytes
|
||||
DataBlockByteCount Number of bytes in each data block
|
||||
TotalBlockByteCount Number of bytes is data block and skip block
|
||||
|
||||
The disk offset in the Mcb has already been biased by the size of
|
||||
the Xar block if present. All of the byte count fields are aligned
|
||||
on logical block boundaries. If this is a directory or path table
|
||||
then the file offset has been biased to round the initial disk
|
||||
offset down to a sector boundary. The biasing is done when loading
|
||||
the values into an Mcb entry.
|
||||
|
||||
An XA file has a header prepended to the file and each sector is 2352
|
||||
bytes. The allocation information ignores the header and only deals
|
||||
with 2048 byte sectors. Callers into the allocation package have
|
||||
adjusted the starting offset value to reflect 2048 sectors. On return
|
||||
from this package the caller will have to convert from 2048 sector values
|
||||
into raw XA sector values.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_ALLOCSUP)
|
||||
|
||||
//
|
||||
// Local support routines
|
||||
//
|
||||
|
||||
ULONG
|
||||
CdFindMcbEntry (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN LONGLONG FileOffset
|
||||
);
|
||||
|
||||
VOID
|
||||
CdDiskOffsetFromMcbEntry (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PCD_MCB_ENTRY McbEntry,
|
||||
IN LONGLONG FileOffset,
|
||||
IN PLONGLONG DiskOffset,
|
||||
IN PULONG ByteCount
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdAddInitialAllocation)
|
||||
#pragma alloc_text(PAGE, CdAddAllocationFromDirent)
|
||||
#pragma alloc_text(PAGE, CdDiskOffsetFromMcbEntry)
|
||||
#pragma alloc_text(PAGE, CdFindMcbEntry)
|
||||
#pragma alloc_text(PAGE, CdInitializeMcb)
|
||||
#pragma alloc_text(PAGE, CdLookupAllocation)
|
||||
#pragma alloc_text(PAGE, CdTruncateAllocation)
|
||||
#pragma alloc_text(PAGE, CdUninitializeMcb)
|
||||
#endif
|
||||
|
||||
|
||||
VOID
|
||||
CdLookupAllocation (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN LONGLONG FileOffset,
|
||||
OUT PLONGLONG DiskOffset,
|
||||
OUT PULONG ByteCount
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine looks through the mapping information for the file
|
||||
to find the logical diskoffset and number of bytes at that offset.
|
||||
We only deal with logical 2048 byte sectors here.
|
||||
|
||||
If the mapping isn't present we will look it up on disk now.
|
||||
This routine assumes we are looking up a valid range in the file. This
|
||||
routine raises if it can't find mapping for the file offset.
|
||||
|
||||
The Fcb may not be locked prior to calling this routine. We will always
|
||||
acquire it here.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - Fcb representing this stream.
|
||||
|
||||
FileOffset - Lookup the allocation beginning at this point.
|
||||
|
||||
DiskOffset - Address to store the logical disk offset.
|
||||
|
||||
ByteCount - Address to store the number of contiguous bytes beginning
|
||||
at DiskOffset above.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
BOOLEAN FirstPass = TRUE;
|
||||
ULONG McbEntryOffset;
|
||||
PFCB ParentFcb;
|
||||
BOOLEAN CleanupParent = FALSE;
|
||||
|
||||
BOOLEAN UnlockFcb = FALSE;
|
||||
|
||||
LONGLONG CurrentFileOffset;
|
||||
ULONG CurrentMcbOffset;
|
||||
PCD_MCB_ENTRY CurrentMcbEntry;
|
||||
|
||||
DIRENT_ENUM_CONTEXT DirContext;
|
||||
DIRENT Dirent;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_FCB( Fcb );
|
||||
|
||||
//
|
||||
// Use a try finally to facilitate cleanup.
|
||||
//
|
||||
|
||||
try {
|
||||
|
||||
//
|
||||
// We use a loop to perform the lookup. If we don't find the mapping in the
|
||||
// first pass then we look up all of the allocation and then look again.
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
//
|
||||
//
|
||||
// Lookup the entry containing this file offset.
|
||||
//
|
||||
|
||||
CdLockFcb( IrpContext, Fcb );
|
||||
UnlockFcb = TRUE;
|
||||
|
||||
McbEntryOffset = CdFindMcbEntry( IrpContext, Fcb, FileOffset );
|
||||
|
||||
//
|
||||
// If within the Mcb then we use the data out of this entry and are
|
||||
// done.
|
||||
//
|
||||
|
||||
if (McbEntryOffset < Fcb->Mcb.CurrentEntryCount) {
|
||||
|
||||
CdDiskOffsetFromMcbEntry( IrpContext,
|
||||
Fcb->Mcb.McbArray + McbEntryOffset,
|
||||
FileOffset,
|
||||
DiskOffset,
|
||||
ByteCount );
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// If this is not the first pass then the disk is corrupt.
|
||||
//
|
||||
|
||||
} else if (!FirstPass) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
|
||||
}
|
||||
|
||||
CdUnlockFcb( IrpContext, Fcb );
|
||||
UnlockFcb = FALSE;
|
||||
|
||||
//
|
||||
// Initialize the search dirent structures.
|
||||
//
|
||||
|
||||
CdInitializeDirContext( IrpContext, &DirContext );
|
||||
CdInitializeDirent( IrpContext, &Dirent );
|
||||
|
||||
//
|
||||
// Otherwise we need to walk the dirents for this file until we find
|
||||
// the one containing this entry. The parent Fcb should always be
|
||||
// present.
|
||||
//
|
||||
|
||||
ParentFcb = Fcb->ParentFcb;
|
||||
CdAcquireFileShared( IrpContext, ParentFcb );
|
||||
CleanupParent = TRUE;
|
||||
|
||||
//
|
||||
// Do an unsafe test to see if we need to create a file object.
|
||||
//
|
||||
|
||||
if (ParentFcb->FileObject == NULL) {
|
||||
|
||||
CdCreateInternalStream( IrpContext, ParentFcb->Vcb, ParentFcb );
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the local variables to indicate the first dirent
|
||||
// and lookup the first dirent.
|
||||
//
|
||||
|
||||
CurrentFileOffset = 0;
|
||||
CurrentMcbOffset = 0;
|
||||
|
||||
CdLookupDirent( IrpContext,
|
||||
ParentFcb,
|
||||
CdQueryFidDirentOffset( Fcb->FileId ),
|
||||
&DirContext );
|
||||
|
||||
//
|
||||
// If we are adding allocation to the Mcb then add all of it.
|
||||
//
|
||||
|
||||
while (TRUE ) {
|
||||
|
||||
//
|
||||
// Update the dirent from the on-disk dirent.
|
||||
//
|
||||
|
||||
CdUpdateDirentFromRawDirent( IrpContext, ParentFcb, &DirContext, &Dirent );
|
||||
|
||||
//
|
||||
// Add this dirent to the Mcb if not already present.
|
||||
//
|
||||
|
||||
CdLockFcb( IrpContext, Fcb );
|
||||
UnlockFcb = TRUE;
|
||||
|
||||
if (CurrentMcbOffset >= Fcb->Mcb.CurrentEntryCount) {
|
||||
|
||||
CdAddAllocationFromDirent( IrpContext, Fcb, CurrentMcbOffset, CurrentFileOffset, &Dirent );
|
||||
}
|
||||
|
||||
CdUnlockFcb( IrpContext, Fcb );
|
||||
UnlockFcb = FALSE;
|
||||
|
||||
//
|
||||
// If this is the last dirent for the file then exit.
|
||||
//
|
||||
|
||||
if (!FlagOn( Dirent.DirentFlags, CD_ATTRIBUTE_MULTI )) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// If we couldn't find another entry then the directory is corrupt because
|
||||
// the last dirent for a file doesn't exist.
|
||||
//
|
||||
|
||||
if (!CdLookupNextDirent( IrpContext, ParentFcb, &DirContext, &DirContext )) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
|
||||
}
|
||||
|
||||
//
|
||||
// Update our loop variables.
|
||||
//
|
||||
|
||||
CurrentMcbEntry = Fcb->Mcb.McbArray + CurrentMcbOffset;
|
||||
CurrentFileOffset += CurrentMcbEntry->ByteCount;
|
||||
CurrentMcbOffset += 1;
|
||||
}
|
||||
|
||||
//
|
||||
// All of the allocation is loaded. Go back and look up the mapping again.
|
||||
// It better be there this time.
|
||||
//
|
||||
|
||||
FirstPass = FALSE;
|
||||
}
|
||||
|
||||
} finally {
|
||||
|
||||
if (CleanupParent) {
|
||||
|
||||
//
|
||||
// Release the parent and cleanup the dirent structures.
|
||||
//
|
||||
|
||||
CdReleaseFile( IrpContext, ParentFcb );
|
||||
|
||||
CdCleanupDirContext( IrpContext, &DirContext );
|
||||
CdCleanupDirent( IrpContext, &Dirent );
|
||||
}
|
||||
|
||||
if (UnlockFcb) { CdUnlockFcb( IrpContext, Fcb ); }
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdAddAllocationFromDirent (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN ULONG McbEntryOffset,
|
||||
IN LONGLONG StartingFileOffset,
|
||||
IN PDIRENT Dirent
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to add an entry into the Cd Mcb. We grow the Mcb
|
||||
as necessary and update the new entry.
|
||||
|
||||
NOTE - The Fcb has already been locked prior to makeing this call.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - Fcb containing the Mcb to update.
|
||||
|
||||
McbEntryOffset - Offset into the Mcb array to add this data.
|
||||
|
||||
StartingFileOffset - Offset in bytes from the start of the file.
|
||||
|
||||
Dirent - Dirent containing the on-disk data for this entry.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ULONG NewArraySize;
|
||||
PVOID NewMcbArray;
|
||||
PCD_MCB_ENTRY McbEntry;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_FCB( Fcb );
|
||||
ASSERT_LOCKED_FCB( Fcb );
|
||||
|
||||
//
|
||||
// If we need to grow the Mcb then do it now.
|
||||
//
|
||||
|
||||
if (McbEntryOffset >= Fcb->Mcb.MaximumEntryCount) {
|
||||
|
||||
//
|
||||
// Allocate a new buffer and copy the old data over.
|
||||
//
|
||||
|
||||
NewArraySize = Fcb->Mcb.MaximumEntryCount * 2 * sizeof( CD_MCB_ENTRY );
|
||||
|
||||
NewMcbArray = FsRtlAllocatePoolWithTag( CdPagedPool,
|
||||
NewArraySize,
|
||||
TAG_MCB_ARRAY );
|
||||
|
||||
RtlZeroMemory( NewMcbArray, NewArraySize );
|
||||
RtlCopyMemory( NewMcbArray,
|
||||
Fcb->Mcb.McbArray,
|
||||
Fcb->Mcb.MaximumEntryCount * sizeof( CD_MCB_ENTRY ));
|
||||
|
||||
//
|
||||
// Deallocate the current array unless it is embedded in the Fcb.
|
||||
//
|
||||
|
||||
if (Fcb->Mcb.MaximumEntryCount != 1) {
|
||||
|
||||
CdFreePool( &Fcb->Mcb.McbArray );
|
||||
}
|
||||
|
||||
//
|
||||
// Now update the Mcb with the new array.
|
||||
//
|
||||
|
||||
Fcb->Mcb.MaximumEntryCount *= 2;
|
||||
Fcb->Mcb.McbArray = NewMcbArray;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the new entry with the input data.
|
||||
//
|
||||
|
||||
McbEntry = Fcb->Mcb.McbArray + McbEntryOffset;
|
||||
|
||||
//
|
||||
// Start with the location and length on disk.
|
||||
//
|
||||
|
||||
McbEntry->DiskOffset = LlBytesFromBlocks( Fcb->Vcb, Dirent->StartingOffset );
|
||||
McbEntry->ByteCount = Dirent->DataLength;
|
||||
|
||||
//
|
||||
// Round the byte count up to a logical block boundary if this is
|
||||
// the last extent.
|
||||
//
|
||||
|
||||
if (!FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_MULTI )) {
|
||||
|
||||
McbEntry->ByteCount = BlockAlign( Fcb->Vcb, McbEntry->ByteCount );
|
||||
}
|
||||
|
||||
//
|
||||
// The file offset is the logical position within this file.
|
||||
// We know this is correct regardless of whether we bias the
|
||||
// file size or disk offset.
|
||||
//
|
||||
|
||||
McbEntry->FileOffset = StartingFileOffset;
|
||||
|
||||
//
|
||||
// Convert the interleave information from logical blocks to
|
||||
// bytes.
|
||||
//
|
||||
|
||||
if (Dirent->FileUnitSize != 0) {
|
||||
|
||||
McbEntry->DataBlockByteCount = LlBytesFromBlocks( Fcb->Vcb, Dirent->FileUnitSize );
|
||||
McbEntry->TotalBlockByteCount = McbEntry->DataBlockByteCount +
|
||||
LlBytesFromBlocks( Fcb->Vcb, Dirent->InterleaveGapSize );
|
||||
|
||||
//
|
||||
// If the file is not interleaved then the size of the data block
|
||||
// and total block are the same as the byte count.
|
||||
//
|
||||
|
||||
} else {
|
||||
|
||||
McbEntry->DataBlockByteCount =
|
||||
McbEntry->TotalBlockByteCount = McbEntry->ByteCount;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the number of entries in the Mcb. The Mcb is never sparse
|
||||
// so whenever we add an entry it becomes the last entry in the Mcb.
|
||||
//
|
||||
|
||||
Fcb->Mcb.CurrentEntryCount = McbEntryOffset + 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdAddInitialAllocation (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN ULONG StartingBlock,
|
||||
IN LONGLONG DataLength
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to set up the initial entry in an Mcb.
|
||||
|
||||
This routine handles the single initial entry for a directory file. We will
|
||||
round the start block down to a sector boundary. Our caller has already
|
||||
biased the DataLength with any adjustments. This is used for the case
|
||||
where there is a single entry and we want to align the data on a sector
|
||||
boundary.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - Fcb containing the Mcb to update.
|
||||
|
||||
StartingBlock - Starting logical block for this directory. This is
|
||||
the start of the actual data. We will bias this by the sector
|
||||
offset of the data.
|
||||
|
||||
DataLength - Length of the data.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PCD_MCB_ENTRY McbEntry;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_FCB( Fcb );
|
||||
ASSERT_LOCKED_FCB( Fcb );
|
||||
ASSERT( 0 == Fcb->Mcb.CurrentEntryCount);
|
||||
ASSERT( CDFS_NTC_FCB_DATA != Fcb->NodeTypeCode);
|
||||
|
||||
//
|
||||
// Update the new entry with the input data.
|
||||
//
|
||||
|
||||
McbEntry = Fcb->Mcb.McbArray;
|
||||
|
||||
//
|
||||
// Start with the location and length on disk.
|
||||
//
|
||||
|
||||
McbEntry->DiskOffset = LlBytesFromBlocks( Fcb->Vcb, StartingBlock );
|
||||
McbEntry->DiskOffset -= Fcb->StreamOffset;
|
||||
|
||||
McbEntry->ByteCount = DataLength;
|
||||
|
||||
//
|
||||
// The file offset is the logical position within this file.
|
||||
// We know this is correct regardless of whether we bias the
|
||||
// file size or disk offset.
|
||||
//
|
||||
|
||||
McbEntry->FileOffset = 0;
|
||||
|
||||
//
|
||||
// If the file is not interleaved then the size of the data block
|
||||
// and total block are the same as the byte count.
|
||||
//
|
||||
|
||||
McbEntry->DataBlockByteCount =
|
||||
McbEntry->TotalBlockByteCount = McbEntry->ByteCount;
|
||||
|
||||
//
|
||||
// Update the number of entries in the Mcb. The Mcb is never sparse
|
||||
// so whenever we add an entry it becomes the last entry in the Mcb.
|
||||
//
|
||||
|
||||
Fcb->Mcb.CurrentEntryCount = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdTruncateAllocation (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN LONGLONG StartingFileOffset
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine truncates the Mcb for a file by eliminating all of the Mcb
|
||||
entries from the entry which contains the given offset.
|
||||
|
||||
The Fcb should be locked when this routine is called.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - Fcb containing the Mcb to truncate.
|
||||
|
||||
StartingFileOffset - Offset in the file to truncate the Mcb from.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ULONG McbEntryOffset;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_FCB( Fcb );
|
||||
ASSERT_LOCKED_FCB( Fcb );
|
||||
|
||||
//
|
||||
// Find the entry containg this starting offset.
|
||||
//
|
||||
|
||||
McbEntryOffset = CdFindMcbEntry( IrpContext, Fcb, StartingFileOffset );
|
||||
|
||||
//
|
||||
// Now set the current size of the mcb to this point.
|
||||
//
|
||||
|
||||
Fcb->Mcb.CurrentEntryCount = McbEntryOffset;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdInitializeMcb (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to initialize the Mcb in an Fcb. We initialize
|
||||
this with an entry count of one and point to the entry in the Fcb
|
||||
itself.
|
||||
|
||||
Fcb should be acquired exclusively when this is called.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - Fcb containing the Mcb to initialize.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_FCB( Fcb );
|
||||
|
||||
//
|
||||
// Set the entry counts to show there is one entry in the array and
|
||||
// it is unused.
|
||||
//
|
||||
|
||||
Fcb->Mcb.MaximumEntryCount = 1;
|
||||
Fcb->Mcb.CurrentEntryCount = 0;
|
||||
|
||||
Fcb->Mcb.McbArray = &Fcb->McbEntry;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdUninitializeMcb (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to cleanup an Mcb in an Fcb. We look at the
|
||||
maximum run count in the Fcb and if greater than one we will deallocate
|
||||
the buffer.
|
||||
|
||||
Fcb should be acquired exclusively when this is called.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - Fcb containing the Mcb to uninitialize.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_FCB( Fcb );
|
||||
|
||||
//
|
||||
// If the count is greater than one then this is an allocated buffer.
|
||||
//
|
||||
|
||||
if (Fcb->Mcb.MaximumEntryCount > 1) {
|
||||
|
||||
CdFreePool( &Fcb->Mcb.McbArray );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local suupport routine
|
||||
//
|
||||
|
||||
ULONG
|
||||
CdFindMcbEntry (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN LONGLONG FileOffset
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to find the Mcb entry which contains the file
|
||||
offset at the given point. If the file offset is not currently in the
|
||||
Mcb then we return the offset of the entry to add.
|
||||
|
||||
Fcb should be locked when this is called.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - Fcb containing the Mcb to uninitialize.
|
||||
|
||||
FileOffset - Return the Mcb entry which contains this file offset.
|
||||
|
||||
Return Value:
|
||||
|
||||
ULONG - Offset in the Mcb of the entry for this offset.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ULONG CurrentMcbOffset;
|
||||
PCD_MCB_ENTRY CurrentMcbEntry;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_FCB( Fcb );
|
||||
ASSERT_LOCKED_FCB( Fcb );
|
||||
|
||||
//
|
||||
// We expect a linear search will be sufficient here.
|
||||
//
|
||||
|
||||
CurrentMcbOffset = 0;
|
||||
CurrentMcbEntry = Fcb->Mcb.McbArray;
|
||||
|
||||
while (CurrentMcbOffset < Fcb->Mcb.CurrentEntryCount) {
|
||||
|
||||
//
|
||||
// Check if the offset lies within the current Mcb position.
|
||||
//
|
||||
|
||||
if (FileOffset < CurrentMcbEntry->FileOffset + CurrentMcbEntry->ByteCount) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Move to the next entry.
|
||||
//
|
||||
|
||||
CurrentMcbOffset += 1;
|
||||
CurrentMcbEntry += 1;
|
||||
}
|
||||
|
||||
//
|
||||
// This is the offset containing this file offset (or the point
|
||||
// where an entry should be added).
|
||||
//
|
||||
|
||||
return CurrentMcbOffset;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
VOID
|
||||
CdDiskOffsetFromMcbEntry (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PCD_MCB_ENTRY McbEntry,
|
||||
IN LONGLONG FileOffset,
|
||||
IN PLONGLONG DiskOffset,
|
||||
IN PULONG ByteCount
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to return the diskoffset and length of the file
|
||||
data which begins at offset 'FileOffset'. We have the Mcb entry which
|
||||
contains the mapping and interleave information.
|
||||
|
||||
NOTE - This routine deals with data in 2048 byte logical sectors. If
|
||||
this is an XA file then our caller has already converted from
|
||||
'raw' file bytes to 'cooked' file bytes.
|
||||
|
||||
Arguments:
|
||||
|
||||
McbEntry - Entry in the Mcb containing the allocation information.
|
||||
|
||||
FileOffset - Starting Offset in the file to find the matching disk
|
||||
offsets.
|
||||
|
||||
DiskOffset - Address to store the starting disk offset for this operation.
|
||||
|
||||
ByteCount - Address to store number of contiguous bytes starting at this
|
||||
disk offset.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
LONGLONG ExtentOffset;
|
||||
|
||||
LONGLONG CurrentDiskOffset;
|
||||
LONGLONG CurrentExtentOffset;
|
||||
|
||||
LONGLONG LocalByteCount;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
|
||||
//
|
||||
// Extent offset is the difference between the file offset and the start
|
||||
// of the extent.
|
||||
//
|
||||
|
||||
ExtentOffset = FileOffset - McbEntry->FileOffset;
|
||||
|
||||
//
|
||||
// Optimize the non-interleave case.
|
||||
//
|
||||
|
||||
if (McbEntry->ByteCount == McbEntry->DataBlockByteCount) {
|
||||
|
||||
*DiskOffset = McbEntry->DiskOffset + ExtentOffset;
|
||||
|
||||
LocalByteCount = McbEntry->ByteCount - ExtentOffset;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Walk though any interleave until we reach the current offset in
|
||||
// this extent.
|
||||
//
|
||||
|
||||
CurrentExtentOffset = McbEntry->DataBlockByteCount;
|
||||
CurrentDiskOffset = McbEntry->DiskOffset;
|
||||
|
||||
while (CurrentExtentOffset <= ExtentOffset) {
|
||||
|
||||
CurrentDiskOffset += McbEntry->TotalBlockByteCount;
|
||||
CurrentExtentOffset += McbEntry->DataBlockByteCount;
|
||||
}
|
||||
|
||||
//
|
||||
// We are now positioned at the data block containing the starting
|
||||
// file offset we were given. The disk offset is the offset of
|
||||
// the start of this block plus the extent offset into this block.
|
||||
// The byte count is the data block byte count minus our offset into
|
||||
// this block.
|
||||
//
|
||||
|
||||
*DiskOffset = CurrentDiskOffset + (ExtentOffset + McbEntry->DataBlockByteCount - CurrentExtentOffset);
|
||||
|
||||
//
|
||||
// Make sure we aren't past the end of the data length. This is possible
|
||||
// if we only use part of the last data block on an interleaved file.
|
||||
//
|
||||
|
||||
if (CurrentExtentOffset > McbEntry->ByteCount) {
|
||||
|
||||
CurrentExtentOffset = McbEntry->ByteCount;
|
||||
}
|
||||
|
||||
LocalByteCount = CurrentExtentOffset - ExtentOffset;
|
||||
}
|
||||
|
||||
//
|
||||
// If the byte count exceeds our limit then cut it to fit in 32 bits.
|
||||
//
|
||||
|
||||
if (LocalByteCount > MAXULONG) {
|
||||
|
||||
*ByteCount = MAXULONG;
|
||||
|
||||
} else {
|
||||
|
||||
*ByteCount = (ULONG) LocalByteCount;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
+644
@@ -0,0 +1,644 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1990-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
Cache.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the cache management routines for the Cdfs
|
||||
FSD and FSP, by calling the Common Cache Manager.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_CACHESUP)
|
||||
|
||||
//
|
||||
// Local debug trace level
|
||||
//
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdCompleteMdl)
|
||||
#pragma alloc_text(PAGE, CdCreateInternalStream)
|
||||
#pragma alloc_text(PAGE, CdDeleteInternalStream)
|
||||
#pragma alloc_text(PAGE, CdPurgeVolume)
|
||||
#endif
|
||||
|
||||
|
||||
VOID
|
||||
CdCreateInternalStream (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PFCB Fcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This function creates an internal stream file for interaction
|
||||
with the cache manager. The Fcb here can be for either a
|
||||
directory stream or for a path table stream.
|
||||
|
||||
Arguments:
|
||||
|
||||
Vcb - Vcb for this volume.
|
||||
|
||||
Fcb - Points to the Fcb for this file. It is either an Index or
|
||||
Path Table Fcb.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PFILE_OBJECT StreamFile = NULL;
|
||||
BOOLEAN DecrementReference = FALSE;
|
||||
|
||||
BOOLEAN CleanupDirContext = FALSE;
|
||||
BOOLEAN UpdateFcbSizes = FALSE;
|
||||
|
||||
DIRENT Dirent;
|
||||
DIRENT_ENUM_CONTEXT DirContext;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_FCB( Fcb );
|
||||
|
||||
//
|
||||
// We may only have the Fcb shared. Lock the Fcb and do a
|
||||
// safe test to see if we need to really create the file object.
|
||||
//
|
||||
|
||||
CdLockFcb( IrpContext, Fcb );
|
||||
|
||||
if (Fcb->FileObject != NULL) {
|
||||
|
||||
CdUnlockFcb( IrpContext, Fcb );
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Use a try-finally to facilitate cleanup.
|
||||
//
|
||||
|
||||
try {
|
||||
|
||||
//
|
||||
// Create the internal stream. The Vpb should be pointing at our volume
|
||||
// device object at this point.
|
||||
//
|
||||
|
||||
StreamFile = IoCreateStreamFileObject( NULL, Vcb->Vpb->RealDevice );
|
||||
|
||||
if (StreamFile == NULL) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the fields of the file object.
|
||||
//
|
||||
|
||||
StreamFile->ReadAccess = TRUE;
|
||||
StreamFile->WriteAccess = FALSE;
|
||||
StreamFile->DeleteAccess = FALSE;
|
||||
|
||||
StreamFile->SectionObjectPointer = &Fcb->FcbNonpaged->SegmentObject;
|
||||
|
||||
//
|
||||
// Set the file object type and increment the Vcb counts.
|
||||
//
|
||||
|
||||
CdSetFileObject( IrpContext,
|
||||
StreamFile,
|
||||
StreamFileOpen,
|
||||
Fcb,
|
||||
NULL );
|
||||
|
||||
//
|
||||
// We will reference the current Fcb twice to keep it from going
|
||||
// away in the error path. Otherwise if we dereference it
|
||||
// below in the finally clause a close could cause the Fcb to
|
||||
// be deallocated.
|
||||
//
|
||||
|
||||
CdLockVcb( IrpContext, Vcb );
|
||||
CdIncrementReferenceCounts( IrpContext, Fcb, 2, 0 );
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
DecrementReference = TRUE;
|
||||
|
||||
//
|
||||
// Initialize the cache map for the file.
|
||||
//
|
||||
|
||||
CcInitializeCacheMap( StreamFile,
|
||||
(PCC_FILE_SIZES)&Fcb->AllocationSize,
|
||||
TRUE,
|
||||
&CdData.CacheManagerCallbacks,
|
||||
Fcb );
|
||||
|
||||
//
|
||||
// Go ahead and store the stream file into the Fcb.
|
||||
//
|
||||
|
||||
Fcb->FileObject = StreamFile;
|
||||
StreamFile = NULL;
|
||||
|
||||
//
|
||||
// If this is the first file object for a directory then we need to
|
||||
// read the self entry for this directory and update the sizes
|
||||
// in the Fcb. We know that the Fcb has been initialized so
|
||||
// that we have a least one sector available to read.
|
||||
//
|
||||
|
||||
if (!FlagOn( Fcb->FcbState, FCB_STATE_INITIALIZED )) {
|
||||
|
||||
ULONG NewDataLength;
|
||||
|
||||
//
|
||||
// Initialize the search structures.
|
||||
//
|
||||
|
||||
CdInitializeDirContext( IrpContext, &DirContext );
|
||||
CdInitializeDirent( IrpContext, &Dirent );
|
||||
CleanupDirContext = TRUE;
|
||||
|
||||
//
|
||||
// Read the dirent from disk and transfer the data to the
|
||||
// in-memory dirent.
|
||||
//
|
||||
|
||||
CdLookupDirent( IrpContext,
|
||||
Fcb,
|
||||
Fcb->StreamOffset,
|
||||
&DirContext );
|
||||
|
||||
CdUpdateDirentFromRawDirent( IrpContext, Fcb, &DirContext, &Dirent );
|
||||
|
||||
//
|
||||
// Verify that this really for the self entry. We do this by
|
||||
// updating the name in the dirent and then checking that it matches
|
||||
// one of the hard coded names.
|
||||
//
|
||||
|
||||
CdUpdateDirentName( IrpContext, &Dirent, FALSE );
|
||||
|
||||
if (Dirent.CdFileName.FileName.Buffer != CdUnicodeSelfArray) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
|
||||
}
|
||||
|
||||
//
|
||||
// If the data sizes are different then update the header
|
||||
// and Mcb for this Fcb.
|
||||
//
|
||||
|
||||
NewDataLength = BlockAlign( Vcb, Dirent.DataLength + Fcb->StreamOffset );
|
||||
|
||||
if (NewDataLength == 0) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
|
||||
}
|
||||
|
||||
if (NewDataLength != Fcb->FileSize.QuadPart) {
|
||||
|
||||
Fcb->AllocationSize.QuadPart =
|
||||
Fcb->FileSize.QuadPart =
|
||||
Fcb->ValidDataLength.QuadPart = NewDataLength;
|
||||
|
||||
CcSetFileSizes( Fcb->FileObject, (PCC_FILE_SIZES) &Fcb->AllocationSize );
|
||||
|
||||
CdTruncateAllocation( IrpContext, Fcb, 0 );
|
||||
CdAddInitialAllocation( IrpContext,
|
||||
Fcb,
|
||||
Dirent.StartingOffset,
|
||||
NewDataLength );
|
||||
|
||||
UpdateFcbSizes = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Check for the existence flag and transform to hidden.
|
||||
//
|
||||
|
||||
if (FlagOn( Dirent.DirentFlags, CD_ATTRIBUTE_HIDDEN )) {
|
||||
|
||||
SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
|
||||
}
|
||||
|
||||
//
|
||||
// Convert the time to NT time.
|
||||
//
|
||||
|
||||
CdConvertCdTimeToNtTime( IrpContext,
|
||||
Dirent.CdTime,
|
||||
(PLARGE_INTEGER) &Fcb->CreationTime );
|
||||
|
||||
//
|
||||
// Update the Fcb flags to indicate we have read the
|
||||
// self entry.
|
||||
//
|
||||
|
||||
SetFlag( Fcb->FcbState, FCB_STATE_INITIALIZED );
|
||||
|
||||
//
|
||||
// If we updated the sizes then we want to purge the file. Go
|
||||
// ahead and unpin and then purge the first page.
|
||||
//
|
||||
|
||||
CdCleanupDirContext( IrpContext, &DirContext );
|
||||
CdCleanupDirent( IrpContext, &Dirent );
|
||||
CleanupDirContext = FALSE;
|
||||
|
||||
if (UpdateFcbSizes) {
|
||||
|
||||
CcPurgeCacheSection( &Fcb->FcbNonpaged->SegmentObject,
|
||||
NULL,
|
||||
0,
|
||||
FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
|
||||
//
|
||||
// Cleanup any dirent structures we may have used.
|
||||
//
|
||||
|
||||
if (CleanupDirContext) {
|
||||
|
||||
CdCleanupDirContext( IrpContext, &DirContext );
|
||||
CdCleanupDirent( IrpContext, &Dirent );
|
||||
}
|
||||
|
||||
//
|
||||
// If we raised then we need to dereference the file object.
|
||||
//
|
||||
|
||||
if (StreamFile != NULL) {
|
||||
|
||||
ObDereferenceObject( StreamFile );
|
||||
Fcb->FileObject = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Dereference and unlock the Fcb.
|
||||
//
|
||||
|
||||
if (DecrementReference) {
|
||||
|
||||
CdLockVcb( IrpContext, Vcb );
|
||||
CdDecrementReferenceCounts( IrpContext, Fcb, 1, 0 );
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
}
|
||||
|
||||
CdUnlockFcb( IrpContext, Fcb );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdDeleteInternalStream (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This function creates an internal stream file for interaction
|
||||
with the cache manager. The Fcb here can be for either a
|
||||
directory stream or for a path table stream.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - Points to the Fcb for this file. It is either an Index or
|
||||
Path Table Fcb.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PFILE_OBJECT FileObject;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_FCB( Fcb );
|
||||
|
||||
//
|
||||
// Lock the Fcb.
|
||||
//
|
||||
|
||||
CdLockFcb( IrpContext, Fcb );
|
||||
|
||||
//
|
||||
// Capture the file object.
|
||||
//
|
||||
|
||||
FileObject = Fcb->FileObject;
|
||||
Fcb->FileObject = NULL;
|
||||
|
||||
//
|
||||
// It is now safe to unlock the Fcb.
|
||||
//
|
||||
|
||||
CdUnlockFcb( IrpContext, Fcb );
|
||||
|
||||
//
|
||||
// Dereference the file object if present.
|
||||
//
|
||||
|
||||
if (FileObject != NULL) {
|
||||
|
||||
if (FileObject->PrivateCacheMap != NULL) {
|
||||
|
||||
CcUninitializeCacheMap( FileObject, NULL, NULL );
|
||||
}
|
||||
|
||||
ObDereferenceObject( FileObject );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdCompleteMdl (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine performs the function of completing Mdl reads.
|
||||
It should be called only from CdFsdRead.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Supplies the originating Irp.
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - Will always be STATUS_SUCCESS.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PFILE_OBJECT FileObject;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Do completion processing.
|
||||
//
|
||||
|
||||
FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject;
|
||||
|
||||
CcMdlReadComplete( FileObject, Irp->MdlAddress );
|
||||
|
||||
//
|
||||
// Mdl is now deallocated.
|
||||
//
|
||||
|
||||
Irp->MdlAddress = NULL;
|
||||
|
||||
//
|
||||
// Complete the request and exit right away.
|
||||
//
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdPurgeVolume (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN BOOLEAN DismountUnderway
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to purge the volume. The purpose is to make all the stale file
|
||||
objects in the system go away in order to lock the volume.
|
||||
|
||||
The Vcb is already acquired exclusively. We will lock out all file operations by
|
||||
acquiring the global file resource. Then we will walk through all of the Fcb's and
|
||||
perform the purge.
|
||||
|
||||
Arguments:
|
||||
|
||||
Vcb - Vcb for the volume to purge.
|
||||
|
||||
DismountUnderway - Indicates that we are trying to delete all of the objects.
|
||||
We will purge the Path Table and VolumeDasd and dereference all
|
||||
internal streams.
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The first failure of the purge operation.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PVOID RestartKey = NULL;
|
||||
PFCB ThisFcb = NULL;
|
||||
PFCB NextFcb;
|
||||
|
||||
BOOLEAN RemovedFcb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_EXCLUSIVE_VCB( Vcb);
|
||||
|
||||
//
|
||||
// Force any remaining Fcb's in the delayed close queue to be closed.
|
||||
//
|
||||
|
||||
CdFspClose( Vcb );
|
||||
|
||||
//
|
||||
// Acquire the global file resource.
|
||||
//
|
||||
|
||||
CdAcquireAllFiles( IrpContext, Vcb );
|
||||
|
||||
//
|
||||
// Loop through each Fcb in the Fcb Table and perform the flush.
|
||||
//
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
//
|
||||
// Lock the Vcb to lookup the next Fcb.
|
||||
//
|
||||
|
||||
CdLockVcb( IrpContext, Vcb );
|
||||
NextFcb = CdGetNextFcb( IrpContext, Vcb, &RestartKey );
|
||||
|
||||
//
|
||||
// Reference the NextFcb if present.
|
||||
//
|
||||
|
||||
if (NextFcb != NULL) {
|
||||
|
||||
NextFcb->FcbReference += 1;
|
||||
}
|
||||
|
||||
//
|
||||
// If the last Fcb is present then decrement reference count and call teardown
|
||||
// to see if it should be removed.
|
||||
//
|
||||
|
||||
if (ThisFcb != NULL) {
|
||||
|
||||
ThisFcb->FcbReference -= 1;
|
||||
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
|
||||
CdTeardownStructures( IrpContext, ThisFcb, &RemovedFcb );
|
||||
|
||||
} else {
|
||||
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
}
|
||||
|
||||
//
|
||||
// Break out of the loop if no more Fcb's.
|
||||
//
|
||||
|
||||
if (NextFcb == NULL) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Move to the next Fcb.
|
||||
//
|
||||
|
||||
ThisFcb = NextFcb;
|
||||
|
||||
//
|
||||
// If there is a image section then see if that can be closed.
|
||||
//
|
||||
|
||||
if (ThisFcb->FcbNonpaged->SegmentObject.ImageSectionObject != NULL) {
|
||||
|
||||
MmFlushImageSection( &ThisFcb->FcbNonpaged->SegmentObject, MmFlushForWrite );
|
||||
}
|
||||
|
||||
//
|
||||
// If there is a data section then purge this. If there is an image
|
||||
// section then we won't be able to. Remember this if it is our first
|
||||
// error.
|
||||
//
|
||||
|
||||
if ((ThisFcb->FcbNonpaged->SegmentObject.DataSectionObject != NULL) &&
|
||||
!CcPurgeCacheSection( &ThisFcb->FcbNonpaged->SegmentObject,
|
||||
NULL,
|
||||
0,
|
||||
FALSE ) &&
|
||||
(Status == STATUS_SUCCESS)) {
|
||||
|
||||
Status = STATUS_UNABLE_TO_DELETE_SECTION;
|
||||
}
|
||||
|
||||
//
|
||||
// Dereference the internal stream if dismounting.
|
||||
//
|
||||
|
||||
if (DismountUnderway &&
|
||||
(SafeNodeType( ThisFcb ) != CDFS_NTC_FCB_DATA) &&
|
||||
(ThisFcb->FileObject != NULL)) {
|
||||
|
||||
CdDeleteInternalStream( IrpContext, ThisFcb );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Now look at the path table and volume Dasd Fcb's.
|
||||
//
|
||||
|
||||
if (DismountUnderway) {
|
||||
|
||||
if (Vcb->PathTableFcb != NULL) {
|
||||
|
||||
ThisFcb = Vcb->PathTableFcb;
|
||||
InterlockedIncrement( &Vcb->PathTableFcb->FcbReference );
|
||||
|
||||
if ((ThisFcb->FcbNonpaged->SegmentObject.DataSectionObject != NULL) &&
|
||||
!CcPurgeCacheSection( &ThisFcb->FcbNonpaged->SegmentObject,
|
||||
NULL,
|
||||
0,
|
||||
FALSE ) &&
|
||||
(Status == STATUS_SUCCESS)) {
|
||||
|
||||
Status = STATUS_UNABLE_TO_DELETE_SECTION;
|
||||
}
|
||||
|
||||
CdDeleteInternalStream( IrpContext, ThisFcb );
|
||||
|
||||
InterlockedDecrement( &ThisFcb->FcbReference );
|
||||
|
||||
CdTeardownStructures( IrpContext, ThisFcb, &RemovedFcb );
|
||||
}
|
||||
|
||||
if (Vcb->VolumeDasdFcb != NULL) {
|
||||
|
||||
ThisFcb = Vcb->VolumeDasdFcb;
|
||||
InterlockedIncrement( &ThisFcb->FcbReference );
|
||||
|
||||
if ((ThisFcb->FcbNonpaged->SegmentObject.DataSectionObject != NULL) &&
|
||||
!CcPurgeCacheSection( &ThisFcb->FcbNonpaged->SegmentObject,
|
||||
NULL,
|
||||
0,
|
||||
FALSE ) &&
|
||||
(Status == STATUS_SUCCESS)) {
|
||||
|
||||
Status = STATUS_UNABLE_TO_DELETE_SECTION;
|
||||
}
|
||||
|
||||
InterlockedDecrement( &ThisFcb->FcbReference );
|
||||
|
||||
CdTeardownStructures( IrpContext, ThisFcb, &RemovedFcb );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Release all of the files.
|
||||
//
|
||||
|
||||
CdReleaseAllFiles( IrpContext, Vcb );
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
Executable
+534
@@ -0,0 +1,534 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
Cd.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This module defines the on-disk structure of the Cdfs file system.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _CDFS_
|
||||
#define _CDFS_
|
||||
|
||||
//
|
||||
// Sector size on Cdrom disks is hard-coded to 2048
|
||||
//
|
||||
|
||||
#ifndef SECTOR_SIZE
|
||||
#define SECTOR_SIZE (2048)
|
||||
#endif
|
||||
|
||||
#define RAW_SECTOR_SIZE (2352)
|
||||
#define SECTOR_MASK (SECTOR_SIZE - 1)
|
||||
#define INVERSE_SECTOR_MASK ~(SECTOR_SIZE - 1)
|
||||
|
||||
#ifndef SECTOR_SHIFT
|
||||
#define SECTOR_SHIFT (11)
|
||||
#endif
|
||||
|
||||
#define XA_SECTOR_SIZE (2352)
|
||||
|
||||
//
|
||||
// Cdfs file id is a large integer.
|
||||
//
|
||||
|
||||
typedef LARGE_INTEGER FILE_ID;
|
||||
typedef FILE_ID *PFILE_ID;
|
||||
|
||||
//
|
||||
// The following constants are values from the disk.
|
||||
//
|
||||
|
||||
#define FIRST_VD_SECTOR (16)
|
||||
|
||||
#define VOL_ID_LEN (5)
|
||||
#define ESC_SEQ_LEN (3)
|
||||
|
||||
#define VERSION_1 (1)
|
||||
|
||||
#define VD_TERMINATOR (255)
|
||||
#define VD_PRIMARY (1)
|
||||
#define VD_SECONDARY (2)
|
||||
|
||||
#define VOLUME_ID_LENGTH (32)
|
||||
|
||||
//
|
||||
// Leave the following so that CdfsBoot.c will compile
|
||||
//
|
||||
|
||||
#define CD_SECTOR_SIZE (2048)
|
||||
|
||||
#define ISO_VOL_ID "CD001"
|
||||
#define HSG_VOL_ID "CDROM"
|
||||
|
||||
#define ISO_ATTR_MULTI 0x0080
|
||||
#define ISO_ATTR_DIRECTORY 0x0002
|
||||
|
||||
#define MIN_DIR_REC_SIZE (sizeof( RAW_DIR_REC ) - MAX_FILE_ID_LENGTH)
|
||||
|
||||
#define RVD_STD_ID( r, i ) (i ? r->StandardId : \
|
||||
((PRAW_HSG_VD) r)->StandardId )
|
||||
|
||||
#define RVD_DESC_TYPE( r, i ) (i ? r->DescType : \
|
||||
((PRAW_HSG_VD) r)->DescType )
|
||||
|
||||
#define RVD_VERSION( r, i ) (i ? r->Version : \
|
||||
((PRAW_HSG_VD) r)->Version )
|
||||
|
||||
#define RVD_LB_SIZE( r, i ) (i ? r->LogicalBlkSzI : \
|
||||
((PRAW_HSG_VD) r)->LogicalBlkSzI )
|
||||
|
||||
#define RVD_VOL_SIZE( r, i ) (i ? r->VolSpaceI : \
|
||||
((PRAW_HSG_VD) r)->VolSpaceI )
|
||||
|
||||
#define RVD_ROOT_DE( r, i ) (i ? r->RootDe : \
|
||||
((PRAW_HSG_VD) r)->RootDe )
|
||||
|
||||
#define DE_FILE_FLAGS( iso, de ) (iso ? de->FlagsISO : de->FlagsHSG)
|
||||
|
||||
//
|
||||
// Data track flag for track entries in TOC
|
||||
//
|
||||
|
||||
#define TOC_DATA_TRACK (0x04)
|
||||
#define TOC_LAST_TRACK (0xaa)
|
||||
|
||||
|
||||
//
|
||||
// There is considerable rearrangement of the volume descriptors for
|
||||
// ISO and HSG. However, within each standard the same structure can
|
||||
// be used for both the primary and secondary descriptors.
|
||||
//
|
||||
// Both of these structures are aligned correctly so that no
|
||||
// special macros will be needed to unpack them.
|
||||
//
|
||||
|
||||
//
|
||||
// Declaration of length of root directory entry in volume descriptor
|
||||
//
|
||||
|
||||
#define LEN_ROOT_DE (34)
|
||||
|
||||
//
|
||||
// Maximum length of file ID on the disk. We allow file size beyond the ISO 9660
|
||||
// standard.
|
||||
//
|
||||
|
||||
#define MAX_FILE_ID_LENGTH (255)
|
||||
|
||||
|
||||
typedef struct _RAW_ISO_VD {
|
||||
|
||||
UCHAR DescType; // volume type: 1 = standard, 2 = coded
|
||||
UCHAR StandardId[5]; // volume structure standard id = CD001
|
||||
UCHAR Version; // volume structure version number = 1
|
||||
UCHAR VolumeFlags; // volume flags
|
||||
UCHAR SystemId[32]; // system identifier
|
||||
UCHAR VolumeId[32]; // volume identifier
|
||||
UCHAR Reserved[8]; // reserved 8 = 0
|
||||
ULONG VolSpaceI; // size of the volume in LBN's Intel
|
||||
ULONG VolSpaceM; // size of the volume in LBN's Motorola
|
||||
UCHAR CharSet[32]; // character set bytes 0 = ASCII
|
||||
USHORT VolSetSizeI; // volume set size Intel
|
||||
USHORT VolSetSizeM; // volume set size Motorola
|
||||
USHORT VolSeqNumI; // volume set sequence number Intel
|
||||
USHORT VolSeqNumM; // volume set sequence number Motorola
|
||||
USHORT LogicalBlkSzI; // logical block size Intel
|
||||
USHORT LogicalBlkSzM; // logical block size Motorola
|
||||
ULONG PathTableSzI; // path table size in bytes Intel
|
||||
ULONG PathTableSzM; // path table size in bytes Motorola
|
||||
ULONG PathTabLocI[2]; // LBN of 2 path tables Intel
|
||||
ULONG PathTabLocM[2]; // LBN of 2 path tables Motorola
|
||||
UCHAR RootDe[LEN_ROOT_DE];// dir entry of the root directory
|
||||
UCHAR VolSetId[128]; // volume set identifier
|
||||
UCHAR PublId[128]; // publisher identifier
|
||||
UCHAR PreparerId[128]; // data preparer identifier
|
||||
UCHAR AppId[128]; // application identifier
|
||||
UCHAR Copyright[37]; // file name of copyright notice
|
||||
UCHAR Abstract[37]; // file name of abstract
|
||||
UCHAR Bibliograph[37]; // file name of bibliography
|
||||
UCHAR CreateDate[17]; // volume creation date and time
|
||||
UCHAR ModDate[17]; // volume modification date and time
|
||||
UCHAR ExpireDate[17]; // volume expiration date and time
|
||||
UCHAR EffectDate[17]; // volume effective date and time
|
||||
UCHAR FileStructVer; // file structure version number = 1
|
||||
UCHAR Reserved3; // reserved
|
||||
UCHAR ResApp[512]; // reserved for application
|
||||
UCHAR Reserved4[653]; // remainder of 2048 bytes reserved
|
||||
|
||||
} RAW_ISO_VD;
|
||||
typedef RAW_ISO_VD *PRAW_ISO_VD;
|
||||
|
||||
|
||||
typedef struct _RAW_HSG_VD {
|
||||
|
||||
ULONG BlkNumI; // logical block number Intel
|
||||
ULONG BlkNumM; // logical block number Motorola
|
||||
UCHAR DescType; // volume type: 1 = standard, 2 = coded
|
||||
UCHAR StandardId[5]; // volume structure standard id = CDROM
|
||||
UCHAR Version; // volume structure version number = 1
|
||||
UCHAR VolumeFlags; // volume flags
|
||||
UCHAR SystemId[32]; // system identifier
|
||||
UCHAR VolumeId[32]; // volume identifier
|
||||
UCHAR Reserved[8]; // reserved 8 = 0
|
||||
ULONG VolSpaceI; // size of the volume in LBN's Intel
|
||||
ULONG VolSpaceM; // size of the volume in LBN's Motorola
|
||||
UCHAR CharSet[32]; // character set bytes 0 = ASCII
|
||||
USHORT VolSetSizeI; // volume set size Intel
|
||||
USHORT VolSetSizeM; // volume set size Motorola
|
||||
USHORT VolSeqNumI; // volume set sequence number Intel
|
||||
USHORT VolSeqNumM; // volume set sequence number Motorola
|
||||
USHORT LogicalBlkSzI; // logical block size Intel
|
||||
USHORT LogicalBlkSzM; // logical block size Motorola
|
||||
ULONG PathTableSzI; // path table size in bytes Intel
|
||||
ULONG PathTableSzM; // path table size in bytes Motorola
|
||||
ULONG PathTabLocI[4]; // LBN of 4 path tables Intel
|
||||
ULONG PathTabLocM[4]; // LBN of 4 path tables Motorola
|
||||
UCHAR RootDe[LEN_ROOT_DE];// dir entry of the root directory
|
||||
UCHAR VolSetId[128]; // volume set identifier
|
||||
UCHAR PublId[128]; // publisher identifier
|
||||
UCHAR PreparerId[128]; // data preparer identifier
|
||||
UCHAR AppId[128]; // application identifier
|
||||
UCHAR Copyright[32]; // file name of copyright notice
|
||||
UCHAR Abstract[32]; // file name of abstract
|
||||
UCHAR CreateDate[16]; // volume creation date and time
|
||||
UCHAR ModDate[16]; // volume modification date and time
|
||||
UCHAR ExpireDate[16]; // volume expiration date and time
|
||||
UCHAR EffectDate[16]; // volume effective date and time
|
||||
UCHAR FileStructVer; // file structure version number
|
||||
UCHAR Reserved3; // reserved
|
||||
UCHAR ResApp[512]; // reserved for application
|
||||
UCHAR Reserved4[680]; // remainder of 2048 bytes reserved
|
||||
|
||||
} RAW_HSG_VD;
|
||||
typedef RAW_HSG_VD *PRAW_HSG_VD;
|
||||
|
||||
|
||||
typedef struct _RAW_JOLIET_VD {
|
||||
|
||||
UCHAR DescType; // volume type: 2 = coded
|
||||
UCHAR StandardId[5]; // volume structure standard id = CD001
|
||||
UCHAR Version; // volume structure version number = 1
|
||||
UCHAR VolumeFlags; // volume flags
|
||||
UCHAR SystemId[32]; // system identifier
|
||||
UCHAR VolumeId[32]; // volume identifier
|
||||
UCHAR Reserved[8]; // reserved 8 = 0
|
||||
ULONG VolSpaceI; // size of the volume in LBN's Intel
|
||||
ULONG VolSpaceM; // size of the volume in LBN's Motorola
|
||||
UCHAR CharSet[32]; // character set bytes 0 = ASCII, Joliett Seq here
|
||||
USHORT VolSetSizeI; // volume set size Intel
|
||||
USHORT VolSetSizeM; // volume set size Motorola
|
||||
USHORT VolSeqNumI; // volume set sequence number Intel
|
||||
USHORT VolSeqNumM; // volume set sequence number Motorola
|
||||
USHORT LogicalBlkSzI; // logical block size Intel
|
||||
USHORT LogicalBlkSzM; // logical block size Motorola
|
||||
ULONG PathTableSzI; // path table size in bytes Intel
|
||||
ULONG PathTableSzM; // path table size in bytes Motorola
|
||||
ULONG PathTabLocI[2]; // LBN of 2 path tables Intel
|
||||
ULONG PathTabLocM[2]; // LBN of 2 path tables Motorola
|
||||
UCHAR RootDe[LEN_ROOT_DE];// dir entry of the root directory
|
||||
UCHAR VolSetId[128]; // volume set identifier
|
||||
UCHAR PublId[128]; // publisher identifier
|
||||
UCHAR PreparerId[128]; // data preparer identifier
|
||||
UCHAR AppId[128]; // application identifier
|
||||
UCHAR Copyright[37]; // file name of copyright notice
|
||||
UCHAR Abstract[37]; // file name of abstract
|
||||
UCHAR Bibliograph[37]; // file name of bibliography
|
||||
UCHAR CreateDate[17]; // volume creation date and time
|
||||
UCHAR ModDate[17]; // volume modification date and time
|
||||
UCHAR ExpireDate[17]; // volume expiration date and time
|
||||
UCHAR EffectDate[17]; // volume effective date and time
|
||||
UCHAR FileStructVer; // file structure version number = 1
|
||||
UCHAR Reserved3; // reserved
|
||||
UCHAR ResApp[512]; // reserved for application
|
||||
UCHAR Reserved4[653]; // remainder of 2048 bytes reserved
|
||||
|
||||
} RAW_JOLIET_VD;
|
||||
typedef RAW_JOLIET_VD *PRAW_JOLIET_VD;
|
||||
|
||||
//
|
||||
// Macros to access the different volume descriptors.
|
||||
//
|
||||
|
||||
#define CdRvdId(R,F) ( \
|
||||
FlagOn( (F), VCB_STATE_HSG ) ? \
|
||||
((PRAW_HSG_VD) (R))->StandardId : \
|
||||
((PRAW_ISO_VD) (R))->StandardId \
|
||||
)
|
||||
|
||||
#define CdRvdVersion(R,F) ( \
|
||||
FlagOn( (F), VCB_STATE_HSG ) ? \
|
||||
((PRAW_HSG_VD) (R))->Version : \
|
||||
((PRAW_ISO_VD) (R))->Version \
|
||||
)
|
||||
|
||||
#define CdRvdDescType(R,F) ( \
|
||||
FlagOn( (F), VCB_STATE_HSG ) ? \
|
||||
((PRAW_HSG_VD) (R))->DescType : \
|
||||
((PRAW_ISO_VD) (R))->DescType \
|
||||
)
|
||||
|
||||
#define CdRvdEsc(R,F) ( \
|
||||
FlagOn( (F), VCB_STATE_HSG ) ? \
|
||||
((PRAW_HSG_VD) (R))->CharSet : \
|
||||
((PRAW_ISO_VD) (R))->CharSet \
|
||||
)
|
||||
|
||||
#define CdRvdVolId(R,F) ( \
|
||||
FlagOn( (F), VCB_STATE_HSG ) ? \
|
||||
((PRAW_HSG_VD) (R))->VolumeId : \
|
||||
((PRAW_ISO_VD) (R))->VolumeId \
|
||||
)
|
||||
|
||||
#define CdRvdBlkSz(R,F) ( \
|
||||
FlagOn( (F), VCB_STATE_HSG ) ? \
|
||||
((PRAW_HSG_VD) (R))->LogicalBlkSzI :\
|
||||
((PRAW_ISO_VD) (R))->LogicalBlkSzI \
|
||||
)
|
||||
|
||||
#define CdRvdPtLoc(R,F) ( \
|
||||
FlagOn( (F), VCB_STATE_HSG ) ? \
|
||||
((PRAW_HSG_VD) (R))->PathTabLocI[0]:\
|
||||
((PRAW_ISO_VD) (R))->PathTabLocI[0] \
|
||||
)
|
||||
|
||||
#define CdRvdPtSz(R,F) ( \
|
||||
FlagOn( (F), VCB_STATE_HSG ) ? \
|
||||
((PRAW_HSG_VD) (R))->PathTableSzI : \
|
||||
((PRAW_ISO_VD) (R))->PathTableSzI \
|
||||
)
|
||||
|
||||
#define CdRvdDirent(R,F) ( \
|
||||
FlagOn( (F), VCB_STATE_HSG ) ? \
|
||||
((PRAW_HSG_VD) (R))->RootDe : \
|
||||
((PRAW_ISO_VD) (R))->RootDe \
|
||||
)
|
||||
|
||||
#define CdRvdVolSz(R,F) ( \
|
||||
FlagOn( (F), VCB_STATE_HSG ) ? \
|
||||
((PRAW_HSG_VD) (R))->VolSpaceI : \
|
||||
((PRAW_ISO_VD) (R))->VolSpaceI \
|
||||
)
|
||||
|
||||
|
||||
//
|
||||
// This structure is used to overlay a region of a disk sector
|
||||
// to retrieve a single directory entry. There is a difference
|
||||
// in the file flags between the ISO and HSG version and a
|
||||
// additional byte in the ISO for the offset from Greenwich time.
|
||||
//
|
||||
// The disk structure is aligned on a word boundary, so any 32
|
||||
// bit fields will be represented as an array of 16 bit fields.
|
||||
//
|
||||
|
||||
typedef struct _RAW_DIRENT {
|
||||
|
||||
UCHAR DirLen;
|
||||
UCHAR XarLen;
|
||||
UCHAR FileLoc[4];
|
||||
UCHAR FileLocMot[4];
|
||||
UCHAR DataLen[4];
|
||||
UCHAR DataLenMot[4];
|
||||
UCHAR RecordTime[6];
|
||||
UCHAR FlagsHSG;
|
||||
UCHAR FlagsISO;
|
||||
UCHAR IntLeaveSize;
|
||||
UCHAR IntLeaveSkip;
|
||||
UCHAR Vssn[2];
|
||||
UCHAR VssnMot[2];
|
||||
UCHAR FileIdLen;
|
||||
UCHAR FileId[MAX_FILE_ID_LENGTH];
|
||||
|
||||
} RAW_DIRENT;
|
||||
typedef RAW_DIRENT RAW_DIR_REC;
|
||||
typedef RAW_DIRENT *PRAW_DIR_REC;
|
||||
typedef RAW_DIRENT *PRAW_DIRENT;
|
||||
|
||||
#define CD_ATTRIBUTE_HIDDEN (0x01)
|
||||
#define CD_ATTRIBUTE_DIRECTORY (0x02)
|
||||
#define CD_ATTRIBUTE_ASSOC (0x04)
|
||||
#define CD_ATTRIBUTE_MULTI (0x80)
|
||||
|
||||
#define CD_BASE_YEAR (1900)
|
||||
|
||||
#define MIN_RAW_DIRENT_LEN (FIELD_OFFSET( RAW_DIRENT, FileId ) + 1)
|
||||
|
||||
#define BYTE_COUNT_8_DOT_3 (24)
|
||||
|
||||
#define SHORT_NAME_SHIFT (5)
|
||||
|
||||
//
|
||||
// The following macro recovers the correct flag field.
|
||||
//
|
||||
|
||||
#define CdRawDirentFlags(IC,RD) ( \
|
||||
FlagOn( (IC)->Vcb->VcbState, VCB_STATE_HSG) ? \
|
||||
(RD)->FlagsHSG : \
|
||||
(RD)->FlagsISO \
|
||||
)
|
||||
|
||||
//
|
||||
// The following macro converts from CD time to NT time. On ISO
|
||||
// 9660 media, we now pay attention to the GMT offset (integer
|
||||
// increments of 15 minutes offset from GMT). HSG does not record
|
||||
// this field.
|
||||
//
|
||||
// The restriction to the interval [-48, 52] comes from 9660 8.4.26.1
|
||||
//
|
||||
// VOID
|
||||
// CdConvertCdTimeToNtTime (
|
||||
// IN PIRP_CONTEXT IrpContext,
|
||||
// IN PCHAR CdTime,
|
||||
// OUT PLARGE_INTEGER NtTime
|
||||
// );
|
||||
//
|
||||
|
||||
#define GMT_OFFSET_TO_NT ((LONGLONG) 15 * 60 * 1000 * 1000 * 10)
|
||||
|
||||
#define CdConvertCdTimeToNtTime(IC,CD,NT) { \
|
||||
TIME_FIELDS _TimeField; \
|
||||
CHAR GmtOffset; \
|
||||
_TimeField.Year = (CSHORT) *((PCHAR) CD) + CD_BASE_YEAR; \
|
||||
_TimeField.Month = (CSHORT) *(Add2Ptr( CD, 1, PCHAR )); \
|
||||
_TimeField .Day = (CSHORT) *(Add2Ptr( CD, 2, PCHAR )); \
|
||||
_TimeField.Hour = (CSHORT) *(Add2Ptr( CD, 3, PCHAR )); \
|
||||
_TimeField.Minute = (CSHORT) *(Add2Ptr( CD, 4, PCHAR )); \
|
||||
_TimeField.Second = (CSHORT) *(Add2Ptr( CD, 5, PCHAR )); \
|
||||
_TimeField.Milliseconds = (CSHORT) 0; \
|
||||
RtlTimeFieldsToTime( &_TimeField, NT ); \
|
||||
if (!FlagOn((IC)->Vcb->VcbState, VCB_STATE_HSG) && \
|
||||
((GmtOffset = *(Add2Ptr( CD, 6, PCHAR ))) != 0 ) && \
|
||||
(GmtOffset >= -48 && GmtOffset <= 52)) { \
|
||||
(NT)->QuadPart += -GmtOffset * GMT_OFFSET_TO_NT; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// The on-disk representation of a Path Table entry differs between
|
||||
// the ISO version and the HSG version. The fields are the same
|
||||
// and the same size, but the positions are different.
|
||||
//
|
||||
|
||||
typedef struct _RAW_PATH_ISO {
|
||||
|
||||
UCHAR DirIdLen;
|
||||
UCHAR XarLen;
|
||||
USHORT DirLoc[2];
|
||||
USHORT ParentNum;
|
||||
UCHAR DirId[MAX_FILE_ID_LENGTH];
|
||||
|
||||
} RAW_PATH_ISO;
|
||||
typedef RAW_PATH_ISO *PRAW_PATH_ISO;
|
||||
typedef RAW_PATH_ISO RAW_PATH_ENTRY;
|
||||
typedef RAW_PATH_ISO *PRAW_PATH_ENTRY;
|
||||
|
||||
typedef struct _RAW_PATH_HSG {
|
||||
|
||||
USHORT DirLoc[2];
|
||||
UCHAR XarLen;
|
||||
UCHAR DirIdLen;
|
||||
USHORT ParentNum;
|
||||
UCHAR DirId[MAX_FILE_ID_LENGTH];
|
||||
|
||||
} RAW_PATH_HSG;
|
||||
typedef RAW_PATH_HSG *PRAW_PATH_HSG;
|
||||
|
||||
#define MIN_RAW_PATH_ENTRY_LEN (FIELD_OFFSET( RAW_PATH_ENTRY, DirId ) + 1)
|
||||
|
||||
//
|
||||
// The following macros are used to recover the different fields of the
|
||||
// Path Table entries. The macro to recover the disk location of the
|
||||
// directory must copy it into a different variable for alignment reasons.
|
||||
//
|
||||
// CdRawPathIdLen - Length of directory name in bytes
|
||||
// CdRawPathXar - Number of Xar blocks
|
||||
// CdRawPathLoc - Address of unaligned ulong for disk offset in blocks
|
||||
//
|
||||
|
||||
#define CdRawPathIdLen(IC, RP) ( \
|
||||
FlagOn( (IC)->Vcb->VcbState, VCB_STATE_HSG ) ? \
|
||||
((PRAW_PATH_HSG) (RP))->DirIdLen : \
|
||||
(RP)->DirIdLen \
|
||||
)
|
||||
|
||||
#define CdRawPathXar(IC, RP) ( \
|
||||
FlagOn( (IC)->Vcb->VcbState, VCB_STATE_HSG ) ? \
|
||||
((PRAW_PATH_HSG) (RP))->XarLen : \
|
||||
(RP)->XarLen \
|
||||
)
|
||||
|
||||
#define CdRawPathLoc(IC, RP) ( \
|
||||
FlagOn( (IC)->Vcb->VcbState, VCB_STATE_HSG ) ? \
|
||||
((PRAW_PATH_HSG) (RP))->DirLoc : \
|
||||
(RP)->DirLoc \
|
||||
)
|
||||
|
||||
|
||||
//
|
||||
// System use are for XA data. The following is the system use area for
|
||||
// directory entries on XA data disks.
|
||||
//
|
||||
|
||||
typedef struct _SYSTEM_USE_XA {
|
||||
|
||||
//
|
||||
// Owner ID. Not used in this version.
|
||||
//
|
||||
|
||||
UCHAR OwnerId[4];
|
||||
|
||||
//
|
||||
// Extent attributes. Only interested if mode2 form2 or digital audio.
|
||||
// This is stored big endian. We will define the attribute flags so
|
||||
// we can ignore this fact.
|
||||
//
|
||||
|
||||
USHORT Attributes;
|
||||
|
||||
//
|
||||
// XA signature. This value must be 'XA'.
|
||||
//
|
||||
|
||||
USHORT Signature;
|
||||
|
||||
//
|
||||
// File Number.
|
||||
//
|
||||
|
||||
UCHAR FileNumber;
|
||||
|
||||
//
|
||||
// Not used in this version.
|
||||
//
|
||||
|
||||
UCHAR Reserved[5];
|
||||
|
||||
} SYSTEM_USE_XA;
|
||||
typedef SYSTEM_USE_XA *PSYSTEM_USE_XA;
|
||||
|
||||
#define SYSTEM_USE_XA_FORM1 (0x0008)
|
||||
#define SYSTEM_USE_XA_FORM2 (0x0010)
|
||||
#define SYSTEM_USE_XA_DA (0x0040)
|
||||
|
||||
#define SYSTEM_XA_SIGNATURE (0x4158)
|
||||
|
||||
typedef enum _XA_EXTENT_TYPE {
|
||||
|
||||
Form1Data = 0,
|
||||
Mode2Form2Data,
|
||||
CDAudio
|
||||
|
||||
} XA_EXTENT_TYPE;
|
||||
typedef XA_EXTENT_TYPE *PXA_EXTENT_TYPE;
|
||||
|
||||
#endif // _CDFS_
|
||||
|
||||
|
||||
|
||||
+1151
File diff suppressed because it is too large
Load Diff
+278
@@ -0,0 +1,278 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
CdData.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module declares the global data used by the Cdfs file system.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _CDDATA_
|
||||
#define _CDDATA_
|
||||
|
||||
//
|
||||
// Global data structures
|
||||
//
|
||||
|
||||
extern CD_DATA CdData;
|
||||
extern FAST_IO_DISPATCH CdFastIoDispatch;
|
||||
|
||||
//
|
||||
// Global constants
|
||||
//
|
||||
|
||||
//
|
||||
// This is the number of times a mounted Vcb will be referenced on behalf
|
||||
// of the system. The counts include the following references.
|
||||
//
|
||||
// 1 reference - shows the volume is mounted
|
||||
// 1 reference - 1 for VolumeDasdFcb.
|
||||
// 2 references - 1 for RootIndexFcb, 1 for internal stream.
|
||||
// 2 references - 1 for PathTableFcb, 1 for internal stream.
|
||||
//
|
||||
// For user references we add one for the reference in each of the internal
|
||||
// Fcb's.
|
||||
//
|
||||
|
||||
#define CDFS_RESIDUAL_REFERENCE (6)
|
||||
#define CDFS_RESIDUAL_USER_REFERENCE (3)
|
||||
|
||||
//
|
||||
// Reserved directory strings
|
||||
//
|
||||
|
||||
extern WCHAR CdUnicodeSelfArray[];
|
||||
extern WCHAR CdUnicodeParentArray[];
|
||||
|
||||
extern UNICODE_STRING CdUnicodeDirectoryNames[];
|
||||
|
||||
//
|
||||
// Volume descriptor identifier strings.
|
||||
//
|
||||
|
||||
extern CHAR CdHsgId[];
|
||||
extern CHAR CdIsoId[];
|
||||
extern CHAR CdXaId[];
|
||||
|
||||
//
|
||||
// Volume label for audio disks.
|
||||
//
|
||||
|
||||
extern WCHAR CdAudioLabel[];
|
||||
extern USHORT CdAudioLabelLength;
|
||||
|
||||
//
|
||||
// Pseudo file names for audio disks.
|
||||
//
|
||||
|
||||
extern CHAR CdAudioFileName[];
|
||||
extern UCHAR CdAudioFileNameLength;
|
||||
extern ULONG CdAudioDirentSize;
|
||||
extern ULONG CdAudioDirentsPerSector;
|
||||
extern ULONG CdAudioSystemUseOffset;
|
||||
|
||||
#define AUDIO_NAME_ONES_OFFSET (6)
|
||||
#define AUDIO_NAME_TENS_OFFSET (5)
|
||||
|
||||
//
|
||||
// Escape sequences for mounting Unicode volumes.
|
||||
//
|
||||
|
||||
extern PCHAR CdJolietEscape[];
|
||||
|
||||
//
|
||||
// Hardcoded header for RIFF files.
|
||||
//
|
||||
|
||||
extern LONG CdXAFileHeader[];
|
||||
extern LONG CdAudioPlayHeader[];
|
||||
extern LONG CdXAAudioPhileHeader[];
|
||||
|
||||
|
||||
//
|
||||
// Turn on pseudo-asserts if CD_FREE_ASSERTS is defined.
|
||||
//
|
||||
|
||||
#if !DBG
|
||||
#ifdef CD_FREE_ASSERTS
|
||||
#undef ASSERT
|
||||
#undef ASSERTMSG
|
||||
#define ASSERT(exp) if (!(exp)) { extern BOOLEAN KdDebuggerEnabled; DbgPrint("%s:%d %s\n",__FILE__,__LINE__,#exp); if (KdDebuggerEnabled) { DbgBreakPoint(); } }
|
||||
#define ASSERTMSG(msg,exp) if (!(exp)) { extern BOOLEAN KdDebuggerEnabled; DbgPrint("%s:%d %s %s\n",__FILE__,__LINE__,msg,#exp); if (KdDebuggerEnabled) { DbgBreakPoint(); } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// The following assertion macros ensure that the indicated structure
|
||||
// is valid
|
||||
//
|
||||
// ASSERT_STRUCT( IN PVOID Struct, IN CSHORT NodeType );
|
||||
// ASSERT_OPTIONAL_STRUCT( IN PVOID Struct OPTIONAL, IN CSHORT NodeType );
|
||||
//
|
||||
// ASSERT_VCB( IN PVCB Vcb );
|
||||
// ASSERT_OPTIONAL_VCB( IN PVCB Vcb OPTIONAL );
|
||||
//
|
||||
// ASSERT_FCB( IN PFCB Fcb );
|
||||
// ASSERT_OPTIONAL_FCB( IN PFCB Fcb OPTIONAL );
|
||||
//
|
||||
// ASSERT_FCB_NONPAGED( IN PFCB_NONPAGED FcbNonpaged );
|
||||
// ASSERT_OPTIONAL_FCB( IN PFCB_NONPAGED FcbNonpaged OPTIONAL );
|
||||
//
|
||||
// ASSERT_CCB( IN PSCB Ccb );
|
||||
// ASSERT_OPTIONAL_CCB( IN PSCB Ccb OPTIONAL );
|
||||
//
|
||||
// ASSERT_IRP_CONTEXT( IN PIRP_CONTEXT IrpContext );
|
||||
// ASSERT_OPTIONAL_IRP_CONTEXT( IN PIRP_CONTEXT IrpContext OPTIONAL );
|
||||
//
|
||||
// ASSERT_IRP( IN PIRP Irp );
|
||||
// ASSERT_OPTIONAL_IRP( IN PIRP Irp OPTIONAL );
|
||||
//
|
||||
// ASSERT_FILE_OBJECT( IN PFILE_OBJECT FileObject );
|
||||
// ASSERT_OPTIONAL_FILE_OBJECT( IN PFILE_OBJECT FileObject OPTIONAL );
|
||||
//
|
||||
// The following macros are used to check the current thread owns
|
||||
// the indicated resource
|
||||
//
|
||||
// ASSERT_EXCLUSIVE_RESOURCE( IN PERESOURCE Resource );
|
||||
//
|
||||
// ASSERT_SHARED_RESOURCE( IN PERESOURCE Resource );
|
||||
//
|
||||
// ASSERT_RESOURCE_NOT_MINE( IN PERESOURCE Resource );
|
||||
//
|
||||
// The following macros are used to check whether the current thread
|
||||
// owns the resoures in the given structures.
|
||||
//
|
||||
// ASSERT_EXCLUSIVE_CDDATA
|
||||
//
|
||||
// ASSERT_EXCLUSIVE_VCB( IN PVCB Vcb );
|
||||
//
|
||||
// ASSERT_SHARED_VCB( IN PVCB Vcb );
|
||||
//
|
||||
// ASSERT_EXCLUSIVE_FCB( IN PFCB Fcb );
|
||||
//
|
||||
// ASSERT_SHARED_FCB( IN PFCB Fcb );
|
||||
//
|
||||
// ASSERT_EXCLUSIVE_FILE( IN PFCB Fcb );
|
||||
//
|
||||
// ASSERT_SHARED_FILE( IN PFCB Fcb );
|
||||
//
|
||||
// ASSERT_LOCKED_VCB( IN PVCB Vcb );
|
||||
//
|
||||
// ASSERT_NOT_LOCKED_VCB( IN PVCB Vcb );
|
||||
//
|
||||
// ASSERT_LOCKED_FCB( IN PFCB Fcb );
|
||||
//
|
||||
// ASSERT_NOT_LOCKED_FCB( IN PFCB Fcb );
|
||||
//
|
||||
|
||||
//
|
||||
// Turn on the sanity checks if this is DBG or CD_FREE_ASSERTS
|
||||
//
|
||||
|
||||
#if DBG
|
||||
#undef CD_SANITY
|
||||
#define CD_SANITY
|
||||
#endif
|
||||
|
||||
#ifdef CD_SANITY
|
||||
|
||||
#define ASSERT_STRUCT(S,T) ASSERT( SafeNodeType( S ) == (T) )
|
||||
#define ASSERT_OPTIONAL_STRUCT(S,T) ASSERT( ((S) == NULL) || (SafeNodeType( S ) == (T)) )
|
||||
|
||||
#define ASSERT_VCB(V) ASSERT_STRUCT( (V), CDFS_NTC_VCB )
|
||||
#define ASSERT_OPTIONAL_VCB(V) ASSERT_OPTIONAL_STRUCT( (V), CDFS_NTC_VCB )
|
||||
|
||||
#define ASSERT_FCB(F) \
|
||||
ASSERT( (SafeNodeType( F ) == CDFS_NTC_FCB_DATA ) || \
|
||||
(SafeNodeType( F ) == CDFS_NTC_FCB_INDEX ) || \
|
||||
(SafeNodeType( F ) == CDFS_NTC_FCB_PATH_TABLE ) )
|
||||
|
||||
#define ASSERT_OPTIONAL_FCB(F) \
|
||||
ASSERT( ((F) == NULL) || \
|
||||
(SafeNodeType( F ) == CDFS_NTC_FCB_DATA ) || \
|
||||
(SafeNodeType( F ) == CDFS_NTC_FCB_INDEX ) || \
|
||||
(SafeNodeType( F ) == CDFS_NTC_FCB_PATH_TABLE ) )
|
||||
|
||||
#define ASSERT_FCB_NONPAGED(FN) ASSERT_STRUCT( (FN), CDFS_NTC_FCB_NONPAGED )
|
||||
#define ASSERT_OPTIONAL_FCB_NONPAGED(FN) ASSERT_OPTIONAL_STRUCT( (FN), CDFS_NTC_FCB_NONPAGED )
|
||||
|
||||
#define ASSERT_CCB(C) ASSERT_STRUCT( (C), CDFS_NTC_CCB )
|
||||
#define ASSERT_OPTIONAL_CCB(C) ASSERT_OPTIONAL_STRUCT( (C), CDFS_NTC_CCB )
|
||||
|
||||
#define ASSERT_IRP_CONTEXT(IC) ASSERT_STRUCT( (IC), CDFS_NTC_IRP_CONTEXT )
|
||||
#define ASSERT_OPTIONAL_IRP_CONTEXT(IC) ASSERT_OPTIONAL_STRUCT( (IC), CDFS_NTC_IRP_CONTEXT )
|
||||
|
||||
#define ASSERT_IRP(I) ASSERT_STRUCT( (I), IO_TYPE_IRP )
|
||||
#define ASSERT_OPTIONAL_IRP(I) ASSERT_OPTIONAL_STRUCT( (I), IO_TYPE_IRP )
|
||||
|
||||
#define ASSERT_FILE_OBJECT(FO) ASSERT_STRUCT( (FO), IO_TYPE_FILE )
|
||||
#define ASSERT_OPTIONAL_FILE_OBJECT(FO) ASSERT_OPTIONAL_STRUCT( (FO), IO_TYPE_FILE )
|
||||
|
||||
#define ASSERT_EXCLUSIVE_RESOURCE(R) ASSERT( ExIsResourceAcquiredExclusiveLite( R ))
|
||||
|
||||
#define ASSERT_SHARED_RESOURCE(R) ASSERT( ExIsResourceAcquiredSharedLite( R ))
|
||||
|
||||
#define ASSERT_RESOURCE_NOT_MINE(R) ASSERT( !ExIsResourceAcquiredSharedLite( R ))
|
||||
|
||||
#define ASSERT_EXCLUSIVE_CDDATA ASSERT( ExIsResourceAcquiredExclusiveLite( &CdData.DataResource ))
|
||||
#define ASSERT_EXCLUSIVE_VCB(V) ASSERT( ExIsResourceAcquiredExclusiveLite( &(V)->VcbResource ))
|
||||
#define ASSERT_SHARED_VCB(V) ASSERT( ExIsResourceAcquiredSharedLite( &(V)->VcbResource ))
|
||||
|
||||
#define ASSERT_EXCLUSIVE_FCB(F) ASSERT( ExIsResourceAcquiredExclusiveLite( &(F)->FcbNonpaged->FcbResource ))
|
||||
#define ASSERT_SHARED_FCB(F) ASSERT( ExIsResourceAcquiredSharedLite( &(F)->FcbNonpaged->FcbResource ))
|
||||
|
||||
#define ASSERT_EXCLUSIVE_FILE(F) ASSERT( ExIsResourceAcquiredExclusiveLite( (F)->Resource ))
|
||||
#define ASSERT_SHARED_FILE(F) ASSERT( ExIsResourceAcquiredSharedLite( (F)->Resource ))
|
||||
|
||||
#define ASSERT_LOCKED_VCB(V) ASSERT( (V)->VcbLockThread == PsGetCurrentThread() )
|
||||
#define ASSERT_NOT_LOCKED_VCB(V) ASSERT( (V)->VcbLockThread != PsGetCurrentThread() )
|
||||
|
||||
#define ASSERT_LOCKED_FCB(F) ASSERT( !FlagOn( (F)->FcbState, FCB_STATE_IN_FCB_TABLE) || ((F)->FcbLockThread == PsGetCurrentThread()))
|
||||
#define ASSERT_NOT_LOCKED_FCB(F) ASSERT( (F)->FcbLockThread != PsGetCurrentThread() )
|
||||
|
||||
#else
|
||||
|
||||
#define DebugBreakOnStatus(S) { NOTHING; }
|
||||
|
||||
#define ASSERT_STRUCT(S,T) { NOTHING; }
|
||||
#define ASSERT_OPTIONAL_STRUCT(S,T) { NOTHING; }
|
||||
#define ASSERT_VCB(V) { NOTHING; }
|
||||
#define ASSERT_OPTIONAL_VCB(V) { NOTHING; }
|
||||
#define ASSERT_FCB(F) { NOTHING; }
|
||||
#define ASSERT_OPTIONAL_FCB(F) { NOTHING; }
|
||||
#define ASSERT_FCB_NONPAGED(FN) { NOTHING; }
|
||||
#define ASSERT_OPTIONAL_FCB(FN) { NOTHING; }
|
||||
#define ASSERT_CCB(C) { NOTHING; }
|
||||
#define ASSERT_OPTIONAL_CCB(C) { NOTHING; }
|
||||
#define ASSERT_IRP_CONTEXT(IC) { NOTHING; }
|
||||
#define ASSERT_OPTIONAL_IRP_CONTEXT(IC) { NOTHING; }
|
||||
#define ASSERT_IRP(I) { NOTHING; }
|
||||
#define ASSERT_OPTIONAL_IRP(I) { NOTHING; }
|
||||
#define ASSERT_FILE_OBJECT(FO) { NOTHING; }
|
||||
#define ASSERT_OPTIONAL_FILE_OBJECT(FO) { NOTHING; }
|
||||
#define ASSERT_EXCLUSIVE_RESOURCE(R) { NOTHING; }
|
||||
#define ASSERT_SHARED_RESOURCE(R) { NOTHING; }
|
||||
#define ASSERT_RESOURCE_NOT_MINE(R) { NOTHING; }
|
||||
#define ASSERT_EXCLUSIVE_CDDATA { NOTHING; }
|
||||
#define ASSERT_EXCLUSIVE_VCB(V) { NOTHING; }
|
||||
#define ASSERT_SHARED_VCB(V) { NOTHING; }
|
||||
#define ASSERT_EXCLUSIVE_FCB(F) { NOTHING; }
|
||||
#define ASSERT_SHARED_FCB(F) { NOTHING; }
|
||||
#define ASSERT_EXCLUSIVE_FILE(F) { NOTHING; }
|
||||
#define ASSERT_SHARED_FILE(F) { NOTHING; }
|
||||
#define ASSERT_LOCKED_VCB(V) { NOTHING; }
|
||||
#define ASSERT_NOT_LOCKED_VCB(V) { NOTHING; }
|
||||
#define ASSERT_LOCKED_FCB(F) { NOTHING; }
|
||||
#define ASSERT_NOT_LOCKED_FCB(F) { NOTHING; }
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _CDDATA_
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
|
||||
<module name="cdfs_new" type="kernelmodedriver" installbase="system32/drivers" installname="cdfs_new.sys">
|
||||
<bootstrap installbase="$(CDOUTPUT)" />
|
||||
<include base="cdfs_new">.</include>
|
||||
<library>ntoskrnl</library>
|
||||
<library>hal</library>
|
||||
<file>allocsup.c</file>
|
||||
<file>cachesup.c</file>
|
||||
<file>cddata.c</file>
|
||||
<file>cdinit.c</file>
|
||||
<file>cleanup.c</file>
|
||||
<file>close.c</file>
|
||||
<file>create.c</file>
|
||||
<file>devctrl.c</file>
|
||||
<file>deviosup.c</file>
|
||||
<file>dirctrl.c</file>
|
||||
<file>dirsup.c</file>
|
||||
<file>fileinfo.c</file>
|
||||
<file>filobsup.c</file>
|
||||
<file>fsctrl.c</file>
|
||||
<file>fspdisp.c</file>
|
||||
<file>lockctrl.c</file>
|
||||
<file>namesup.c</file>
|
||||
<file>pathsup.c</file>
|
||||
<file>pnp.c</file>
|
||||
<file>prefxsup.c</file>
|
||||
<file>read.c</file>
|
||||
<file>resrcsup.c</file>
|
||||
<file>strucsup.c</file>
|
||||
<file>verfysup.c</file>
|
||||
<file>volinfo.c</file>
|
||||
<file>workque.c</file>
|
||||
<file>cdfs.rc</file>
|
||||
<compilerflag>-fms-extensions</compilerflag>
|
||||
<pch>cdprocs.h</pch>
|
||||
</module>
|
||||
@@ -0,0 +1,7 @@
|
||||
/* $Id: cdfs.rc 21710 2006-04-22 16:36:21Z tretiakov $ */
|
||||
|
||||
#define REACTOS_VERSION_DLL
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "ISO9660 Driver\0"
|
||||
#define REACTOS_STR_INTERNAL_NAME "cdfs\0"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "cdfs.sys\0"
|
||||
#include <reactos/version.rc>
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
CdInit.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the DRIVER_INITIALIZATION routine for Cdfs
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_CDINIT)
|
||||
|
||||
NTSTATUS
|
||||
DriverEntry(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PUNICODE_STRING RegistryPath
|
||||
);
|
||||
|
||||
VOID
|
||||
CdUnload(
|
||||
IN PDRIVER_OBJECT DriverObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdInitializeGlobalData (
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PDEVICE_OBJECT FileSystemDeviceObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdShutdown (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(INIT, DriverEntry)
|
||||
#pragma alloc_text(PAGE, CdUnload)
|
||||
#pragma alloc_text(PAGE, CdShutdown)
|
||||
#pragma alloc_text(INIT, CdInitializeGlobalData)
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
DriverEntry(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PUNICODE_STRING RegistryPath
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the initialization routine for the Cdrom file system
|
||||
device driver. This routine creates the device object for the FileSystem
|
||||
device and performs all other driver initialization.
|
||||
|
||||
Arguments:
|
||||
|
||||
DriverObject - Pointer to driver object created by the system.
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The function value is the final status from the initialization
|
||||
operation.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING UnicodeString;
|
||||
PDEVICE_OBJECT CdfsFileSystemDeviceObject;
|
||||
|
||||
//
|
||||
// Create the device object.
|
||||
//
|
||||
|
||||
RtlInitUnicodeString( &UnicodeString, L"\\Cdfs" );
|
||||
|
||||
Status = IoCreateDevice( DriverObject,
|
||||
0,
|
||||
&UnicodeString,
|
||||
FILE_DEVICE_CD_ROM_FILE_SYSTEM,
|
||||
0,
|
||||
FALSE,
|
||||
&CdfsFileSystemDeviceObject );
|
||||
|
||||
if (!NT_SUCCESS( Status )) {
|
||||
return Status;
|
||||
}
|
||||
DriverObject->DriverUnload = CdUnload;
|
||||
//
|
||||
// Note that because of the way data caching is done, we set neither
|
||||
// the Direct I/O or Buffered I/O bit in DeviceObject->Flags. If
|
||||
// data is not in the cache, or the request is not buffered, we may,
|
||||
// set up for Direct I/O by hand.
|
||||
//
|
||||
|
||||
//
|
||||
// Initialize the driver object with this driver's entry points.
|
||||
//
|
||||
// NOTE - Each entry in the dispatch table must have an entry in
|
||||
// the Fsp/Fsd dispatch switch statements.
|
||||
//
|
||||
|
||||
DriverObject->MajorFunction[IRP_MJ_CREATE] =
|
||||
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
|
||||
DriverObject->MajorFunction[IRP_MJ_READ] =
|
||||
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
|
||||
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
|
||||
DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION]=
|
||||
DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
|
||||
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
|
||||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
|
||||
DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] =
|
||||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
|
||||
DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH) CdFsdDispatch;
|
||||
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = CdShutdown;
|
||||
|
||||
DriverObject->FastIoDispatch = &CdFastIoDispatch;
|
||||
|
||||
Status = IoRegisterShutdownNotification (CdfsFileSystemDeviceObject);
|
||||
if (!NT_SUCCESS (Status)) {
|
||||
IoDeleteDevice (CdfsFileSystemDeviceObject);
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the global data structures
|
||||
//
|
||||
|
||||
Status = CdInitializeGlobalData( DriverObject, CdfsFileSystemDeviceObject );
|
||||
if (!NT_SUCCESS (Status)) {
|
||||
IoDeleteDevice (CdfsFileSystemDeviceObject);
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Register the file system as low priority with the I/O system. This will cause
|
||||
// CDFS to receive mount requests after a) other filesystems currently registered
|
||||
// and b) other normal priority filesystems that may be registered later.
|
||||
//
|
||||
|
||||
CdfsFileSystemDeviceObject->Flags |= DO_LOW_PRIORITY_FILESYSTEM;
|
||||
|
||||
IoRegisterFileSystem( CdfsFileSystemDeviceObject );
|
||||
ObReferenceObject (CdfsFileSystemDeviceObject);
|
||||
|
||||
//
|
||||
// And return to our caller
|
||||
//
|
||||
|
||||
return( STATUS_SUCCESS );
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
CdShutdown (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is the shutdown handler for CDFS.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - Supplies the registered device object for CDFS.
|
||||
Irp - Shutdown IRP
|
||||
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
IoUnregisterFileSystem (DeviceObject);
|
||||
IoDeleteDevice (CdData.FileSystemDeviceObject);
|
||||
|
||||
CdCompleteRequest( NULL, Irp, STATUS_SUCCESS );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdUnload(
|
||||
IN PDRIVER_OBJECT DriverObject
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine unload routine for CDFS.
|
||||
|
||||
Arguments:
|
||||
|
||||
DriverObject - Supplies the driver object for CDFS.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
PIRP_CONTEXT IrpContext;
|
||||
|
||||
//
|
||||
// Free any IRP contexts
|
||||
//
|
||||
while (1) {
|
||||
IrpContext = (PIRP_CONTEXT) PopEntryList( &CdData.IrpContextList) ;
|
||||
if (IrpContext == NULL) {
|
||||
break;
|
||||
}
|
||||
CdFreePool(&IrpContext);
|
||||
}
|
||||
|
||||
IoFreeWorkItem (CdData.CloseItem);
|
||||
ExDeleteResourceLite( &CdData.DataResource );
|
||||
ObDereferenceObject (CdData.FileSystemDeviceObject);
|
||||
}
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
CdInitializeGlobalData (
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PDEVICE_OBJECT FileSystemDeviceObject
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine initializes the global cdfs data structures.
|
||||
|
||||
Arguments:
|
||||
|
||||
DriverObject - Supplies the driver object for CDFS.
|
||||
|
||||
FileSystemDeviceObject - Supplies the device object for CDFS.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
//
|
||||
// Start by initializing the FastIoDispatch Table.
|
||||
//
|
||||
|
||||
RtlZeroMemory( &CdFastIoDispatch, sizeof( FAST_IO_DISPATCH ));
|
||||
|
||||
CdFastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
|
||||
CdFastIoDispatch.FastIoCheckIfPossible = CdFastIoCheckIfPossible; // CheckForFastIo
|
||||
CdFastIoDispatch.FastIoRead = FsRtlCopyRead; // Read
|
||||
CdFastIoDispatch.FastIoQueryBasicInfo = CdFastQueryBasicInfo; // QueryBasicInfo
|
||||
CdFastIoDispatch.FastIoQueryStandardInfo = CdFastQueryStdInfo; // QueryStandardInfo
|
||||
CdFastIoDispatch.FastIoLock = CdFastLock; // Lock
|
||||
CdFastIoDispatch.FastIoUnlockSingle = CdFastUnlockSingle; // UnlockSingle
|
||||
CdFastIoDispatch.FastIoUnlockAll = CdFastUnlockAll; // UnlockAll
|
||||
CdFastIoDispatch.FastIoUnlockAllByKey = CdFastUnlockAllByKey; // UnlockAllByKey
|
||||
CdFastIoDispatch.AcquireFileForNtCreateSection = CdAcquireForCreateSection;
|
||||
CdFastIoDispatch.ReleaseFileForNtCreateSection = CdReleaseForCreateSection;
|
||||
CdFastIoDispatch.FastIoQueryNetworkOpenInfo = CdFastQueryNetworkInfo; // QueryNetworkInfo
|
||||
|
||||
CdFastIoDispatch.MdlRead = FsRtlMdlReadDev;
|
||||
CdFastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev;
|
||||
CdFastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev;
|
||||
CdFastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev;
|
||||
|
||||
//
|
||||
// Initialize the CdData structure.
|
||||
//
|
||||
|
||||
RtlZeroMemory( &CdData, sizeof( CD_DATA ));
|
||||
|
||||
CdData.NodeTypeCode = CDFS_NTC_DATA_HEADER;
|
||||
CdData.NodeByteSize = sizeof( CD_DATA );
|
||||
|
||||
CdData.DriverObject = DriverObject;
|
||||
CdData.FileSystemDeviceObject = FileSystemDeviceObject;
|
||||
|
||||
InitializeListHead( &CdData.VcbQueue );
|
||||
|
||||
ExInitializeResourceLite( &CdData.DataResource );
|
||||
|
||||
//
|
||||
// Initialize the cache manager callback routines
|
||||
//
|
||||
|
||||
CdData.CacheManagerCallbacks.AcquireForLazyWrite = &CdAcquireForCache;
|
||||
CdData.CacheManagerCallbacks.ReleaseFromLazyWrite = &CdReleaseFromCache;
|
||||
CdData.CacheManagerCallbacks.AcquireForReadAhead = &CdAcquireForCache;
|
||||
CdData.CacheManagerCallbacks.ReleaseFromReadAhead = &CdReleaseFromCache;
|
||||
|
||||
CdData.CacheManagerVolumeCallbacks.AcquireForLazyWrite = &CdNoopAcquire;
|
||||
CdData.CacheManagerVolumeCallbacks.ReleaseFromLazyWrite = &CdNoopRelease;
|
||||
CdData.CacheManagerVolumeCallbacks.AcquireForReadAhead = &CdNoopAcquire;
|
||||
CdData.CacheManagerVolumeCallbacks.ReleaseFromReadAhead = &CdNoopRelease;
|
||||
|
||||
//
|
||||
// Initialize the lock mutex and the async and delay close queues.
|
||||
//
|
||||
|
||||
ExInitializeFastMutex( &CdData.CdDataMutex );
|
||||
InitializeListHead( &CdData.AsyncCloseQueue );
|
||||
InitializeListHead( &CdData.DelayedCloseQueue );
|
||||
|
||||
CdData.CloseItem = IoAllocateWorkItem (FileSystemDeviceObject);
|
||||
if (CdData.CloseItem == NULL) {
|
||||
|
||||
ExDeleteResourceLite( &CdData.DataResource );
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
//
|
||||
// Do the initialization based on the system size.
|
||||
//
|
||||
|
||||
switch (MmQuerySystemSize()) {
|
||||
|
||||
case MmSmallSystem:
|
||||
|
||||
CdData.IrpContextMaxDepth = 4;
|
||||
CdData.MaxDelayedCloseCount = 8;
|
||||
CdData.MinDelayedCloseCount = 2;
|
||||
break;
|
||||
|
||||
case MmMediumSystem:
|
||||
|
||||
CdData.IrpContextMaxDepth = 8;
|
||||
CdData.MaxDelayedCloseCount = 24;
|
||||
CdData.MinDelayedCloseCount = 6;
|
||||
break;
|
||||
|
||||
case MmLargeSystem:
|
||||
|
||||
CdData.IrpContextMaxDepth = 32;
|
||||
CdData.MaxDelayedCloseCount = 72;
|
||||
CdData.MinDelayedCloseCount = 18;
|
||||
break;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
+1888
File diff suppressed because it is too large
Load Diff
+1763
File diff suppressed because it is too large
Load Diff
+332
@@ -0,0 +1,332 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
Cleanup.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the File Cleanup routine for Cdfs called by the
|
||||
dispatch driver.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_CLEANUP)
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdCommonCleanup (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the common routine for cleanup of a file/directory called by both
|
||||
the fsd and fsp threads.
|
||||
|
||||
Cleanup is invoked whenever the last handle to a file object is closed.
|
||||
This is different than the Close operation which is invoked when the last
|
||||
reference to a file object is deleted.
|
||||
|
||||
The function of cleanup is to essentially "cleanup" the file/directory
|
||||
after a user is done with it. The Fcb/Dcb remains around (because MM
|
||||
still has the file object referenced) but is now available for another
|
||||
user to open (i.e., as far as the user is concerned the is now closed).
|
||||
|
||||
See close for a more complete description of what close does.
|
||||
|
||||
We do no synchronization in this routine until we get to the point
|
||||
where we modify the counts, share access and volume lock field.
|
||||
|
||||
We need to update the Fcb and Vcb to show that a user handle has been closed.
|
||||
The following structures and fields are affected.
|
||||
|
||||
Vcb:
|
||||
|
||||
VolumeLockFileObject - Did the user lock the volume with this file object.
|
||||
VcbState - Check if we are unlocking the volume here.
|
||||
VcbCleanup - Count of outstanding handles on the volume.
|
||||
DirNotifyQueue - If this file object has pending DirNotify Irps.
|
||||
|
||||
Fcb:
|
||||
|
||||
ShareAccess - If this is a user handle.
|
||||
FcbCleanup - Count of outstanding handles on this Fcb.
|
||||
Oplock - Any outstanding oplocks on this file object.
|
||||
FileLock - Any outstanding filelocks on this file object.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Supplies the Irp to process
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The return status for the operation.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PFILE_OBJECT FileObject;
|
||||
TYPE_OF_OPEN TypeOfOpen;
|
||||
|
||||
BOOLEAN SendUnlockNotification = FALSE;
|
||||
BOOLEAN AttemptTeardown;
|
||||
BOOLEAN VcbAcquired = FALSE;
|
||||
|
||||
PVCB Vcb;
|
||||
PFCB Fcb;
|
||||
PCCB Ccb;
|
||||
|
||||
KIRQL SavedIrql;
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_IRP( Irp );
|
||||
|
||||
//
|
||||
// If we were called with our file system device object instead of a
|
||||
// volume device object, just complete this request with STATUS_SUCCESS.
|
||||
//
|
||||
|
||||
if (IrpContext->Vcb == NULL) {
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the file object out of the Irp and decode the type of open.
|
||||
//
|
||||
|
||||
FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject;
|
||||
|
||||
TypeOfOpen = CdDecodeFileObject( IrpContext,
|
||||
FileObject,
|
||||
&Fcb,
|
||||
&Ccb );
|
||||
|
||||
//
|
||||
// No work here for either an UnopenedFile object or a StreamFileObject.
|
||||
//
|
||||
|
||||
if (TypeOfOpen <= StreamFileOpen) {
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Keep a local pointer to the Vcb.
|
||||
//
|
||||
|
||||
Vcb = Fcb->Vcb;
|
||||
|
||||
//
|
||||
// Synchronise with reads while we set the cleanup complete
|
||||
// flag on this fileobject. Once this flag is set, any further
|
||||
// reads will be rejected (CdVerifyFcbOperation)
|
||||
//
|
||||
|
||||
CdAcquireFileExclusive( IrpContext, Fcb);
|
||||
|
||||
//
|
||||
// Set the flag in the FileObject to indicate that cleanup is complete.
|
||||
//
|
||||
|
||||
SetFlag( FileObject->Flags, FO_CLEANUP_COMPLETE );
|
||||
|
||||
CdReleaseFile( IrpContext, Fcb);
|
||||
|
||||
//
|
||||
// Acquire the current file.
|
||||
//
|
||||
|
||||
CdAcquireFcbExclusive( IrpContext, Fcb, FALSE );
|
||||
|
||||
//
|
||||
// Use a try-finally to facilitate cleanup.
|
||||
//
|
||||
|
||||
try {
|
||||
|
||||
//
|
||||
// Case on the type of open that we are trying to cleanup.
|
||||
//
|
||||
|
||||
switch (TypeOfOpen) {
|
||||
|
||||
case UserDirectoryOpen:
|
||||
|
||||
//
|
||||
// Check if we need to complete any dir notify Irps on this file object.
|
||||
//
|
||||
|
||||
FsRtlNotifyCleanup( Vcb->NotifySync,
|
||||
&Vcb->DirNotifyList,
|
||||
Ccb );
|
||||
|
||||
break;
|
||||
|
||||
case UserFileOpen:
|
||||
|
||||
//
|
||||
// Coordinate the cleanup operation with the oplock state.
|
||||
// Oplock cleanup operations can always cleanup immediately so no
|
||||
// need to check for STATUS_PENDING.
|
||||
//
|
||||
|
||||
FsRtlCheckOplock( &Fcb->Oplock,
|
||||
Irp,
|
||||
IrpContext,
|
||||
NULL,
|
||||
NULL );
|
||||
|
||||
//
|
||||
// Unlock all outstanding file locks.
|
||||
//
|
||||
|
||||
if (Fcb->FileLock != NULL) {
|
||||
|
||||
FsRtlFastUnlockAll( Fcb->FileLock,
|
||||
FileObject,
|
||||
IoGetRequestorProcess( Irp ),
|
||||
NULL );
|
||||
}
|
||||
|
||||
//
|
||||
// Cleanup the cache map.
|
||||
//
|
||||
|
||||
CcUninitializeCacheMap( FileObject, NULL, NULL );
|
||||
|
||||
//
|
||||
// Check the fast io state.
|
||||
//
|
||||
|
||||
CdLockFcb( IrpContext, Fcb );
|
||||
Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
|
||||
CdUnlockFcb( IrpContext, Fcb );
|
||||
|
||||
break;
|
||||
|
||||
case UserVolumeOpen :
|
||||
|
||||
break;
|
||||
|
||||
default :
|
||||
|
||||
CdBugCheck( TypeOfOpen, 0, 0 );
|
||||
}
|
||||
|
||||
//
|
||||
// Now lock the Vcb in order to modify the fields in the in-memory
|
||||
// structures.
|
||||
//
|
||||
|
||||
CdLockVcb( IrpContext, Vcb );
|
||||
|
||||
//
|
||||
// Decrement the cleanup counts in the Vcb and Fcb.
|
||||
//
|
||||
|
||||
CdDecrementCleanupCounts( IrpContext, Fcb );
|
||||
|
||||
//
|
||||
// If the cleanup count hit zero and the volume is not mounted, we
|
||||
// will want to try to spark teardown.
|
||||
//
|
||||
|
||||
AttemptTeardown = (Vcb->VcbCleanup == 0 && Vcb->VcbCondition == VcbNotMounted);
|
||||
|
||||
//
|
||||
// If this file object has locked the volume then perform the unlock operation.
|
||||
// We do this regardless of explicit or implicit (no share DASD open) lock.
|
||||
//
|
||||
|
||||
if (FileObject == Vcb->VolumeLockFileObject) {
|
||||
|
||||
ASSERT( FlagOn( Vcb->VcbState, VCB_STATE_LOCKED));
|
||||
|
||||
IoAcquireVpbSpinLock( &SavedIrql );
|
||||
|
||||
ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED);
|
||||
ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED );
|
||||
Vcb->VolumeLockFileObject = NULL;
|
||||
SendUnlockNotification = TRUE;
|
||||
|
||||
IoReleaseVpbSpinLock( SavedIrql );
|
||||
}
|
||||
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
|
||||
//
|
||||
// We must clean up the share access at this time, since we may not
|
||||
// get a Close call for awhile if the file was mapped through this
|
||||
// File Object.
|
||||
//
|
||||
|
||||
IoRemoveShareAccess( FileObject, &Fcb->ShareAccess );
|
||||
|
||||
} finally {
|
||||
|
||||
CdReleaseFcb( IrpContext, Fcb );
|
||||
|
||||
if (SendUnlockNotification) {
|
||||
|
||||
FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_UNLOCK );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If appropriate, try to spark teardown by purging the volume. Should
|
||||
// this very fileobject we were cleaning up be the last reason for the
|
||||
// volume to remain, teardown will commence on completion of this Irp.
|
||||
//
|
||||
|
||||
if (AttemptTeardown) {
|
||||
|
||||
//
|
||||
// Preacquire CdData here, since the purges will generate closes which
|
||||
// may acquire CdData if there is a possibility of tearing the volume
|
||||
// down.
|
||||
//
|
||||
|
||||
CdAcquireCdData( IrpContext);
|
||||
|
||||
try {
|
||||
|
||||
CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
|
||||
VcbAcquired = TRUE;
|
||||
|
||||
CdPurgeVolume( IrpContext, Vcb, FALSE );
|
||||
|
||||
} finally {
|
||||
|
||||
if (VcbAcquired) { CdReleaseVcb( IrpContext, Vcb ); }
|
||||
|
||||
CdReleaseCdData( IrpContext);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If this is a normal termination then complete the request
|
||||
//
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Executable
+1026
File diff suppressed because it is too large
Load Diff
+2916
File diff suppressed because it is too large
Load Diff
+196
@@ -0,0 +1,196 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
DevCtrl.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the File System Device Control routines for Cdfs
|
||||
called by the dispatch driver.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_DEVCTRL)
|
||||
|
||||
//
|
||||
// Local support routines
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
CdDevCtrlCompletionRoutine (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Contxt
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdCommonDevControl)
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdCommonDevControl (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Arguments:
|
||||
|
||||
Return Value:
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
TYPE_OF_OPEN TypeOfOpen;
|
||||
PFCB Fcb;
|
||||
PCCB Ccb;
|
||||
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
PIO_STACK_LOCATION NextIrpSp;
|
||||
|
||||
PVOID TargetBuffer = NULL;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Extract and decode the file object.
|
||||
//
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
TypeOfOpen = CdDecodeFileObject( IrpContext,
|
||||
IrpSp->FileObject,
|
||||
&Fcb,
|
||||
&Ccb );
|
||||
|
||||
//
|
||||
// The only type of opens we accept are user volume opens.
|
||||
//
|
||||
|
||||
if (TypeOfOpen != UserVolumeOpen) {
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) {
|
||||
|
||||
//
|
||||
// Verify the Vcb in this case to detect if the volume has changed.
|
||||
//
|
||||
|
||||
CdVerifyVcb( IrpContext, Fcb->Vcb );
|
||||
|
||||
//
|
||||
// Handle the case of the disk type ourselves.
|
||||
//
|
||||
|
||||
} else if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_DISK_TYPE) {
|
||||
|
||||
//
|
||||
// Verify the Vcb in this case to detect if the volume has changed.
|
||||
//
|
||||
|
||||
CdVerifyVcb( IrpContext, Fcb->Vcb );
|
||||
|
||||
//
|
||||
// Check the size of the output buffer.
|
||||
//
|
||||
|
||||
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof( CDROM_DISK_DATA )) {
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_BUFFER_TOO_SMALL );
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
//
|
||||
// Copy the data from the Vcb.
|
||||
//
|
||||
|
||||
((PCDROM_DISK_DATA) Irp->AssociatedIrp.SystemBuffer)->DiskData = Fcb->Vcb->DiskFlags;
|
||||
|
||||
Irp->IoStatus.Information = sizeof( CDROM_DISK_DATA );
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the next stack location, and copy over the stack parameter
|
||||
// information.
|
||||
//
|
||||
|
||||
NextIrpSp = IoGetNextIrpStackLocation( Irp );
|
||||
|
||||
*NextIrpSp = *IrpSp;
|
||||
|
||||
//
|
||||
// Set up the completion routine
|
||||
//
|
||||
|
||||
IoSetCompletionRoutine( Irp,
|
||||
CdDevCtrlCompletionRoutine,
|
||||
NULL,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
//
|
||||
// Send the request.
|
||||
//
|
||||
|
||||
Status = IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
|
||||
|
||||
//
|
||||
// Cleanup our Irp Context. The driver has completed the Irp.
|
||||
//
|
||||
|
||||
CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
CdDevCtrlCompletionRoutine (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Contxt
|
||||
)
|
||||
|
||||
{
|
||||
//
|
||||
// Add the hack-o-ramma to fix formats.
|
||||
//
|
||||
|
||||
if (Irp->PendingReturned) {
|
||||
|
||||
IoMarkIrpPending( Irp );
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
UNREFERENCED_PARAMETER( DeviceObject );
|
||||
UNREFERENCED_PARAMETER( Contxt );
|
||||
}
|
||||
|
||||
|
||||
+3603
File diff suppressed because it is too large
Load Diff
+1520
File diff suppressed because it is too large
Load Diff
+1863
File diff suppressed because it is too large
Load Diff
+478
@@ -0,0 +1,478 @@
|
||||
#include "CdProcs.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define doit(a,b) { printf("%s %04lx %4lx %s\n", #a, FIELD_OFFSET(a,b), sizeof(d.b), #b); }
|
||||
|
||||
VOID
|
||||
__cdecl
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
printf("<Record> <offset> <size> <field>\n\n");
|
||||
{
|
||||
CD_MCB d;
|
||||
doit( CD_MCB, MaximumEntryCount );
|
||||
doit( CD_MCB, CurrentEntryCount );
|
||||
doit( CD_MCB, McbArray );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
CD_MCB_ENTRY d;
|
||||
doit( CD_MCB_ENTRY, DiskOffset );
|
||||
doit( CD_MCB_ENTRY, ByteCount );
|
||||
doit( CD_MCB_ENTRY, FileOffset );
|
||||
doit( CD_MCB_ENTRY, DataBlockByteCount );
|
||||
doit( CD_MCB_ENTRY, TotalBlockByteCount );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
CD_NAME d;
|
||||
doit( CD_NAME, FileName );
|
||||
doit( CD_NAME, VersionString );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
NAME_LINK d;
|
||||
doit( NAME_LINK, Links );
|
||||
doit( NAME_LINK, FileName );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
PREFIX_ENTRY d;
|
||||
doit( PREFIX_ENTRY, Fcb );
|
||||
doit( PREFIX_ENTRY, PrefixFlags );
|
||||
doit( PREFIX_ENTRY, ExactCaseName );
|
||||
doit( PREFIX_ENTRY, IgnoreCaseName );
|
||||
doit( PREFIX_ENTRY, FileNameBuffer );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
CD_DATA d;
|
||||
doit( CD_DATA, NodeTypeCode );
|
||||
doit( CD_DATA, NodeByteSize );
|
||||
doit( CD_DATA, DriverObject );
|
||||
doit( CD_DATA, VcbQueue );
|
||||
doit( CD_DATA, IrpContextDepth );
|
||||
doit( CD_DATA, IrpContextMaxDepth );
|
||||
doit( CD_DATA, IrpContextList );
|
||||
doit( CD_DATA, FileSystemDeviceObject );
|
||||
doit( CD_DATA, AsyncCloseQueue );
|
||||
doit( CD_DATA, AsyncCloseCount );
|
||||
doit( CD_DATA, FspCloseActive );
|
||||
doit( CD_DATA, ReduceDelayedClose );
|
||||
doit( CD_DATA, PadUshort );
|
||||
doit( CD_DATA, DelayedCloseQueue );
|
||||
doit( CD_DATA, DelayedCloseCount );
|
||||
doit( CD_DATA, MinDelayedCloseCount );
|
||||
doit( CD_DATA, MaxDelayedCloseCount );
|
||||
doit( CD_DATA, CdDataLockThread );
|
||||
doit( CD_DATA, CdDataMutex );
|
||||
doit( CD_DATA, DataResource );
|
||||
doit( CD_DATA, CacheManagerCallbacks );
|
||||
doit( CD_DATA, CacheManagerVolumeCallbacks );
|
||||
doit( CD_DATA, CloseItem );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
VCB d;
|
||||
doit( VCB, NodeTypeCode );
|
||||
doit( VCB, NodeByteSize );
|
||||
doit( VCB, Vpb );
|
||||
doit( VCB, TargetDeviceObject );
|
||||
doit( VCB, VolumeLockFileObject );
|
||||
doit( VCB, VcbLinks );
|
||||
doit( VCB, VcbState );
|
||||
doit( VCB, VcbCondition );
|
||||
doit( VCB, VcbCleanup );
|
||||
doit( VCB, VcbReference );
|
||||
doit( VCB, VcbUserReference );
|
||||
doit( VCB, VolumeDasdFcb );
|
||||
doit( VCB, RootIndexFcb );
|
||||
doit( VCB, PathTableFcb );
|
||||
doit( VCB, BaseSector );
|
||||
doit( VCB, VdSectorOffset );
|
||||
doit( VCB, PrimaryVdSectorOffset );
|
||||
doit( VCB, XASector );
|
||||
doit( VCB, XADiskOffset );
|
||||
doit( VCB, VcbResource );
|
||||
doit( VCB, FileResource );
|
||||
doit( VCB, VcbMutex );
|
||||
doit( VCB, VcbLockThread );
|
||||
doit( VCB, NotifySync );
|
||||
doit( VCB, DirNotifyList );
|
||||
doit( VCB, BlockSize );
|
||||
doit( VCB, BlockToSectorShift );
|
||||
doit( VCB, BlockToByteShift );
|
||||
doit( VCB, BlocksPerSector );
|
||||
doit( VCB, BlockMask );
|
||||
doit( VCB, BlockInverseMask );
|
||||
doit( VCB, FcbTable );
|
||||
doit( VCB, CdromToc );
|
||||
doit( VCB, TocLength );
|
||||
doit( VCB, TrackCount );
|
||||
doit( VCB, DiskFlags );
|
||||
doit( VCB, BlockFactor );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
VOLUME_DEVICE_OBJECT d;
|
||||
doit( VOLUME_DEVICE_OBJECT, DeviceObject );
|
||||
doit( VOLUME_DEVICE_OBJECT, PostedRequestCount );
|
||||
doit( VOLUME_DEVICE_OBJECT, OverflowQueueCount );
|
||||
doit( VOLUME_DEVICE_OBJECT, OverflowQueue );
|
||||
doit( VOLUME_DEVICE_OBJECT, OverflowQueueSpinLock );
|
||||
doit( VOLUME_DEVICE_OBJECT, Vcb );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
FCB_DATA d;
|
||||
doit( FCB_DATA, Oplock );
|
||||
doit( FCB_DATA, FileLock );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
FCB_INDEX d;
|
||||
doit( FCB_INDEX, FileObject );
|
||||
doit( FCB_INDEX, StreamOffset );
|
||||
doit( FCB_INDEX, FcbQueue );
|
||||
doit( FCB_INDEX, Ordinal );
|
||||
doit( FCB_INDEX, ChildPathTableOffset );
|
||||
doit( FCB_INDEX, ChildOrdinal );
|
||||
doit( FCB_INDEX, ExactCaseRoot );
|
||||
doit( FCB_INDEX, IgnoreCaseRoot );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
FCB_NONPAGED d;
|
||||
doit( FCB_NONPAGED, NodeTypeCode );
|
||||
doit( FCB_NONPAGED, NodeByteSize );
|
||||
doit( FCB_NONPAGED, SegmentObject );
|
||||
doit( FCB_NONPAGED, FcbResource );
|
||||
doit( FCB_NONPAGED, FcbMutex );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
FCB d;
|
||||
doit( FCB, Header );
|
||||
doit( FCB, Vcb );
|
||||
doit( FCB, ParentFcb );
|
||||
doit( FCB, FcbLinks );
|
||||
doit( FCB, FileId );
|
||||
doit( FCB, FcbCleanup );
|
||||
doit( FCB, FcbReference );
|
||||
doit( FCB, FcbUserReference );
|
||||
doit( FCB, FcbState );
|
||||
doit( FCB, FileAttributes );
|
||||
doit( FCB, XAAttributes );
|
||||
doit( FCB, XAFileNumber );
|
||||
doit( FCB, FcbLockThread );
|
||||
doit( FCB, FcbLockCount );
|
||||
doit( FCB, FcbNonpaged );
|
||||
doit( FCB, ShareAccess );
|
||||
doit( FCB, McbEntry );
|
||||
doit( FCB, Mcb );
|
||||
doit( FCB, ShortNamePrefix );
|
||||
doit( FCB, FileNamePrefix );
|
||||
doit( FCB, CreationTime );
|
||||
doit( FCB, FcbType );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
CCB d;
|
||||
doit( CCB, NodeTypeCode );
|
||||
doit( CCB, NodeByteSize );
|
||||
doit( CCB, Flags );
|
||||
doit( CCB, Fcb );
|
||||
doit( CCB, CurrentDirentOffset );
|
||||
doit( CCB, SearchExpression );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
IRP_CONTEXT d;
|
||||
doit( IRP_CONTEXT, NodeTypeCode );
|
||||
doit( IRP_CONTEXT, NodeByteSize );
|
||||
doit( IRP_CONTEXT, Irp );
|
||||
doit( IRP_CONTEXT, Vcb );
|
||||
doit( IRP_CONTEXT, ExceptionStatus );
|
||||
doit( IRP_CONTEXT, Flags );
|
||||
doit( IRP_CONTEXT, RealDevice );
|
||||
doit( IRP_CONTEXT, IoContext );
|
||||
doit( IRP_CONTEXT, TeardownFcb );
|
||||
doit( IRP_CONTEXT, TopLevel );
|
||||
doit( IRP_CONTEXT, MajorFunction );
|
||||
doit( IRP_CONTEXT, MinorFunction );
|
||||
doit( IRP_CONTEXT, ThreadContext );
|
||||
doit( IRP_CONTEXT, WorkQueueItem );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
IRP_CONTEXT_LITE d;
|
||||
doit( IRP_CONTEXT_LITE, NodeTypeCode );
|
||||
doit( IRP_CONTEXT_LITE, NodeByteSize );
|
||||
doit( IRP_CONTEXT_LITE, Fcb );
|
||||
doit( IRP_CONTEXT_LITE, DelayedCloseLinks );
|
||||
doit( IRP_CONTEXT_LITE, UserReference );
|
||||
doit( IRP_CONTEXT_LITE, RealDevice );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
CD_IO_CONTEXT d;
|
||||
doit( CD_IO_CONTEXT, IrpCount );
|
||||
doit( CD_IO_CONTEXT, MasterIrp );
|
||||
doit( CD_IO_CONTEXT, Status );
|
||||
doit( CD_IO_CONTEXT, AllocatedContext );
|
||||
doit( CD_IO_CONTEXT, Resource );
|
||||
doit( CD_IO_CONTEXT, ResourceThreadId );
|
||||
doit( CD_IO_CONTEXT, SyncEvent );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
THREAD_CONTEXT d;
|
||||
doit( THREAD_CONTEXT, Cdfs );
|
||||
doit( THREAD_CONTEXT, SavedTopLevelIrp );
|
||||
doit( THREAD_CONTEXT, TopLevelIrpContext );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
PATH_ENUM_CONTEXT d;
|
||||
doit( PATH_ENUM_CONTEXT, Data );
|
||||
doit( PATH_ENUM_CONTEXT, BaseOffset );
|
||||
doit( PATH_ENUM_CONTEXT, DataLength );
|
||||
doit( PATH_ENUM_CONTEXT, Bcb );
|
||||
doit( PATH_ENUM_CONTEXT, DataOffset );
|
||||
doit( PATH_ENUM_CONTEXT, AllocatedData );
|
||||
doit( PATH_ENUM_CONTEXT, LastDataBlock );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
PATH_ENTRY d;
|
||||
doit( PATH_ENTRY, Ordinal );
|
||||
doit( PATH_ENTRY, PathTableOffset );
|
||||
doit( PATH_ENTRY, DiskOffset );
|
||||
doit( PATH_ENTRY, PathEntryLength );
|
||||
doit( PATH_ENTRY, ParentOrdinal );
|
||||
doit( PATH_ENTRY, DirNameLen );
|
||||
doit( PATH_ENTRY, DirName );
|
||||
doit( PATH_ENTRY, Flags );
|
||||
doit( PATH_ENTRY, CdDirName );
|
||||
doit( PATH_ENTRY, CdCaseDirName );
|
||||
doit( PATH_ENTRY, NameBuffer );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
COMPOUND_PATH_ENTRY d;
|
||||
doit( COMPOUND_PATH_ENTRY, PathContext );
|
||||
doit( COMPOUND_PATH_ENTRY, PathEntry );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
DIRENT_ENUM_CONTEXT d;
|
||||
doit( DIRENT_ENUM_CONTEXT, Sector );
|
||||
doit( DIRENT_ENUM_CONTEXT, BaseOffset );
|
||||
doit( DIRENT_ENUM_CONTEXT, DataLength );
|
||||
doit( DIRENT_ENUM_CONTEXT, Bcb );
|
||||
doit( DIRENT_ENUM_CONTEXT, SectorOffset );
|
||||
doit( DIRENT_ENUM_CONTEXT, NextDirentOffset );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
DIRENT d;
|
||||
doit( DIRENT, DirentOffset );
|
||||
doit( DIRENT, DirentLength );
|
||||
doit( DIRENT, StartingOffset );
|
||||
doit( DIRENT, DataLength );
|
||||
doit( DIRENT, CdTime );
|
||||
doit( DIRENT, DirentFlags );
|
||||
doit( DIRENT, Flags );
|
||||
doit( DIRENT, FileUnitSize );
|
||||
doit( DIRENT, InterleaveGapSize );
|
||||
doit( DIRENT, SystemUseOffset );
|
||||
doit( DIRENT, XAAttributes );
|
||||
doit( DIRENT, XAFileNumber );
|
||||
doit( DIRENT, FileNameLen );
|
||||
doit( DIRENT, FileName );
|
||||
doit( DIRENT, CdFileName );
|
||||
doit( DIRENT, CdCaseFileName );
|
||||
doit( DIRENT, ExtentType );
|
||||
doit( DIRENT, NameBuffer );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
COMPOUND_DIRENT d;
|
||||
doit( COMPOUND_DIRENT, DirContext );
|
||||
doit( COMPOUND_DIRENT, Dirent );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
FILE_ENUM_CONTEXT d;
|
||||
doit( FILE_ENUM_CONTEXT, PriorDirent );
|
||||
doit( FILE_ENUM_CONTEXT, InitialDirent );
|
||||
doit( FILE_ENUM_CONTEXT, CurrentDirent );
|
||||
doit( FILE_ENUM_CONTEXT, Flags );
|
||||
doit( FILE_ENUM_CONTEXT, FileSize );
|
||||
doit( FILE_ENUM_CONTEXT, ShortName );
|
||||
doit( FILE_ENUM_CONTEXT, ShortNameBuffer );
|
||||
doit( FILE_ENUM_CONTEXT, Dirents );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
RIFF_HEADER d;
|
||||
doit( RIFF_HEADER, ChunkId );
|
||||
doit( RIFF_HEADER, ChunkSize );
|
||||
doit( RIFF_HEADER, SignatureCDXA );
|
||||
doit( RIFF_HEADER, SignatureFMT );
|
||||
doit( RIFF_HEADER, XAChunkSize );
|
||||
doit( RIFF_HEADER, OwnerId );
|
||||
doit( RIFF_HEADER, Attributes );
|
||||
doit( RIFF_HEADER, SignatureXA );
|
||||
doit( RIFF_HEADER, FileNumber );
|
||||
doit( RIFF_HEADER, Reserved );
|
||||
doit( RIFF_HEADER, SignatureData );
|
||||
doit( RIFF_HEADER, RawSectors );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
AUDIO_PLAY_HEADER d;
|
||||
doit( AUDIO_PLAY_HEADER, Chunk );
|
||||
doit( AUDIO_PLAY_HEADER, ChunkSize );
|
||||
doit( AUDIO_PLAY_HEADER, SignatureCDDA );
|
||||
doit( AUDIO_PLAY_HEADER, SignatureFMT );
|
||||
doit( AUDIO_PLAY_HEADER, FMTChunkSize );
|
||||
doit( AUDIO_PLAY_HEADER, FormatTag );
|
||||
doit( AUDIO_PLAY_HEADER, TrackNumber );
|
||||
doit( AUDIO_PLAY_HEADER, DiskID );
|
||||
doit( AUDIO_PLAY_HEADER, StartingSector );
|
||||
doit( AUDIO_PLAY_HEADER, SectorCount );
|
||||
doit( AUDIO_PLAY_HEADER, TrackAddress );
|
||||
doit( AUDIO_PLAY_HEADER, TrackLength );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
RAW_ISO_VD d;
|
||||
doit( RAW_ISO_VD, DescType );
|
||||
doit( RAW_ISO_VD, StandardId );
|
||||
doit( RAW_ISO_VD, Version );
|
||||
doit( RAW_ISO_VD, VolumeFlags );
|
||||
doit( RAW_ISO_VD, SystemId );
|
||||
doit( RAW_ISO_VD, VolumeId );
|
||||
doit( RAW_ISO_VD, Reserved );
|
||||
doit( RAW_ISO_VD, VolSpaceI );
|
||||
doit( RAW_ISO_VD, VolSpaceM );
|
||||
doit( RAW_ISO_VD, CharSet );
|
||||
doit( RAW_ISO_VD, VolSetSizeI );
|
||||
doit( RAW_ISO_VD, VolSetSizeM );
|
||||
doit( RAW_ISO_VD, VolSeqNumI );
|
||||
doit( RAW_ISO_VD, VolSeqNumM );
|
||||
doit( RAW_ISO_VD, LogicalBlkSzI );
|
||||
doit( RAW_ISO_VD, LogicalBlkSzM );
|
||||
doit( RAW_ISO_VD, PathTableSzI );
|
||||
doit( RAW_ISO_VD, PathTableSzM );
|
||||
doit( RAW_ISO_VD, PathTabLocI );
|
||||
doit( RAW_ISO_VD, PathTabLocM );
|
||||
doit( RAW_ISO_VD, RootDe );
|
||||
doit( RAW_ISO_VD, VolSetId );
|
||||
doit( RAW_ISO_VD, PublId );
|
||||
doit( RAW_ISO_VD, PreparerId );
|
||||
doit( RAW_ISO_VD, AppId );
|
||||
doit( RAW_ISO_VD, Copyright );
|
||||
doit( RAW_ISO_VD, Abstract );
|
||||
doit( RAW_ISO_VD, Bibliograph );
|
||||
doit( RAW_ISO_VD, CreateDate );
|
||||
doit( RAW_ISO_VD, ModDate );
|
||||
doit( RAW_ISO_VD, ExpireDate );
|
||||
doit( RAW_ISO_VD, EffectDate );
|
||||
doit( RAW_ISO_VD, FileStructVer );
|
||||
doit( RAW_ISO_VD, Reserved3 );
|
||||
doit( RAW_ISO_VD, ResApp );
|
||||
doit( RAW_ISO_VD, Reserved4 );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
RAW_HSG_VD d;
|
||||
doit( RAW_HSG_VD, BlkNumI );
|
||||
doit( RAW_HSG_VD, BlkNumM );
|
||||
doit( RAW_HSG_VD, DescType );
|
||||
doit( RAW_HSG_VD, StandardId );
|
||||
doit( RAW_HSG_VD, Version );
|
||||
doit( RAW_HSG_VD, VolumeFlags );
|
||||
doit( RAW_HSG_VD, SystemId );
|
||||
doit( RAW_HSG_VD, VolumeId );
|
||||
doit( RAW_HSG_VD, Reserved );
|
||||
doit( RAW_HSG_VD, VolSpaceI );
|
||||
doit( RAW_HSG_VD, VolSpaceM );
|
||||
doit( RAW_HSG_VD, CharSet );
|
||||
doit( RAW_HSG_VD, VolSetSizeI );
|
||||
doit( RAW_HSG_VD, VolSetSizeM );
|
||||
doit( RAW_HSG_VD, VolSeqNumI );
|
||||
doit( RAW_HSG_VD, VolSeqNumM );
|
||||
doit( RAW_HSG_VD, LogicalBlkSzI );
|
||||
doit( RAW_HSG_VD, LogicalBlkSzM );
|
||||
doit( RAW_HSG_VD, PathTableSzI );
|
||||
doit( RAW_HSG_VD, PathTableSzM );
|
||||
doit( RAW_HSG_VD, PathTabLocI );
|
||||
doit( RAW_HSG_VD, PathTabLocM );
|
||||
doit( RAW_HSG_VD, RootDe );
|
||||
doit( RAW_HSG_VD, VolSetId );
|
||||
doit( RAW_HSG_VD, PublId );
|
||||
doit( RAW_HSG_VD, PreparerId );
|
||||
doit( RAW_HSG_VD, AppId );
|
||||
doit( RAW_HSG_VD, Copyright );
|
||||
doit( RAW_HSG_VD, Abstract );
|
||||
doit( RAW_HSG_VD, CreateDate );
|
||||
doit( RAW_HSG_VD, ModDate );
|
||||
doit( RAW_HSG_VD, ExpireDate );
|
||||
doit( RAW_HSG_VD, EffectDate );
|
||||
doit( RAW_HSG_VD, FileStructVer );
|
||||
doit( RAW_HSG_VD, Reserved3 );
|
||||
doit( RAW_HSG_VD, ResApp );
|
||||
doit( RAW_HSG_VD, Reserved4 );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
RAW_DIRENT d;
|
||||
doit( RAW_DIRENT, DirLen );
|
||||
doit( RAW_DIRENT, XarLen );
|
||||
doit( RAW_DIRENT, FileLoc );
|
||||
doit( RAW_DIRENT, FileLocMot );
|
||||
doit( RAW_DIRENT, DataLen );
|
||||
doit( RAW_DIRENT, DataLenMot );
|
||||
doit( RAW_DIRENT, RecordTime );
|
||||
doit( RAW_DIRENT, FlagsHSG );
|
||||
doit( RAW_DIRENT, FlagsISO );
|
||||
doit( RAW_DIRENT, IntLeaveSize );
|
||||
doit( RAW_DIRENT, IntLeaveSkip );
|
||||
doit( RAW_DIRENT, Vssn );
|
||||
doit( RAW_DIRENT, VssnMot );
|
||||
doit( RAW_DIRENT, FileIdLen );
|
||||
doit( RAW_DIRENT, FileId );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
RAW_PATH_ISO d;
|
||||
doit( RAW_PATH_ISO, DirIdLen );
|
||||
doit( RAW_PATH_ISO, XarLen );
|
||||
doit( RAW_PATH_ISO, DirLoc );
|
||||
doit( RAW_PATH_ISO, ParentNum );
|
||||
doit( RAW_PATH_ISO, DirId );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
RAW_PATH_HSG d;
|
||||
doit( RAW_PATH_HSG, DirLoc );
|
||||
doit( RAW_PATH_HSG, XarLen );
|
||||
doit( RAW_PATH_HSG, DirIdLen );
|
||||
doit( RAW_PATH_HSG, ParentNum );
|
||||
doit( RAW_PATH_HSG, DirId );
|
||||
}
|
||||
printf("\n");
|
||||
{
|
||||
SYSTEM_USE_XA d;
|
||||
doit( SYSTEM_USE_XA, OwnerId );
|
||||
doit( SYSTEM_USE_XA, Attributes );
|
||||
doit( SYSTEM_USE_XA, Signature );
|
||||
doit( SYSTEM_USE_XA, FileNumber );
|
||||
doit( SYSTEM_USE_XA, Reserved );
|
||||
}
|
||||
}
|
||||
|
||||
+1501
File diff suppressed because it is too large
Load Diff
+234
@@ -0,0 +1,234 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FilObSup.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the Cdfs File object support routines.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_FILOBSUP)
|
||||
|
||||
//
|
||||
// Local constants.
|
||||
//
|
||||
|
||||
#define TYPE_OF_OPEN_MASK (0x00000007)
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdDecodeFileObject)
|
||||
#pragma alloc_text(PAGE, CdFastDecodeFileObject)
|
||||
#pragma alloc_text(PAGE, CdSetFileObject)
|
||||
#endif
|
||||
|
||||
|
||||
VOID
|
||||
CdSetFileObject (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFILE_OBJECT FileObject,
|
||||
IN TYPE_OF_OPEN TypeOfOpen,
|
||||
IN PFCB Fcb OPTIONAL,
|
||||
IN PCCB Ccb OPTIONAL
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine will initialize the FileObject context fields based on the
|
||||
input type and data structures.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - Supplies the file object pointer being initialized.
|
||||
|
||||
TypeOfOpen - Sets the type of open.
|
||||
|
||||
Fcb - Fcb for this file object. Ignored for UnopenedFileObject.
|
||||
|
||||
Ccb - Ccb for the handle corresponding to this file object. Will not
|
||||
be present for stream file objects.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// We only have values 0 to 7 available so make sure we didn't
|
||||
// inadvertantly add a new type.
|
||||
//
|
||||
|
||||
ASSERTMSG( "FileObject types exceed available bits\n", BeyondValidType <= 8 );
|
||||
|
||||
//
|
||||
// Setting a file object to type UnopenedFileObject means just
|
||||
// clearing all of the context fields. All the other input
|
||||
//
|
||||
|
||||
if (TypeOfOpen == UnopenedFileObject) {
|
||||
|
||||
FileObject->FsContext =
|
||||
FileObject->FsContext2 = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Check that the 3 low-order bits of the Ccb are clear.
|
||||
//
|
||||
|
||||
ASSERTMSG( "Ccb is not quad-aligned\n", !FlagOn( ((ULONG_PTR) Ccb), TYPE_OF_OPEN_MASK ));
|
||||
|
||||
//
|
||||
// We will or the type of open into the low order bits of FsContext2
|
||||
// along with the Ccb value.
|
||||
// The Fcb is stored into the FsContext field.
|
||||
//
|
||||
|
||||
FileObject->FsContext = Fcb;
|
||||
FileObject->FsContext2 = Ccb;
|
||||
|
||||
SetFlag( ((ULONG_PTR) FileObject->FsContext2), TypeOfOpen );
|
||||
|
||||
//
|
||||
// Set the Vpb field in the file object.
|
||||
//
|
||||
|
||||
FileObject->Vpb = Fcb->Vcb->Vpb;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TYPE_OF_OPEN
|
||||
CdDecodeFileObject (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFILE_OBJECT FileObject,
|
||||
OUT PFCB *Fcb,
|
||||
OUT PCCB *Ccb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine takes a file object and extracts the Fcb and Ccb (possibly NULL)
|
||||
and returns the type of open.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - Supplies the file object pointer being initialized.
|
||||
|
||||
Fcb - Address to store the Fcb contained in the file object.
|
||||
|
||||
Ccb - Address to store the Ccb contained in the file object.
|
||||
|
||||
Return Value:
|
||||
|
||||
TYPE_OF_OPEN - Indicates the type of file object.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
TYPE_OF_OPEN TypeOfOpen;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// If this is an unopened file object then return NULL for the
|
||||
// Fcb/Ccb. Don't trust any other values in the file object.
|
||||
//
|
||||
|
||||
TypeOfOpen = (TYPE_OF_OPEN) FlagOn( (ULONG_PTR) FileObject->FsContext2,
|
||||
TYPE_OF_OPEN_MASK );
|
||||
|
||||
if (TypeOfOpen == UnopenedFileObject) {
|
||||
|
||||
*Fcb = NULL;
|
||||
*Ccb = NULL;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// The Fcb is pointed to by the FsContext field. The Ccb is in
|
||||
// FsContext2 (after clearing the low three bits). The low three
|
||||
// bits are the file object type.
|
||||
//
|
||||
|
||||
*Fcb = FileObject->FsContext;
|
||||
*Ccb = FileObject->FsContext2;
|
||||
|
||||
ClearFlag( (ULONG_PTR) *Ccb, TYPE_OF_OPEN_MASK );
|
||||
}
|
||||
|
||||
//
|
||||
// Now return the type of open.
|
||||
//
|
||||
|
||||
return TypeOfOpen;
|
||||
}
|
||||
|
||||
|
||||
TYPE_OF_OPEN
|
||||
CdFastDecodeFileObject (
|
||||
IN PFILE_OBJECT FileObject,
|
||||
OUT PFCB *Fcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This procedure takes a pointer to a file object, that has already been
|
||||
opened by Cdfs and does a quick decode operation. It will only return
|
||||
a non null value if the file object is a user file open
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - Supplies the file object pointer being interrogated
|
||||
|
||||
Fcb - Address to store Fcb if this is a user file object. NULL
|
||||
otherwise.
|
||||
|
||||
Return Value:
|
||||
|
||||
TYPE_OF_OPEN - type of open of this file object.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_FILE_OBJECT( FileObject );
|
||||
|
||||
//
|
||||
// The Fcb is in the FsContext field. The type of open is in the low
|
||||
// bits of the Ccb.
|
||||
//
|
||||
|
||||
*Fcb = FileObject->FsContext;
|
||||
|
||||
return (TYPE_OF_OPEN)
|
||||
FlagOn( (ULONG_PTR) FileObject->FsContext2, TYPE_OF_OPEN_MASK );
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3166
File diff suppressed because it is too large
Load Diff
+278
@@ -0,0 +1,278 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FspDisp.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the main dispatch procedure/thread for the Cdfs
|
||||
Fsp
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_FSPDISP)
|
||||
|
||||
|
||||
VOID
|
||||
CdFspDispatch (
|
||||
IN PIRP_CONTEXT IrpContext
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the main FSP thread routine that is executed to receive
|
||||
and dispatch IRP requests. Each FSP thread begins its execution here.
|
||||
There is one thread created at system initialization time and subsequent
|
||||
threads created as needed.
|
||||
|
||||
Arguments:
|
||||
|
||||
IrpContext - IrpContext for a request to process.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
THREAD_CONTEXT ThreadContext;
|
||||
NTSTATUS Status;
|
||||
|
||||
PIRP Irp = IrpContext->Irp;
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
PVOLUME_DEVICE_OBJECT VolDo = NULL;
|
||||
|
||||
//
|
||||
// If this request has an associated volume device object, remember it.
|
||||
//
|
||||
|
||||
if (IrpSp->FileObject != NULL) {
|
||||
|
||||
VolDo = CONTAINING_RECORD( IrpSp->DeviceObject,
|
||||
VOLUME_DEVICE_OBJECT,
|
||||
DeviceObject );
|
||||
}
|
||||
|
||||
//
|
||||
// Now case on the function code. For each major function code,
|
||||
// either call the appropriate worker routine. This routine that
|
||||
// we call is responsible for completing the IRP, and not us.
|
||||
// That way the routine can complete the IRP and then continue
|
||||
// post processing as required. For example, a read can be
|
||||
// satisfied right away and then read can be done.
|
||||
//
|
||||
// We'll do all of the work within an exception handler that
|
||||
// will be invoked if ever some underlying operation gets into
|
||||
// trouble.
|
||||
//
|
||||
|
||||
while ( TRUE ) {
|
||||
|
||||
//
|
||||
// Set all the flags indicating we are in the Fsp.
|
||||
//
|
||||
|
||||
SetFlag( IrpContext->Flags, IRP_CONTEXT_FSP_FLAGS );
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
CdSetThreadContext( IrpContext, &ThreadContext );
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
try {
|
||||
|
||||
//
|
||||
// Reinitialize for the next try at completing this
|
||||
// request.
|
||||
//
|
||||
|
||||
Status =
|
||||
IrpContext->ExceptionStatus = STATUS_SUCCESS;
|
||||
|
||||
//
|
||||
// Initialize the Io status field in the Irp.
|
||||
//
|
||||
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
//
|
||||
// Case on the major irp code.
|
||||
//
|
||||
|
||||
switch (IrpContext->MajorFunction) {
|
||||
|
||||
case IRP_MJ_CREATE :
|
||||
|
||||
CdCommonCreate( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
case IRP_MJ_CLOSE :
|
||||
|
||||
ASSERT( FALSE );
|
||||
break;
|
||||
|
||||
case IRP_MJ_READ :
|
||||
|
||||
CdCommonRead( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
case IRP_MJ_QUERY_INFORMATION :
|
||||
|
||||
CdCommonQueryInfo( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
case IRP_MJ_SET_INFORMATION :
|
||||
|
||||
CdCommonSetInfo( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
case IRP_MJ_QUERY_VOLUME_INFORMATION :
|
||||
|
||||
CdCommonQueryVolInfo( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
case IRP_MJ_DIRECTORY_CONTROL :
|
||||
|
||||
CdCommonDirControl( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
case IRP_MJ_FILE_SYSTEM_CONTROL :
|
||||
|
||||
CdCommonFsControl( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL :
|
||||
|
||||
CdCommonDevControl( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
case IRP_MJ_LOCK_CONTROL :
|
||||
|
||||
CdCommonLockControl( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
case IRP_MJ_CLEANUP :
|
||||
|
||||
CdCommonCleanup( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
case IRP_MJ_PNP :
|
||||
|
||||
ASSERT( FALSE );
|
||||
CdCommonPnp( IrpContext, Irp );
|
||||
break;
|
||||
|
||||
default :
|
||||
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
CdCompleteRequest( IrpContext, Irp, Status );
|
||||
}
|
||||
|
||||
} except( CdExceptionFilter( IrpContext, GetExceptionInformation() )) {
|
||||
|
||||
Status = CdProcessException( IrpContext, Irp, GetExceptionCode() );
|
||||
}
|
||||
|
||||
//
|
||||
// Break out of the loop if we didn't get CANT_WAIT.
|
||||
//
|
||||
|
||||
if (Status != STATUS_CANT_WAIT) { break; }
|
||||
|
||||
//
|
||||
// We are retrying this request. Cleanup the IrpContext for the retry.
|
||||
//
|
||||
|
||||
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
|
||||
CdCleanupIrpContext( IrpContext, FALSE );
|
||||
}
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
|
||||
//
|
||||
// If there are any entries on this volume's overflow queue, service
|
||||
// them.
|
||||
//
|
||||
|
||||
if (VolDo != NULL) {
|
||||
|
||||
KIRQL SavedIrql;
|
||||
PVOID Entry = NULL;
|
||||
|
||||
//
|
||||
// We have a volume device object so see if there is any work
|
||||
// left to do in its overflow queue.
|
||||
//
|
||||
|
||||
KeAcquireSpinLock( &VolDo->OverflowQueueSpinLock, &SavedIrql );
|
||||
|
||||
if (VolDo->OverflowQueueCount > 0) {
|
||||
|
||||
//
|
||||
// There is overflow work to do in this volume so we'll
|
||||
// decrement the Overflow count, dequeue the IRP, and release
|
||||
// the Event
|
||||
//
|
||||
|
||||
VolDo->OverflowQueueCount -= 1;
|
||||
|
||||
Entry = RemoveHeadList( &VolDo->OverflowQueue );
|
||||
}
|
||||
|
||||
KeReleaseSpinLock( &VolDo->OverflowQueueSpinLock, SavedIrql );
|
||||
|
||||
//
|
||||
// There wasn't an entry, break out of the loop and return to
|
||||
// the Ex Worker thread.
|
||||
//
|
||||
|
||||
if (Entry == NULL) { break; }
|
||||
|
||||
//
|
||||
// Extract the IrpContext , Irp, set wait to TRUE, and loop.
|
||||
//
|
||||
|
||||
IrpContext = CONTAINING_RECORD( Entry,
|
||||
IRP_CONTEXT,
|
||||
WorkQueueItem.List );
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Decrement the PostedRequestCount if there was a volume device object.
|
||||
//
|
||||
|
||||
if (VolDo) {
|
||||
|
||||
InterlockedDecrement( &VolDo->PostedRequestCount );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+674
@@ -0,0 +1,674 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
LockCtrl.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the Lock Control routines for Cdfs called
|
||||
by the Fsd/Fsp dispatch driver.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_LOCKCTRL)
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdCommonLockControl)
|
||||
#pragma alloc_text(PAGE, CdFastLock)
|
||||
#pragma alloc_text(PAGE, CdFastUnlockAll)
|
||||
#pragma alloc_text(PAGE, CdFastUnlockAllByKey)
|
||||
#pragma alloc_text(PAGE, CdFastUnlockSingle)
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdCommonLockControl (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the common routine for Lock Control called by both the fsd and fsp
|
||||
threads.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Supplies the Irp to process
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The return status for the operation
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
TYPE_OF_OPEN TypeOfOpen;
|
||||
PFCB Fcb;
|
||||
PCCB Ccb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Extract and decode the type of file object we're being asked to process
|
||||
//
|
||||
|
||||
TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
|
||||
|
||||
//
|
||||
// If the file is not a user file open then we reject the request
|
||||
// as an invalid parameter
|
||||
//
|
||||
|
||||
if (TypeOfOpen != UserFileOpen) {
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// We check whether we can proceed based on the state of the file oplocks.
|
||||
// This call might post the irp for us.
|
||||
//
|
||||
|
||||
Status = FsRtlCheckOplock( &Fcb->Oplock,
|
||||
Irp,
|
||||
IrpContext,
|
||||
CdOplockComplete,
|
||||
NULL );
|
||||
|
||||
//
|
||||
// If we don't get success then the oplock package completed the request.
|
||||
//
|
||||
|
||||
if (Status != STATUS_SUCCESS) {
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Verify the Fcb.
|
||||
//
|
||||
|
||||
CdVerifyFcbOperation( IrpContext, Fcb );
|
||||
|
||||
//
|
||||
// If we don't have a file lock, then get one now.
|
||||
//
|
||||
|
||||
if (Fcb->FileLock == NULL) { CdCreateFileLock( IrpContext, Fcb, TRUE ); }
|
||||
|
||||
//
|
||||
// Now call the FsRtl routine to do the actual processing of the
|
||||
// Lock request
|
||||
//
|
||||
|
||||
Status = FsRtlProcessFileLock( Fcb->FileLock, Irp, NULL );
|
||||
|
||||
//
|
||||
// Set the flag indicating if Fast I/O is possible
|
||||
//
|
||||
|
||||
CdLockFcb( IrpContext, Fcb );
|
||||
Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
|
||||
CdUnlockFcb( IrpContext, Fcb );
|
||||
|
||||
//
|
||||
// Complete the request.
|
||||
//
|
||||
|
||||
CdCompleteRequest( IrpContext, NULL, Status );
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdFastLock (
|
||||
IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN PLARGE_INTEGER Length,
|
||||
PEPROCESS ProcessId,
|
||||
ULONG Key,
|
||||
BOOLEAN FailImmediately,
|
||||
BOOLEAN ExclusiveLock,
|
||||
OUT PIO_STATUS_BLOCK IoStatus,
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is a call back routine for doing the fast lock call.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - Supplies the file object used in this operation
|
||||
|
||||
FileOffset - Supplies the file offset used in this operation
|
||||
|
||||
Length - Supplies the length used in this operation
|
||||
|
||||
ProcessId - Supplies the process ID used in this operation
|
||||
|
||||
Key - Supplies the key used in this operation
|
||||
|
||||
FailImmediately - Indicates if the request should fail immediately
|
||||
if the lock cannot be granted.
|
||||
|
||||
ExclusiveLock - Indicates if this is a request for an exclusive or
|
||||
shared lock
|
||||
|
||||
IoStatus - Receives the Status if this operation is successful
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - TRUE if this operation completed and FALSE if caller
|
||||
needs to take the long route.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
BOOLEAN Results = FALSE;
|
||||
|
||||
PFCB Fcb;
|
||||
TYPE_OF_OPEN TypeOfOpen;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_FILE_OBJECT( FileObject );
|
||||
|
||||
IoStatus->Information = 0;
|
||||
|
||||
//
|
||||
// Decode the type of file object we're being asked to process and
|
||||
// make sure that is is only a user file open.
|
||||
//
|
||||
|
||||
TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
|
||||
|
||||
if (TypeOfOpen != UserFileOpen) {
|
||||
|
||||
IoStatus->Status = STATUS_INVALID_PARAMETER;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Only deal with 'good' Fcb's.
|
||||
//
|
||||
|
||||
if (!CdVerifyFcbOperation( NULL, Fcb )) {
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
//
|
||||
// Use a try-finally to facilitate cleanup.
|
||||
//
|
||||
|
||||
try {
|
||||
|
||||
//
|
||||
// We check whether we can proceed based on the state of the file oplocks.
|
||||
//
|
||||
|
||||
if ((Fcb->Oplock != NULL) && !FsRtlOplockIsFastIoPossible( &Fcb->Oplock )) {
|
||||
|
||||
try_return( NOTHING );
|
||||
}
|
||||
|
||||
//
|
||||
// If we don't have a file lock, then get one now.
|
||||
//
|
||||
|
||||
if ((Fcb->FileLock == NULL) && !CdCreateFileLock( NULL, Fcb, FALSE )) {
|
||||
|
||||
try_return( NOTHING );
|
||||
}
|
||||
|
||||
//
|
||||
// Now call the FsRtl routine to perform the lock request.
|
||||
//
|
||||
|
||||
if (Results = FsRtlFastLock( Fcb->FileLock,
|
||||
FileObject,
|
||||
FileOffset,
|
||||
Length,
|
||||
ProcessId,
|
||||
Key,
|
||||
FailImmediately,
|
||||
ExclusiveLock,
|
||||
IoStatus,
|
||||
NULL,
|
||||
FALSE )) {
|
||||
|
||||
//
|
||||
// Set the flag indicating if Fast I/O is questionable. We
|
||||
// only change this flag if the current state is possible.
|
||||
// Retest again after synchronizing on the header.
|
||||
//
|
||||
|
||||
if (Fcb->IsFastIoPossible == FastIoIsPossible) {
|
||||
|
||||
CdLockFcb( NULL, Fcb );
|
||||
Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
|
||||
CdUnlockFcb( NULL, Fcb );
|
||||
}
|
||||
}
|
||||
|
||||
try_exit: NOTHING;
|
||||
} finally {
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
|
||||
return Results;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdFastUnlockSingle (
|
||||
IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN PLARGE_INTEGER Length,
|
||||
PEPROCESS ProcessId,
|
||||
ULONG Key,
|
||||
OUT PIO_STATUS_BLOCK IoStatus,
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is a call back routine for doing the fast unlock single call.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - Supplies the file object used in this operation
|
||||
|
||||
FileOffset - Supplies the file offset used in this operation
|
||||
|
||||
Length - Supplies the length used in this operation
|
||||
|
||||
ProcessId - Supplies the process ID used in this operation
|
||||
|
||||
Key - Supplies the key used in this operation
|
||||
|
||||
Status - Receives the Status if this operation is successful
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - TRUE if this operation completed and FALSE if caller
|
||||
needs to take the long route.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
BOOLEAN Results = FALSE;
|
||||
TYPE_OF_OPEN TypeOfOpen;
|
||||
PFCB Fcb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
IoStatus->Information = 0;
|
||||
|
||||
//
|
||||
// Decode the type of file object we're being asked to process and
|
||||
// make sure that is is only a user file open.
|
||||
//
|
||||
|
||||
TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
|
||||
|
||||
if (TypeOfOpen != UserFileOpen) {
|
||||
|
||||
IoStatus->Status = STATUS_INVALID_PARAMETER;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Only deal with 'good' Fcb's.
|
||||
//
|
||||
|
||||
if (!CdVerifyFcbOperation( NULL, Fcb )) {
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// If there is no lock then return immediately.
|
||||
//
|
||||
|
||||
if (Fcb->FileLock == NULL) {
|
||||
|
||||
IoStatus->Status = STATUS_RANGE_NOT_LOCKED;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
try {
|
||||
|
||||
//
|
||||
// We check whether we can proceed based on the state of the file oplocks.
|
||||
//
|
||||
|
||||
if ((Fcb->Oplock != NULL) && !FsRtlOplockIsFastIoPossible( &Fcb->Oplock )) {
|
||||
|
||||
try_return( NOTHING );
|
||||
}
|
||||
|
||||
//
|
||||
// If we don't have a file lock, then get one now.
|
||||
//
|
||||
|
||||
if ((Fcb->FileLock == NULL) && !CdCreateFileLock( NULL, Fcb, FALSE )) {
|
||||
|
||||
try_return( NOTHING );
|
||||
}
|
||||
|
||||
//
|
||||
// Now call the FsRtl routine to do the actual processing of the
|
||||
// Lock request. The call will always succeed.
|
||||
//
|
||||
|
||||
Results = TRUE;
|
||||
IoStatus->Status = FsRtlFastUnlockSingle( Fcb->FileLock,
|
||||
FileObject,
|
||||
FileOffset,
|
||||
Length,
|
||||
ProcessId,
|
||||
Key,
|
||||
NULL,
|
||||
FALSE );
|
||||
|
||||
//
|
||||
// Set the flag indicating if Fast I/O is possible. We are
|
||||
// only concerned if there are no longer any filelocks on this
|
||||
// file.
|
||||
//
|
||||
|
||||
if (!FsRtlAreThereCurrentFileLocks( Fcb->FileLock ) &&
|
||||
(Fcb->IsFastIoPossible != FastIoIsPossible)) {
|
||||
|
||||
CdLockFcb( IrpContext, Fcb );
|
||||
Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
|
||||
CdUnlockFcb( IrpContext, Fcb );
|
||||
}
|
||||
|
||||
try_exit: NOTHING;
|
||||
} finally {
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
|
||||
return Results;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdFastUnlockAll (
|
||||
IN PFILE_OBJECT FileObject,
|
||||
PEPROCESS ProcessId,
|
||||
OUT PIO_STATUS_BLOCK IoStatus,
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is a call back routine for doing the fast unlock all call.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - Supplies the file object used in this operation
|
||||
|
||||
ProcessId - Supplies the process ID used in this operation
|
||||
|
||||
Status - Receives the Status if this operation is successful
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - TRUE if this operation completed and FALSE if caller
|
||||
needs to take the long route.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
BOOLEAN Results = FALSE;
|
||||
TYPE_OF_OPEN TypeOfOpen;
|
||||
PFCB Fcb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
IoStatus->Information = 0;
|
||||
|
||||
//
|
||||
// Decode the type of file object we're being asked to process and
|
||||
// make sure that is is only a user file open.
|
||||
//
|
||||
|
||||
TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
|
||||
|
||||
if (TypeOfOpen != UserFileOpen) {
|
||||
|
||||
IoStatus->Status = STATUS_INVALID_PARAMETER;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Only deal with 'good' Fcb's.
|
||||
//
|
||||
|
||||
if (!CdVerifyFcbOperation( NULL, Fcb )) {
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// If there is no lock then return immediately.
|
||||
//
|
||||
|
||||
if (Fcb->FileLock == NULL) {
|
||||
|
||||
IoStatus->Status = STATUS_RANGE_NOT_LOCKED;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
try {
|
||||
|
||||
//
|
||||
// We check whether we can proceed based on the state of the file oplocks.
|
||||
//
|
||||
|
||||
if ((Fcb->Oplock != NULL) && !FsRtlOplockIsFastIoPossible( &Fcb->Oplock )) {
|
||||
|
||||
try_return( NOTHING );
|
||||
}
|
||||
|
||||
//
|
||||
// If we don't have a file lock, then get one now.
|
||||
//
|
||||
|
||||
if ((Fcb->FileLock == NULL) && !CdCreateFileLock( NULL, Fcb, FALSE )) {
|
||||
|
||||
try_return( NOTHING );
|
||||
}
|
||||
|
||||
//
|
||||
// Now call the FsRtl routine to do the actual processing of the
|
||||
// Lock request. The call will always succeed.
|
||||
//
|
||||
|
||||
Results = TRUE;
|
||||
IoStatus->Status = FsRtlFastUnlockAll( Fcb->FileLock,
|
||||
FileObject,
|
||||
ProcessId,
|
||||
NULL );
|
||||
|
||||
|
||||
//
|
||||
// Set the flag indicating if Fast I/O is possible
|
||||
//
|
||||
|
||||
CdLockFcb( IrpContext, Fcb );
|
||||
Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
|
||||
CdUnlockFcb( IrpContext, Fcb );
|
||||
|
||||
try_exit: NOTHING;
|
||||
} finally {
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
|
||||
return Results;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdFastUnlockAllByKey (
|
||||
IN PFILE_OBJECT FileObject,
|
||||
PVOID ProcessId,
|
||||
ULONG Key,
|
||||
OUT PIO_STATUS_BLOCK IoStatus,
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is a call back routine for doing the fast unlock all by key call.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - Supplies the file object used in this operation
|
||||
|
||||
ProcessId - Supplies the process ID used in this operation
|
||||
|
||||
Key - Supplies the key used in this operation
|
||||
|
||||
Status - Receives the Status if this operation is successful
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - TRUE if this operation completed and FALSE if caller
|
||||
needs to take the long route.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
BOOLEAN Results = FALSE;
|
||||
TYPE_OF_OPEN TypeOfOpen;
|
||||
PFCB Fcb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
IoStatus->Information = 0;
|
||||
|
||||
//
|
||||
// Decode the type of file object we're being asked to process and
|
||||
// make sure that is is only a user file open.
|
||||
//
|
||||
|
||||
TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
|
||||
|
||||
if (TypeOfOpen != UserFileOpen) {
|
||||
|
||||
IoStatus->Status = STATUS_INVALID_PARAMETER;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Only deal with 'good' Fcb's.
|
||||
//
|
||||
|
||||
if (!CdVerifyFcbOperation( NULL, Fcb )) {
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// If there is no lock then return immediately.
|
||||
//
|
||||
|
||||
if (Fcb->FileLock == NULL) {
|
||||
|
||||
IoStatus->Status = STATUS_RANGE_NOT_LOCKED;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
try {
|
||||
|
||||
//
|
||||
// We check whether we can proceed based on the state of the file oplocks.
|
||||
//
|
||||
|
||||
if ((Fcb->Oplock != NULL) && !FsRtlOplockIsFastIoPossible( &Fcb->Oplock )) {
|
||||
|
||||
try_return( NOTHING );
|
||||
}
|
||||
|
||||
//
|
||||
// If we don't have a file lock, then get one now.
|
||||
//
|
||||
|
||||
if ((Fcb->FileLock == NULL) && !CdCreateFileLock( NULL, Fcb, FALSE )) {
|
||||
|
||||
try_return( NOTHING );
|
||||
}
|
||||
|
||||
//
|
||||
// Now call the FsRtl routine to do the actual processing of the
|
||||
// Lock request. The call will always succeed.
|
||||
//
|
||||
|
||||
Results = TRUE;
|
||||
IoStatus->Status = FsRtlFastUnlockAllByKey( Fcb->FileLock,
|
||||
FileObject,
|
||||
ProcessId,
|
||||
Key,
|
||||
NULL );
|
||||
|
||||
|
||||
//
|
||||
// Set the flag indicating if Fast I/O is possible
|
||||
//
|
||||
|
||||
CdLockFcb( IrpContext, Fcb );
|
||||
Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
|
||||
CdUnlockFcb( IrpContext, Fcb );
|
||||
|
||||
try_exit: NOTHING;
|
||||
} finally {
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
|
||||
return Results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1044
File diff suppressed because it is too large
Load Diff
+103
@@ -0,0 +1,103 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
NodeType.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This module defines all of the node type codes used in this development
|
||||
shell. Every major data structure in the file system is assigned a node
|
||||
type code that is. This code is the first CSHORT in the structure and is
|
||||
followed by a CSHORT containing the size, in bytes, of the structure.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _CDNODETYPE_
|
||||
#define _CDNODETYPE_
|
||||
|
||||
typedef CSHORT NODE_TYPE_CODE;
|
||||
typedef NODE_TYPE_CODE *PNODE_TYPE_CODE;
|
||||
|
||||
#define NTC_UNDEFINED ((NODE_TYPE_CODE)0x0000)
|
||||
|
||||
#define CDFS_NTC_DATA_HEADER ((NODE_TYPE_CODE)0x0301)
|
||||
#define CDFS_NTC_VCB ((NODE_TYPE_CODE)0x0302)
|
||||
#define CDFS_NTC_FCB_PATH_TABLE ((NODE_TYPE_CODE)0x0303)
|
||||
#define CDFS_NTC_FCB_INDEX ((NODE_TYPE_CODE)0x0304)
|
||||
#define CDFS_NTC_FCB_DATA ((NODE_TYPE_CODE)0x0305)
|
||||
#define CDFS_NTC_FCB_NONPAGED ((NODE_TYPE_CODE)0x0306)
|
||||
#define CDFS_NTC_CCB ((NODE_TYPE_CODE)0x0307)
|
||||
#define CDFS_NTC_IRP_CONTEXT ((NODE_TYPE_CODE)0x0308)
|
||||
#define CDFS_NTC_IRP_CONTEXT_LITE ((NODE_TYPE_CODE)0x0309)
|
||||
|
||||
typedef CSHORT NODE_BYTE_SIZE;
|
||||
|
||||
//
|
||||
// So all records start with
|
||||
//
|
||||
// typedef struct _RECORD_NAME {
|
||||
// NODE_TYPE_CODE NodeTypeCode;
|
||||
// NODE_BYTE_SIZE NodeByteSize;
|
||||
// :
|
||||
// } RECORD_NAME;
|
||||
// typedef RECORD_NAME *PRECORD_NAME;
|
||||
//
|
||||
|
||||
#ifndef NodeType
|
||||
#define NodeType(P) ((P) != NULL ? (*((PNODE_TYPE_CODE)(P))) : NTC_UNDEFINED)
|
||||
#endif
|
||||
#ifndef SafeNodeType
|
||||
#define SafeNodeType(Ptr) (*((PNODE_TYPE_CODE)(Ptr)))
|
||||
#endif
|
||||
|
||||
//
|
||||
// The following definitions are used to generate meaningful blue bugcheck
|
||||
// screens. On a bugcheck the file system can output 4 ulongs of useful
|
||||
// information. The first ulong will have encoded in it a source file id
|
||||
// (in the high word) and the line number of the bugcheck (in the low word).
|
||||
// The other values can be whatever the caller of the bugcheck routine deems
|
||||
// necessary.
|
||||
//
|
||||
// Each individual file that calls bugcheck needs to have defined at the
|
||||
// start of the file a constant called BugCheckFileId with one of the
|
||||
// CDFS_BUG_CHECK_ values defined below and then use CdBugCheck to bugcheck
|
||||
// the system.
|
||||
//
|
||||
|
||||
#define CDFS_BUG_CHECK_ACCHKSUP (0x00010000)
|
||||
#define CDFS_BUG_CHECK_ALLOCSUP (0x00020000)
|
||||
#define CDFS_BUG_CHECK_CACHESUP (0x00030000)
|
||||
#define CDFS_BUG_CHECK_CDDATA (0x00040000)
|
||||
#define CDFS_BUG_CHECK_CDINIT (0x00050000)
|
||||
#define CDFS_BUG_CHECK_CLEANUP (0x00060000)
|
||||
#define CDFS_BUG_CHECK_CLOSE (0x00070000)
|
||||
#define CDFS_BUG_CHECK_CREATE (0x00080000)
|
||||
#define CDFS_BUG_CHECK_DEVCTRL (0x00090000)
|
||||
#define CDFS_BUG_CHECK_DEVIOSUP (0x000a0000)
|
||||
#define CDFS_BUG_CHECK_DIRCTRL (0x000b0000)
|
||||
#define CDFS_BUG_CHECK_DIRSUP (0x000c0000)
|
||||
#define CDFS_BUG_CHECK_FILEINFO (0x000d0000)
|
||||
#define CDFS_BUG_CHECK_FILOBSUP (0x000e0000)
|
||||
#define CDFS_BUG_CHECK_FSCTRL (0x000f0000)
|
||||
#define CDFS_BUG_CHECK_FSPDISP (0x00100000)
|
||||
#define CDFS_BUG_CHECK_LOCKCTRL (0x00110000)
|
||||
#define CDFS_BUG_CHECK_NAMESUP (0x00120000)
|
||||
#define CDFS_BUG_CHECK_PATHSUP (0x00130000)
|
||||
#define CDFS_BUG_CHECK_PNP (0x00140000)
|
||||
#define CDFS_BUG_CHECK_PREFXSUP (0x00150000)
|
||||
#define CDFS_BUG_CHECK_READ (0x00160000)
|
||||
#define CDFS_BUG_CHECK_RESRCSUP (0x00170000)
|
||||
#define CDFS_BUG_CHECK_STRUCSUP (0x00180000)
|
||||
#define CDFS_BUG_CHECK_TIMESUP (0x00190000)
|
||||
#define CDFS_BUG_CHECK_VERFYSUP (0x001a0000)
|
||||
#define CDFS_BUG_CHECK_VOLINFO (0x001b0000)
|
||||
#define CDFS_BUG_CHECK_WORKQUE (0x001c0000)
|
||||
|
||||
#define CdBugCheck(A,B,C) { KeBugCheckEx(CDFS_FILE_SYSTEM, BugCheckFileId | __LINE__, A, B, C ); }
|
||||
|
||||
#endif // _NODETYPE_
|
||||
|
||||
+997
@@ -0,0 +1,997 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
PathSup.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the Path Table support routines for Cdfs.
|
||||
|
||||
The path table on a CDROM is a condensed summary of the entire
|
||||
directory structure. It is stored on a number of contiguous sectors
|
||||
on the disk. Each directory on the disk has an entry in the path
|
||||
table. The entries are aligned on USHORT boundaries and MAY span
|
||||
sector boundaries. The entries are stored as a breadth-first search.
|
||||
|
||||
The first entry in the table contains the entry for the root. The
|
||||
next entries will consist of the contents of the root directory. The
|
||||
next entries will consist of the all the directories at the next level
|
||||
of the tree. The children of a given directory will be grouped together.
|
||||
|
||||
The directories are assigned ordinal numbers based on their position in
|
||||
the path table. The root dirctory is assigned ordinal value 1.
|
||||
|
||||
Path table sectors:
|
||||
|
||||
Ordinal 1 2 3 4 5 6
|
||||
+-----------+
|
||||
| Spanning |
|
||||
| Sectors |
|
||||
+----------------------------+ +------------------------+
|
||||
| | | | | | | | |
|
||||
DirName | \ | a | b |c| | c | d | e |
|
||||
| | | | | | | | |
|
||||
Parent #| 1 | 1 | 1 | | | 2 | 2 | 3 |
|
||||
+----------------------------+ +------------------------+
|
||||
|
||||
Directory Tree:
|
||||
|
||||
\ (root)
|
||||
|
||||
/ \
|
||||
/ \
|
||||
a b
|
||||
|
||||
/ \ \
|
||||
/ \ \
|
||||
c d e
|
||||
|
||||
Path Table Entries:
|
||||
|
||||
- Position scan at known offset in the path table. Path Entry at
|
||||
this offset must exist and is known to be valid. Used when
|
||||
scanning for the children of a given directory.
|
||||
|
||||
- Position scan at known offset in the path table. Path Entry is
|
||||
known to start at this location but the bounds must be checked
|
||||
for validity.
|
||||
|
||||
- Move to next path entry in the table.
|
||||
|
||||
- Update a common path entry structure with the details of the
|
||||
on-disk structure. This is used to smooth out the differences
|
||||
in the on-disk structures.
|
||||
|
||||
- Update the filename in the in-memory path entry with the bytes
|
||||
off the disk. For Joliet disks we will have
|
||||
to convert to little endian. We assume that directories
|
||||
don't have version numbers.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_PATHSUP)
|
||||
|
||||
//
|
||||
// Local macros
|
||||
//
|
||||
|
||||
//
|
||||
// PRAW_PATH_ENTRY
|
||||
// CdRawPathEntry (
|
||||
// IN PIRP_CONTEXT IrpContext,
|
||||
// IN PPATH_ENUM_CONTEXT PathContext
|
||||
// );
|
||||
//
|
||||
|
||||
#define CdRawPathEntry(IC, PC) \
|
||||
Add2Ptr( (PC)->Data, (PC)->DataOffset, PRAW_PATH_ENTRY )
|
||||
|
||||
//
|
||||
// Local support routines
|
||||
//
|
||||
|
||||
VOID
|
||||
CdMapPathTableBlock (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN LONGLONG BaseOffset,
|
||||
IN OUT PPATH_ENUM_CONTEXT PathContext
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
CdUpdatePathEntryFromRawPathEntry (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN ULONG Ordinal,
|
||||
IN BOOLEAN VerifyBounds,
|
||||
IN PPATH_ENUM_CONTEXT PathContext,
|
||||
OUT PPATH_ENTRY PathEntry
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdFindPathEntry)
|
||||
#pragma alloc_text(PAGE, CdLookupPathEntry)
|
||||
#pragma alloc_text(PAGE, CdLookupNextPathEntry)
|
||||
#pragma alloc_text(PAGE, CdMapPathTableBlock)
|
||||
#pragma alloc_text(PAGE, CdUpdatePathEntryFromRawPathEntry)
|
||||
#pragma alloc_text(PAGE, CdUpdatePathEntryName)
|
||||
#endif
|
||||
|
||||
|
||||
VOID
|
||||
CdLookupPathEntry (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN ULONG PathEntryOffset,
|
||||
IN ULONG Ordinal,
|
||||
IN BOOLEAN VerifyBounds,
|
||||
IN OUT PCOMPOUND_PATH_ENTRY CompoundPathEntry
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to initiate a walk through a path table. We are
|
||||
looking for a path table entry at location PathEntryOffset.
|
||||
|
||||
Arguments:
|
||||
|
||||
PathEntryOffset - This is our target point in the Path Table. We know that
|
||||
a path entry must begin at this point although we may have to verify
|
||||
the bounds.
|
||||
|
||||
Ordinal - Ordinal number for the directory at the PathEntryOffset above.
|
||||
|
||||
VerifyBounds - Indicates whether we need to check the validity of
|
||||
this entry.
|
||||
|
||||
CompoundPathEntry - PathEnumeration context and in-memory path entry. This
|
||||
has been initialized outside of this call.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PPATH_ENUM_CONTEXT PathContext = &CompoundPathEntry->PathContext;
|
||||
LONGLONG CurrentBaseOffset;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Compute the starting base and starting path table offset.
|
||||
//
|
||||
|
||||
CurrentBaseOffset = SectorTruncate( PathEntryOffset );
|
||||
|
||||
//
|
||||
// Map the next block in the Path Table.
|
||||
//
|
||||
|
||||
CdMapPathTableBlock( IrpContext,
|
||||
IrpContext->Vcb->PathTableFcb,
|
||||
CurrentBaseOffset,
|
||||
PathContext );
|
||||
|
||||
//
|
||||
// Set up our current offset into the Path Context.
|
||||
//
|
||||
|
||||
PathContext->DataOffset = PathEntryOffset - PathContext->BaseOffset;
|
||||
|
||||
//
|
||||
// Update the in-memory structure for this path entry.
|
||||
//
|
||||
|
||||
(VOID) CdUpdatePathEntryFromRawPathEntry( IrpContext,
|
||||
Ordinal,
|
||||
VerifyBounds,
|
||||
&CompoundPathEntry->PathContext,
|
||||
&CompoundPathEntry->PathEntry );
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdLookupNextPathEntry (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN OUT PPATH_ENUM_CONTEXT PathContext,
|
||||
IN OUT PPATH_ENTRY PathEntry
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to move to the next path table entry. We know
|
||||
the offset and the length of the current entry. We start by computing
|
||||
the offset of the next entry and determine if it is contained in the
|
||||
table. Then we check to see if we need to move to the next sector in
|
||||
the path table. We always map two sectors at a time so we don't
|
||||
have to deal with any path entries which span sectors. We move to
|
||||
the next sector if we are in the second sector of the current mapped
|
||||
data block.
|
||||
|
||||
We look up the next entry and update the path entry structure with
|
||||
the values out of the raw sector but don't update the CdName structure.
|
||||
|
||||
Arguments:
|
||||
|
||||
PathContext - Enumeration context for this scan of the path table.
|
||||
|
||||
PathEntry - In-memory representation of the on-disk path table entry.
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - TRUE if another entry is found, FALSE otherwise.
|
||||
This routine may raise on error.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
LONGLONG CurrentBaseOffset;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Get the offset of the next path entry within the current
|
||||
// data block.
|
||||
//
|
||||
|
||||
PathContext->DataOffset += PathEntry->PathEntryLength;
|
||||
|
||||
//
|
||||
// If we are in the last data block then check if we are beyond the
|
||||
// end of the file.
|
||||
//
|
||||
|
||||
if (PathContext->LastDataBlock) {
|
||||
|
||||
if (PathContext->DataOffset >= PathContext->DataLength) {
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// If we are not in the last data block of the path table and
|
||||
// this offset is in the second sector then move to the next
|
||||
// data block.
|
||||
//
|
||||
|
||||
} else if (PathContext->DataOffset >= SECTOR_SIZE) {
|
||||
|
||||
CurrentBaseOffset = PathContext->BaseOffset + SECTOR_SIZE;
|
||||
|
||||
CdMapPathTableBlock( IrpContext,
|
||||
IrpContext->Vcb->PathTableFcb,
|
||||
CurrentBaseOffset,
|
||||
PathContext );
|
||||
|
||||
//
|
||||
// Set up our current offset into the Path Context.
|
||||
//
|
||||
|
||||
PathContext->DataOffset -= SECTOR_SIZE;
|
||||
}
|
||||
|
||||
//
|
||||
// Now update the path entry with the values from the on-disk
|
||||
// structure.
|
||||
//
|
||||
|
||||
return CdUpdatePathEntryFromRawPathEntry( IrpContext,
|
||||
PathEntry->Ordinal + 1,
|
||||
TRUE,
|
||||
PathContext,
|
||||
PathEntry );
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdFindPathEntry (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB ParentFcb,
|
||||
IN PCD_NAME DirName,
|
||||
IN BOOLEAN IgnoreCase,
|
||||
IN OUT PCOMPOUND_PATH_ENTRY CompoundPathEntry
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine will walk through the path table looking for a matching entry for DirName
|
||||
among the child directories of the ParentFcb.
|
||||
|
||||
Arguments:
|
||||
|
||||
ParentFcb - This is the directory we are examining. We know the ordinal and path table
|
||||
offset for this directory in the path table. If this is the first scan for this
|
||||
Fcb we will update the first child offset for this directory in the path table.
|
||||
|
||||
DirName - This is the name we are searching for. This name will not contain wildcard
|
||||
characters. The name will also not have a version string.
|
||||
|
||||
IgnoreCase - Indicates if this search is exact or ignore case.
|
||||
|
||||
CompoundPathEntry - Complete path table enumeration structure. We will have initialized
|
||||
it for the search on entry. This will be positioned at the matching name if found.
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - TRUE if matching entry found, FALSE otherwise.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
BOOLEAN Found = FALSE;
|
||||
BOOLEAN UpdateChildOffset = TRUE;
|
||||
|
||||
ULONG StartingOffset;
|
||||
ULONG StartingOrdinal;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Position ourselves at either the first child or at the directory itself.
|
||||
// Lock the Fcb to get this value and remember whether to update with the first
|
||||
// child.
|
||||
//
|
||||
|
||||
StartingOffset = CdQueryFidPathTableOffset( ParentFcb->FileId );
|
||||
StartingOrdinal = ParentFcb->Ordinal;
|
||||
|
||||
//
|
||||
// ISO 9660 9.4.4 restricts the backpointer from child to parent in a
|
||||
// pathtable entry to 16bits. Although we internally store ordinals
|
||||
// as 32bit values, it is impossible to search for the children of a
|
||||
// directory whose ordinal value is greater than MAXUSHORT. Media that
|
||||
// could induce such a search is illegal.
|
||||
//
|
||||
// Note that it is not illegal to have more than MAXUSHORT directories.
|
||||
//
|
||||
|
||||
if (ParentFcb->Ordinal > MAXUSHORT) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
|
||||
}
|
||||
|
||||
CdLockFcb( IrpContext, ParentFcb );
|
||||
|
||||
if (ParentFcb->ChildPathTableOffset != 0) {
|
||||
|
||||
StartingOffset = ParentFcb->ChildPathTableOffset;
|
||||
StartingOrdinal = ParentFcb->ChildOrdinal;
|
||||
UpdateChildOffset = FALSE;
|
||||
|
||||
} else if (ParentFcb == ParentFcb->Vcb->RootIndexFcb) {
|
||||
|
||||
UpdateChildOffset = FALSE;
|
||||
}
|
||||
|
||||
CdUnlockFcb( IrpContext, ParentFcb );
|
||||
|
||||
CdLookupPathEntry( IrpContext, StartingOffset, StartingOrdinal, FALSE, CompoundPathEntry );
|
||||
|
||||
//
|
||||
// Loop until we find a match or are beyond the children for this directory.
|
||||
//
|
||||
|
||||
do {
|
||||
|
||||
//
|
||||
// If we are beyond this directory then return FALSE.
|
||||
//
|
||||
|
||||
if (CompoundPathEntry->PathEntry.ParentOrdinal > ParentFcb->Ordinal) {
|
||||
|
||||
//
|
||||
// Update the Fcb with the offsets for the children in the path table.
|
||||
//
|
||||
|
||||
if (UpdateChildOffset) {
|
||||
|
||||
CdLockFcb( IrpContext, ParentFcb );
|
||||
|
||||
ParentFcb->ChildPathTableOffset = StartingOffset;
|
||||
ParentFcb->ChildOrdinal = StartingOrdinal;
|
||||
|
||||
CdUnlockFcb( IrpContext, ParentFcb );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// If we are within the children of this directory then check for a match.
|
||||
//
|
||||
|
||||
if (CompoundPathEntry->PathEntry.ParentOrdinal == ParentFcb->Ordinal) {
|
||||
|
||||
//
|
||||
// Update the child offset if not yet done.
|
||||
//
|
||||
|
||||
if (UpdateChildOffset) {
|
||||
|
||||
CdLockFcb( IrpContext, ParentFcb );
|
||||
|
||||
ParentFcb->ChildPathTableOffset = CompoundPathEntry->PathEntry.PathTableOffset;
|
||||
ParentFcb->ChildOrdinal = CompoundPathEntry->PathEntry.Ordinal;
|
||||
|
||||
CdUnlockFcb( IrpContext, ParentFcb );
|
||||
|
||||
UpdateChildOffset = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the name in the path entry.
|
||||
//
|
||||
|
||||
CdUpdatePathEntryName( IrpContext, &CompoundPathEntry->PathEntry, IgnoreCase );
|
||||
|
||||
//
|
||||
// Now compare the names for an exact match.
|
||||
//
|
||||
|
||||
if (CdIsNameInExpression( IrpContext,
|
||||
&CompoundPathEntry->PathEntry.CdCaseDirName,
|
||||
DirName,
|
||||
0,
|
||||
FALSE )) {
|
||||
|
||||
//
|
||||
// Let our caller know we have a match.
|
||||
//
|
||||
|
||||
Found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Go to the next entry in the path table. Remember the current position
|
||||
// in the event we update the Fcb.
|
||||
//
|
||||
|
||||
StartingOffset = CompoundPathEntry->PathEntry.PathTableOffset;
|
||||
StartingOrdinal = CompoundPathEntry->PathEntry.Ordinal;
|
||||
|
||||
} while (CdLookupNextPathEntry( IrpContext,
|
||||
&CompoundPathEntry->PathContext,
|
||||
&CompoundPathEntry->PathEntry ));
|
||||
|
||||
return Found;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
VOID
|
||||
CdMapPathTableBlock (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN LONGLONG BaseOffset,
|
||||
IN OUT PPATH_ENUM_CONTEXT PathContext
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to map (or allocate and copy) the next
|
||||
data block in the path table. We check if the next block will
|
||||
span a view boundary and allocate an auxilary buffer in that case.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - This is the Fcb for the Path Table.
|
||||
|
||||
BaseOffset - Offset of the first sector to map. This will be on a
|
||||
sector boundary.
|
||||
|
||||
PathContext - Enumeration context to update in this routine.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ULONG CurrentLength;
|
||||
ULONG SectorSize;
|
||||
ULONG DataOffset;
|
||||
ULONG PassCount;
|
||||
PVOID Sector;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Map the new block and set the enumeration context to this
|
||||
// point. Allocate an auxilary buffer if necessary.
|
||||
//
|
||||
|
||||
CurrentLength = 2 * SECTOR_SIZE;
|
||||
|
||||
if (CurrentLength >= (ULONG) (Fcb->FileSize.QuadPart - BaseOffset)) {
|
||||
|
||||
CurrentLength = (ULONG) (Fcb->FileSize.QuadPart - BaseOffset);
|
||||
|
||||
//
|
||||
// We know this is the last data block for this
|
||||
// path table.
|
||||
//
|
||||
|
||||
PathContext->LastDataBlock = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Set context values.
|
||||
//
|
||||
|
||||
PathContext->BaseOffset = (ULONG) BaseOffset;
|
||||
PathContext->DataLength = CurrentLength;
|
||||
|
||||
//
|
||||
// Drop the previous sector's mapping
|
||||
//
|
||||
|
||||
CdUnpinData( IrpContext, &PathContext->Bcb );
|
||||
|
||||
//
|
||||
// Check if spanning a view section. The following must
|
||||
// be true before we take this step.
|
||||
//
|
||||
// Data length is more than one sector.
|
||||
// Starting offset must be one sector before the
|
||||
// cache manager VACB boundary.
|
||||
//
|
||||
|
||||
if ((CurrentLength > SECTOR_SIZE) &&
|
||||
(FlagOn( ((ULONG) BaseOffset), VACB_MAPPING_MASK ) == LAST_VACB_SECTOR_OFFSET )) {
|
||||
|
||||
//
|
||||
// Map each sector individually and store into an auxilary
|
||||
// buffer.
|
||||
//
|
||||
|
||||
SectorSize = SECTOR_SIZE;
|
||||
DataOffset = 0;
|
||||
PassCount = 2;
|
||||
|
||||
PathContext->Data = FsRtlAllocatePoolWithTag( CdPagedPool,
|
||||
CurrentLength,
|
||||
TAG_SPANNING_PATH_TABLE );
|
||||
PathContext->AllocatedData = TRUE;
|
||||
|
||||
while (PassCount--) {
|
||||
|
||||
CcMapData( Fcb->FileObject,
|
||||
(PLARGE_INTEGER) &BaseOffset,
|
||||
SectorSize,
|
||||
TRUE,
|
||||
&PathContext->Bcb,
|
||||
&Sector );
|
||||
|
||||
RtlCopyMemory( Add2Ptr( PathContext->Data, DataOffset, PVOID ),
|
||||
Sector,
|
||||
SectorSize );
|
||||
|
||||
CdUnpinData( IrpContext, &PathContext->Bcb );
|
||||
|
||||
BaseOffset += SECTOR_SIZE;
|
||||
SectorSize = CurrentLength - SECTOR_SIZE;
|
||||
DataOffset = SECTOR_SIZE;
|
||||
}
|
||||
|
||||
//
|
||||
// Otherwise we can just map the data into the cache.
|
||||
//
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// There is a slight chance that we have allocated an
|
||||
// auxilary buffer on the previous sector.
|
||||
//
|
||||
|
||||
if (PathContext->AllocatedData) {
|
||||
|
||||
CdFreePool( &PathContext->Data );
|
||||
PathContext->AllocatedData = FALSE;
|
||||
}
|
||||
|
||||
CcMapData( Fcb->FileObject,
|
||||
(PLARGE_INTEGER) &BaseOffset,
|
||||
CurrentLength,
|
||||
TRUE,
|
||||
&PathContext->Bcb,
|
||||
&PathContext->Data );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
BOOLEAN
|
||||
CdUpdatePathEntryFromRawPathEntry (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN ULONG Ordinal,
|
||||
IN BOOLEAN VerifyBounds,
|
||||
IN PPATH_ENUM_CONTEXT PathContext,
|
||||
OUT PPATH_ENTRY PathEntry
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to update the in-memory Path Entry from the on-disk
|
||||
path entry. We also do a careful check of the bounds if requested and we
|
||||
are in the last data block of the path table.
|
||||
|
||||
Arguments:
|
||||
|
||||
Ordinal - Ordinal number for this directory.
|
||||
|
||||
VerifyBounds - Check that the current raw Path Entry actually fits
|
||||
within the data block.
|
||||
|
||||
PathContext - Current path table enumeration context.
|
||||
|
||||
PathEntry - Pointer to the in-memory path entry structure.
|
||||
|
||||
Return Value:
|
||||
|
||||
TRUE if updated ok,
|
||||
FALSE if we've hit the end of the pathtable - zero name length && PT size is a multiple
|
||||
of blocksize. This is a workaround for some Video CDs. Win 9x works around this.
|
||||
|
||||
This routine may raise.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PRAW_PATH_ENTRY RawPathEntry = CdRawPathEntry( IrpContext, PathContext );
|
||||
ULONG RemainingDataLength;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Check for a name length of zero. This is the first byte of the record,
|
||||
// and there must be at least one byte remaining in the buffer else we
|
||||
// wouldn't be here (caller would have spotted buffer end).
|
||||
//
|
||||
|
||||
PathEntry->DirNameLen = CdRawPathIdLen( IrpContext, RawPathEntry );
|
||||
|
||||
if (0 == PathEntry->DirNameLen) {
|
||||
|
||||
//
|
||||
// If we are in the last block, and the path table size (ie last block) is a
|
||||
// multiple of block size, then we will consider this the end of the path table
|
||||
// rather than raising an error. Workaround for NTI Cd Maker video CDs which
|
||||
// round path table length to blocksize multiple. In all other cases we consider
|
||||
// a zero length name to be corruption.
|
||||
//
|
||||
|
||||
if ( PathContext->LastDataBlock &&
|
||||
(0 == BlockOffset( IrpContext->Vcb, PathContext->DataLength))) {
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
|
||||
}
|
||||
|
||||
//
|
||||
// Check if we should verify the path entry. If we are not in the last
|
||||
// data block then there is nothing to check.
|
||||
//
|
||||
|
||||
if (PathContext->LastDataBlock && VerifyBounds) {
|
||||
|
||||
//
|
||||
// Quick check to see if the maximum size is still available. This
|
||||
// will handle most cases and we don't need to access any of the
|
||||
// fields.
|
||||
//
|
||||
|
||||
RemainingDataLength = PathContext->DataLength - PathContext->DataOffset;
|
||||
|
||||
if (RemainingDataLength < sizeof( RAW_PATH_ENTRY )) {
|
||||
|
||||
//
|
||||
// Make sure the remaining bytes hold the path table entries.
|
||||
// Do the following checks.
|
||||
//
|
||||
// - A minimal path table entry will fit (and then check)
|
||||
// - This path table entry (with dir name) will fit.
|
||||
//
|
||||
|
||||
if ((RemainingDataLength < MIN_RAW_PATH_ENTRY_LEN) ||
|
||||
(RemainingDataLength < (ULONG) (CdRawPathIdLen( IrpContext, RawPathEntry ) + MIN_RAW_PATH_ENTRY_LEN - 1))) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The ordinal number of this directory is passed in.
|
||||
// Compute the path table offset of this entry.
|
||||
//
|
||||
|
||||
PathEntry->Ordinal = Ordinal;
|
||||
PathEntry->PathTableOffset = PathContext->BaseOffset + PathContext->DataOffset;
|
||||
|
||||
//
|
||||
// We know we can safely access all of the fields of the raw path table at
|
||||
// this point.
|
||||
|
||||
//
|
||||
// Bias the disk offset by the number of logical blocks
|
||||
//
|
||||
|
||||
CopyUchar4( &PathEntry->DiskOffset, CdRawPathLoc( IrpContext, RawPathEntry ));
|
||||
|
||||
PathEntry->DiskOffset += CdRawPathXar( IrpContext, RawPathEntry );
|
||||
|
||||
CopyUchar2( &PathEntry->ParentOrdinal, &RawPathEntry->ParentNum );
|
||||
|
||||
PathEntry->PathEntryLength = PathEntry->DirNameLen + MIN_RAW_PATH_ENTRY_LEN - 1;
|
||||
|
||||
//
|
||||
// Align the path entry length on a ushort boundary.
|
||||
//
|
||||
|
||||
PathEntry->PathEntryLength = WordAlign( PathEntry->PathEntryLength );
|
||||
|
||||
PathEntry->DirName = RawPathEntry->DirId;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
VOID
|
||||
CdUpdatePathEntryName (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN OUT PPATH_ENTRY PathEntry,
|
||||
IN BOOLEAN IgnoreCase
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine will store the directory name into the CdName in the
|
||||
path entry. If this is a Joliet name then we will make sure we have
|
||||
an allocated buffer and need to convert from big endian to little
|
||||
endian. We also correctly update the case name. If this operation is ignore
|
||||
case then we need an auxilary buffer for the name.
|
||||
|
||||
For an Ansi disk we can use the name from the disk for the exact case. We only
|
||||
need to allocate a buffer for the ignore case name. The on-disk representation of
|
||||
a Unicode name is useless for us. In this case we will need a name buffer for
|
||||
both names. We store a buffer in the PathEntry which can hold two 8.3 unicode
|
||||
names. This means we will almost never need to allocate a buffer in the Ansi case
|
||||
(we only need one buffer and already have 48 characters).
|
||||
|
||||
Arguments:
|
||||
|
||||
PathEntry - Pointer to a path entry structure. We have already updated
|
||||
this path entry with the values from the raw path entry.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ULONG Length;
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Check if this is a self entry. We use a fixed string for this.
|
||||
//
|
||||
// Self-Entry - Length is 1, value is 0.
|
||||
//
|
||||
|
||||
if ((*PathEntry->DirName == 0) &&
|
||||
(PathEntry->DirNameLen == 1)) {
|
||||
|
||||
//
|
||||
// There should be no allocated buffers.
|
||||
//
|
||||
|
||||
ASSERT( !FlagOn( PathEntry->Flags, PATH_ENTRY_FLAG_ALLOC_BUFFER ));
|
||||
|
||||
//
|
||||
// Now use one of the hard coded directory names.
|
||||
//
|
||||
|
||||
PathEntry->CdDirName.FileName = CdUnicodeDirectoryNames[0];
|
||||
|
||||
//
|
||||
// Show that there is no version number.
|
||||
//
|
||||
|
||||
PathEntry->CdDirName.VersionString.Length = 0;
|
||||
|
||||
//
|
||||
// The case name is identical.
|
||||
//
|
||||
|
||||
PathEntry->CdCaseDirName = PathEntry->CdDirName;
|
||||
|
||||
//
|
||||
// Return now.
|
||||
//
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Compute how large a buffer we will need. If this is an ignore
|
||||
// case operation then we will want a double size buffer. If the disk is not
|
||||
// a Joliet disk then we might need two bytes for each byte in the name.
|
||||
//
|
||||
|
||||
Length = PathEntry->DirNameLen;
|
||||
|
||||
if (IgnoreCase) {
|
||||
|
||||
Length *= 2;
|
||||
}
|
||||
|
||||
if (!FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_JOLIET )) {
|
||||
|
||||
Length *= sizeof( WCHAR );
|
||||
}
|
||||
|
||||
//
|
||||
// Now decide if we need to allocate a new buffer. We will if
|
||||
// this name won't fit in the embedded name buffer and it is
|
||||
// larger than the current allocated buffer. We always use the
|
||||
// allocated buffer if present.
|
||||
//
|
||||
// If we haven't allocated a buffer then use the embedded buffer if the data
|
||||
// will fit. This is the typical case.
|
||||
//
|
||||
|
||||
if (!FlagOn( PathEntry->Flags, PATH_ENTRY_FLAG_ALLOC_BUFFER ) &&
|
||||
(Length <= sizeof( PathEntry->NameBuffer ))) {
|
||||
|
||||
PathEntry->CdDirName.FileName.MaximumLength = sizeof( PathEntry->NameBuffer );
|
||||
PathEntry->CdDirName.FileName.Buffer = PathEntry->NameBuffer;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// We need to use an allocated buffer. Check if the current buffer
|
||||
// is large enough.
|
||||
//
|
||||
|
||||
if (Length > PathEntry->CdDirName.FileName.MaximumLength) {
|
||||
|
||||
//
|
||||
// Free any allocated buffer.
|
||||
//
|
||||
|
||||
if (FlagOn( PathEntry->Flags, PATH_ENTRY_FLAG_ALLOC_BUFFER )) {
|
||||
|
||||
CdFreePool( &PathEntry->CdDirName.FileName.Buffer );
|
||||
ClearFlag( PathEntry->Flags, PATH_ENTRY_FLAG_ALLOC_BUFFER );
|
||||
}
|
||||
|
||||
PathEntry->CdDirName.FileName.Buffer = FsRtlAllocatePoolWithTag( CdPagedPool,
|
||||
Length,
|
||||
TAG_PATH_ENTRY_NAME );
|
||||
|
||||
SetFlag( PathEntry->Flags, PATH_ENTRY_FLAG_ALLOC_BUFFER );
|
||||
|
||||
PathEntry->CdDirName.FileName.MaximumLength = (USHORT) Length;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// We now have a buffer for the name. We need to either convert the on-disk bigendian
|
||||
// to little endian or covert the name to Unicode.
|
||||
//
|
||||
|
||||
if (!FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_JOLIET )) {
|
||||
|
||||
Status = RtlOemToUnicodeN( PathEntry->CdDirName.FileName.Buffer,
|
||||
PathEntry->CdDirName.FileName.MaximumLength,
|
||||
&Length,
|
||||
PathEntry->DirName,
|
||||
PathEntry->DirNameLen );
|
||||
|
||||
ASSERT( Status == STATUS_SUCCESS );
|
||||
PathEntry->CdDirName.FileName.Length = (USHORT) Length;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Convert this string to little endian.
|
||||
//
|
||||
|
||||
CdConvertBigToLittleEndian( IrpContext,
|
||||
PathEntry->DirName,
|
||||
PathEntry->DirNameLen,
|
||||
(PCHAR) PathEntry->CdDirName.FileName.Buffer );
|
||||
|
||||
PathEntry->CdDirName.FileName.Length = (USHORT) PathEntry->DirNameLen;
|
||||
}
|
||||
|
||||
//
|
||||
// There is no version string.
|
||||
//
|
||||
|
||||
PathEntry->CdDirName.VersionString.Length =
|
||||
PathEntry->CdCaseDirName.VersionString.Length = 0;
|
||||
|
||||
//
|
||||
// If the name string ends with a period then knock off the last
|
||||
// character.
|
||||
//
|
||||
|
||||
if (PathEntry->CdDirName.FileName.Buffer[(PathEntry->CdDirName.FileName.Length - sizeof( WCHAR )) / 2] == L'.') {
|
||||
|
||||
//
|
||||
// Shrink the filename length.
|
||||
//
|
||||
|
||||
PathEntry->CdDirName.FileName.Length -= sizeof( WCHAR );
|
||||
}
|
||||
|
||||
//
|
||||
// Update the case name buffer if necessary. If this is an exact case
|
||||
// operation then just copy the exact case string.
|
||||
//
|
||||
|
||||
if (IgnoreCase) {
|
||||
|
||||
PathEntry->CdCaseDirName.FileName.Buffer = Add2Ptr( PathEntry->CdDirName.FileName.Buffer,
|
||||
PathEntry->CdDirName.FileName.MaximumLength / 2,
|
||||
PWCHAR);
|
||||
|
||||
PathEntry->CdCaseDirName.FileName.MaximumLength = PathEntry->CdDirName.FileName.MaximumLength / 2;
|
||||
|
||||
CdUpcaseName( IrpContext,
|
||||
&PathEntry->CdDirName,
|
||||
&PathEntry->CdCaseDirName );
|
||||
|
||||
} else {
|
||||
|
||||
PathEntry->CdCaseDirName = PathEntry->CdDirName;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Executable
+793
@@ -0,0 +1,793 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1997-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
Pnp.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the Plug and Play routines for CDFS called by
|
||||
the dispatch driver.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_PNP)
|
||||
|
||||
NTSTATUS
|
||||
CdPnpQueryRemove (
|
||||
PIRP_CONTEXT IrpContext,
|
||||
PIRP Irp,
|
||||
PVCB Vcb
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdPnpRemove (
|
||||
PIRP_CONTEXT IrpContext,
|
||||
PIRP Irp,
|
||||
PVCB Vcb
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdPnpSurpriseRemove (
|
||||
PIRP_CONTEXT IrpContext,
|
||||
PIRP Irp,
|
||||
PVCB Vcb
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdPnpCancelRemove (
|
||||
PIRP_CONTEXT IrpContext,
|
||||
PIRP Irp,
|
||||
PVCB Vcb
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdPnpCompletionRoutine (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Contxt
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdCommonPnp)
|
||||
#pragma alloc_text(PAGE, CdPnpCancelRemove)
|
||||
#pragma alloc_text(PAGE, CdPnpQueryRemove)
|
||||
#pragma alloc_text(PAGE, CdPnpRemove)
|
||||
#pragma alloc_text(PAGE, CdPnpSurpriseRemove)
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdCommonPnp (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the common routine for doing PnP operations called
|
||||
by both the fsd and fsp threads
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Supplies the Irp to process
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The return status for the operation
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
BOOLEAN PassThrough = FALSE;
|
||||
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
PVOLUME_DEVICE_OBJECT OurDeviceObject;
|
||||
PVCB Vcb;
|
||||
|
||||
//
|
||||
// Get the current Irp stack location.
|
||||
//
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
//
|
||||
// Find our Vcb. This is tricky since we have no file object in the Irp.
|
||||
//
|
||||
|
||||
OurDeviceObject = (PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject;
|
||||
|
||||
//
|
||||
// IO holds a handle reference on our VDO and holds the device lock, which
|
||||
// syncs us against mounts/verifies. However we hold no reference on the
|
||||
// volume, which may already have been torn down (and the Vpb freed), for
|
||||
// example by a force dismount. Check for this condition. We must hold this
|
||||
// lock until the pnp worker functions take additional locks/refs on the Vcb.
|
||||
//
|
||||
|
||||
CdAcquireCdData( IrpContext);
|
||||
|
||||
//
|
||||
// Make sure this device object really is big enough to be a volume device
|
||||
// object. If it isn't, we need to get out before we try to reference some
|
||||
// field that takes us past the end of an ordinary device object.
|
||||
//
|
||||
|
||||
if (OurDeviceObject->DeviceObject.Size != sizeof(VOLUME_DEVICE_OBJECT) ||
|
||||
NodeType( &OurDeviceObject->Vcb ) != CDFS_NTC_VCB) {
|
||||
|
||||
//
|
||||
// We were called with something we don't understand.
|
||||
//
|
||||
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
CdReleaseCdData( IrpContext);
|
||||
CdCompleteRequest( IrpContext, Irp, Status );
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Force all PnP operations to be synchronous.
|
||||
//
|
||||
|
||||
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
|
||||
|
||||
Vcb = &OurDeviceObject->Vcb;
|
||||
|
||||
//
|
||||
// Check that the Vcb hasn't already been deleted. If so, just pass the
|
||||
// request through to the driver below, we don't need to do anything.
|
||||
//
|
||||
|
||||
if (NULL == Vcb->Vpb) {
|
||||
|
||||
PassThrough = TRUE;
|
||||
}
|
||||
else {
|
||||
|
||||
//
|
||||
// Case on the minor code.
|
||||
//
|
||||
|
||||
switch ( IrpSp->MinorFunction ) {
|
||||
|
||||
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||||
|
||||
Status = CdPnpQueryRemove( IrpContext, Irp, Vcb );
|
||||
break;
|
||||
|
||||
case IRP_MN_SURPRISE_REMOVAL:
|
||||
|
||||
Status = CdPnpSurpriseRemove( IrpContext, Irp, Vcb );
|
||||
break;
|
||||
|
||||
case IRP_MN_REMOVE_DEVICE:
|
||||
|
||||
Status = CdPnpRemove( IrpContext, Irp, Vcb );
|
||||
break;
|
||||
|
||||
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
||||
|
||||
Status = CdPnpCancelRemove( IrpContext, Irp, Vcb );
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
PassThrough = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (PassThrough) {
|
||||
|
||||
CdReleaseCdData( IrpContext);
|
||||
|
||||
//
|
||||
// Just pass the IRP on. As we do not need to be in the
|
||||
// way on return, ellide ourselves out of the stack.
|
||||
//
|
||||
|
||||
IoSkipCurrentIrpStackLocation( Irp );
|
||||
|
||||
Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
|
||||
|
||||
//
|
||||
// Cleanup our Irp Context. The driver has completed the Irp.
|
||||
//
|
||||
|
||||
CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdPnpQueryRemove (
|
||||
PIRP_CONTEXT IrpContext,
|
||||
PIRP Irp,
|
||||
PVCB Vcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine handles the PnP query remove operation. The filesystem
|
||||
is responsible for answering whether there are any reasons it sees
|
||||
that the volume can not go away (and the device removed). Initiation
|
||||
of the dismount begins when we answer yes to this question.
|
||||
|
||||
Query will be followed by a Cancel or Remove.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Supplies the Irp to process
|
||||
|
||||
Vcb - Supplies the volume being queried.
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The return status for the operation
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
KEVENT Event;
|
||||
BOOLEAN VcbPresent = TRUE;
|
||||
|
||||
ASSERT_EXCLUSIVE_CDDATA;
|
||||
|
||||
//
|
||||
// Having said yes to a QUERY, any communication with the
|
||||
// underlying storage stack is undefined (and may block)
|
||||
// until the bounding CANCEL or REMOVE is sent.
|
||||
//
|
||||
// Acquire the global resource so that we can try to vaporize the volume,
|
||||
// and the vcb resource itself.
|
||||
//
|
||||
|
||||
CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
|
||||
|
||||
//
|
||||
// Drop a reference on the Vcb to keep it around after we drop the locks.
|
||||
//
|
||||
|
||||
CdLockVcb( IrpContext, Vcb);
|
||||
Vcb->VcbReference += 1;
|
||||
CdUnlockVcb( IrpContext, Vcb);
|
||||
|
||||
CdReleaseCdData( IrpContext);
|
||||
|
||||
Status = CdLockVolumeInternal( IrpContext, Vcb, NULL );
|
||||
|
||||
//
|
||||
// Reacquire the global lock, which means dropping the Vcb resource.
|
||||
//
|
||||
|
||||
CdReleaseVcb( IrpContext, Vcb );
|
||||
|
||||
CdAcquireCdData( IrpContext );
|
||||
CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
|
||||
|
||||
//
|
||||
// Remove our extra reference.
|
||||
//
|
||||
|
||||
CdLockVcb( IrpContext, Vcb);
|
||||
Vcb->VcbReference -= 1;
|
||||
CdUnlockVcb( IrpContext, Vcb);
|
||||
|
||||
if (NT_SUCCESS( Status )) {
|
||||
|
||||
//
|
||||
// We need to pass this down before starting the dismount, which
|
||||
// could disconnect us immediately from the stack.
|
||||
//
|
||||
|
||||
//
|
||||
// Get the next stack location, and copy over the stack location
|
||||
//
|
||||
|
||||
IoCopyCurrentIrpStackLocationToNext( Irp );
|
||||
|
||||
//
|
||||
// Set up the completion routine
|
||||
//
|
||||
|
||||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||||
IoSetCompletionRoutine( Irp,
|
||||
CdPnpCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
//
|
||||
// Send the request and wait.
|
||||
//
|
||||
|
||||
Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
|
||||
KeWaitForSingleObject( &Event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL );
|
||||
|
||||
Status = Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Now if no one below us failed already, initiate the dismount
|
||||
// on this volume, make it go away. PnP needs to see our internal
|
||||
// streams close and drop their references to the target device.
|
||||
//
|
||||
// Since we were able to lock the volume, we are guaranteed to
|
||||
// move this volume into dismount state and disconnect it from
|
||||
// the underlying storage stack. The force on our part is actually
|
||||
// unnecesary, though complete.
|
||||
//
|
||||
// What is not strictly guaranteed, though, is that the closes
|
||||
// for the metadata streams take effect synchronously underneath
|
||||
// of this call. This would leave references on the target device
|
||||
// even though we are disconnected!
|
||||
//
|
||||
|
||||
if (NT_SUCCESS( Status )) {
|
||||
|
||||
VcbPresent = CdCheckForDismount( IrpContext, Vcb, TRUE );
|
||||
|
||||
ASSERT( !VcbPresent || Vcb->VcbCondition == VcbDismountInProgress );
|
||||
}
|
||||
|
||||
//
|
||||
// Note: Normally everything will complete and the internal streams will
|
||||
// vaporise. However there is some code in the system which drops additional
|
||||
// references on fileobjects, including our internal stream file objects,
|
||||
// for (WMI) tracing purposes. If that happens to run concurrently with our
|
||||
// teardown, our internal streams will not vaporise until those references
|
||||
// are removed. So it's possible that the volume still remains at this
|
||||
// point. The pnp query remove will fail due to our references on the device.
|
||||
// To be cleaner we will return an error here. We could pend the pnp
|
||||
// IRP until the volume goes away, but since we don't know when that will
|
||||
// be, and this is a very rare case, we'll just fail the query.
|
||||
//
|
||||
// The reason this is the case is that handles/fileobjects place a reference
|
||||
// on the device objects they overly. In the filesystem case, these references
|
||||
// are on our target devices. PnP correcly thinks that if references remain
|
||||
// on the device objects in the stack that someone has a handle, and that this
|
||||
// counts as a reason to not succeed the query - even though every interrogated
|
||||
// driver thinks that it is OK.
|
||||
//
|
||||
|
||||
if (NT_SUCCESS( Status) && VcbPresent && (Vcb->VcbReference != 0)) {
|
||||
|
||||
Status = STATUS_DEVICE_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Release the Vcb if it could still remain.
|
||||
//
|
||||
|
||||
if (VcbPresent) {
|
||||
|
||||
CdReleaseVcb( IrpContext, Vcb );
|
||||
}
|
||||
|
||||
CdReleaseCdData( IrpContext );
|
||||
|
||||
//
|
||||
// Cleanup our IrpContext and complete the IRP if neccesary.
|
||||
//
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, Status );
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdPnpRemove (
|
||||
PIRP_CONTEXT IrpContext,
|
||||
PIRP Irp,
|
||||
PVCB Vcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine handles the PnP remove operation. This is our notification
|
||||
that the underlying storage device for the volume we have is gone, and
|
||||
an excellent indication that the volume will never reappear. The filesystem
|
||||
is responsible for initiation or completion the dismount.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Supplies the Irp to process
|
||||
|
||||
Vcb - Supplies the volume being removed.
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The return status for the operation
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
KEVENT Event;
|
||||
BOOLEAN VcbPresent = TRUE;
|
||||
|
||||
ASSERT_EXCLUSIVE_CDDATA;
|
||||
|
||||
//
|
||||
// REMOVE - a storage device is now gone. We either got
|
||||
// QUERY'd and said yes OR got a SURPRISE OR a storage
|
||||
// stack failed to spin back up from a sleep/stop state
|
||||
// (the only case in which this will be the first warning).
|
||||
//
|
||||
// Note that it is entirely unlikely that we will be around
|
||||
// for a REMOVE in the first two cases, as we try to intiate
|
||||
// dismount.
|
||||
//
|
||||
|
||||
//
|
||||
// Acquire the global resource so that we can try to vaporize
|
||||
// the volume, and the vcb resource itself.
|
||||
//
|
||||
|
||||
CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
|
||||
|
||||
//
|
||||
// The device will be going away. Remove our lock and find
|
||||
// out if we ever had one in the first place.
|
||||
//
|
||||
|
||||
Status = CdUnlockVolumeInternal( IrpContext, Vcb, NULL );
|
||||
|
||||
//
|
||||
// If the volume had not been locked, we must invalidate the
|
||||
// volume to ensure it goes away properly. The remove will
|
||||
// succeed.
|
||||
//
|
||||
|
||||
if (!NT_SUCCESS( Status )) {
|
||||
|
||||
CdLockVcb( IrpContext, Vcb );
|
||||
|
||||
if (Vcb->VcbCondition != VcbDismountInProgress) {
|
||||
|
||||
CdUpdateVcbCondition( Vcb, VcbInvalid);
|
||||
}
|
||||
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// We need to pass this down before starting the dismount, which
|
||||
// could disconnect us immediately from the stack.
|
||||
//
|
||||
|
||||
//
|
||||
// Get the next stack location, and copy over the stack location
|
||||
//
|
||||
|
||||
IoCopyCurrentIrpStackLocationToNext( Irp );
|
||||
|
||||
//
|
||||
// Set up the completion routine
|
||||
//
|
||||
|
||||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||||
IoSetCompletionRoutine( Irp,
|
||||
CdPnpCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
//
|
||||
// Send the request and wait.
|
||||
//
|
||||
|
||||
Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
|
||||
KeWaitForSingleObject( &Event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL );
|
||||
|
||||
Status = Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Now make our dismount happen. This may not vaporize the
|
||||
// Vcb, of course, since there could be any number of handles
|
||||
// outstanding if we were not preceeded by a QUERY.
|
||||
//
|
||||
// PnP will take care of disconnecting this stack if we
|
||||
// couldn't get off of it immediately.
|
||||
//
|
||||
|
||||
|
||||
VcbPresent = CdCheckForDismount( IrpContext, Vcb, TRUE );
|
||||
|
||||
//
|
||||
// Release the Vcb if it could still remain.
|
||||
//
|
||||
|
||||
if (VcbPresent) {
|
||||
|
||||
CdReleaseVcb( IrpContext, Vcb );
|
||||
}
|
||||
|
||||
CdReleaseCdData( IrpContext );
|
||||
|
||||
//
|
||||
// Cleanup our IrpContext and complete the IRP.
|
||||
//
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, Status );
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdPnpSurpriseRemove (
|
||||
PIRP_CONTEXT IrpContext,
|
||||
PIRP Irp,
|
||||
PVCB Vcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine handles the PnP surprise remove operation. This is another
|
||||
type of notification that the underlying storage device for the volume we
|
||||
have is gone, and is excellent indication that the volume will never reappear.
|
||||
The filesystem is responsible for initiation or completion the dismount.
|
||||
|
||||
For the most part, only "real" drivers care about the distinction of a
|
||||
surprise remove, which is a result of our noticing that a user (usually)
|
||||
physically reached into the machine and pulled something out.
|
||||
|
||||
Surprise will be followed by a Remove when all references have been shut down.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Supplies the Irp to process
|
||||
|
||||
Vcb - Supplies the volume being removed.
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The return status for the operation
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
KEVENT Event;
|
||||
BOOLEAN VcbPresent = TRUE;
|
||||
|
||||
ASSERT_EXCLUSIVE_CDDATA;
|
||||
|
||||
//
|
||||
// SURPRISE - a device was physically yanked away without
|
||||
// any warning. This means external forces.
|
||||
//
|
||||
|
||||
CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
|
||||
|
||||
//
|
||||
// Invalidate the volume right now.
|
||||
//
|
||||
// The intent here is to make every subsequent operation
|
||||
// on the volume fail and grease the rails toward dismount.
|
||||
// By definition there is no going back from a SURPRISE.
|
||||
//
|
||||
|
||||
CdLockVcb( IrpContext, Vcb );
|
||||
|
||||
if (Vcb->VcbCondition != VcbDismountInProgress) {
|
||||
|
||||
CdUpdateVcbCondition( Vcb, VcbInvalid);
|
||||
}
|
||||
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
|
||||
//
|
||||
// We need to pass this down before starting the dismount, which
|
||||
// could disconnect us immediately from the stack.
|
||||
//
|
||||
|
||||
//
|
||||
// Get the next stack location, and copy over the stack location
|
||||
//
|
||||
|
||||
IoCopyCurrentIrpStackLocationToNext( Irp );
|
||||
|
||||
//
|
||||
// Set up the completion routine
|
||||
//
|
||||
|
||||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||||
IoSetCompletionRoutine( Irp,
|
||||
CdPnpCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
//
|
||||
// Send the request and wait.
|
||||
//
|
||||
|
||||
Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
|
||||
KeWaitForSingleObject( &Event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL );
|
||||
|
||||
Status = Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Now make our dismount happen. This may not vaporize the
|
||||
// Vcb, of course, since there could be any number of handles
|
||||
// outstanding since this is an out of band notification.
|
||||
//
|
||||
|
||||
|
||||
VcbPresent = CdCheckForDismount( IrpContext, Vcb, TRUE );
|
||||
|
||||
//
|
||||
// Release the Vcb if it could still remain.
|
||||
//
|
||||
|
||||
if (VcbPresent) {
|
||||
|
||||
CdReleaseVcb( IrpContext, Vcb );
|
||||
}
|
||||
|
||||
CdReleaseCdData( IrpContext );
|
||||
|
||||
//
|
||||
// Cleanup our IrpContext and complete the IRP.
|
||||
//
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, Status );
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdPnpCancelRemove (
|
||||
PIRP_CONTEXT IrpContext,
|
||||
PIRP Irp,
|
||||
PVCB Vcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine handles the PnP cancel remove operation. This is our
|
||||
notification that a previously proposed remove (query) was eventually
|
||||
vetoed by a component. The filesystem is responsible for cleaning up
|
||||
and getting ready for more IO.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Supplies the Irp to process
|
||||
|
||||
Vcb - Supplies the volume being removed.
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The return status for the operation
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
ASSERT_EXCLUSIVE_CDDATA;
|
||||
|
||||
//
|
||||
// CANCEL - a previous QUERY has been rescinded as a result
|
||||
// of someone vetoing. Since PnP cannot figure out who may
|
||||
// have gotten the QUERY (think about it: stacked drivers),
|
||||
// we must expect to deal with getting a CANCEL without having
|
||||
// seen the QUERY.
|
||||
//
|
||||
// For CDFS, this is quite easy. In fact, we can't get a
|
||||
// CANCEL if the underlying drivers succeeded the QUERY since
|
||||
// we disconnect the Vpb on our dismount initiation. This is
|
||||
// actually pretty important because if PnP could get to us
|
||||
// after the disconnect we'd be thoroughly unsynchronized
|
||||
// with respect to the Vcb getting torn apart - merely referencing
|
||||
// the volume device object is insufficient to keep us intact.
|
||||
//
|
||||
|
||||
CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
|
||||
CdReleaseCdData( IrpContext);
|
||||
|
||||
//
|
||||
// Unlock the volume. This is benign if we never had seen
|
||||
// a QUERY.
|
||||
//
|
||||
|
||||
(VOID) CdUnlockVolumeInternal( IrpContext, Vcb, NULL );
|
||||
|
||||
CdReleaseVcb( IrpContext, Vcb );
|
||||
|
||||
//
|
||||
// Send the request. The underlying driver will complete the
|
||||
// IRP. Since we don't need to be in the way, simply ellide
|
||||
// ourselves out of the IRP stack.
|
||||
//
|
||||
|
||||
IoSkipCurrentIrpStackLocation( Irp );
|
||||
|
||||
Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
|
||||
|
||||
CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
CdPnpCompletionRoutine (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Contxt
|
||||
)
|
||||
{
|
||||
PKEVENT Event = (PKEVENT) Contxt;
|
||||
|
||||
KeSetEvent( Event, 0, FALSE );
|
||||
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
|
||||
UNREFERENCED_PARAMETER( DeviceObject );
|
||||
UNREFERENCED_PARAMETER( Contxt );
|
||||
}
|
||||
|
||||
|
||||
+711
@@ -0,0 +1,711 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
PrefxSup.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the Cdfs Prefix support routines
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_PREFXSUP)
|
||||
|
||||
//
|
||||
// Local support routines.
|
||||
//
|
||||
|
||||
PNAME_LINK
|
||||
CdFindNameLink (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PRTL_SPLAY_LINKS *RootNode,
|
||||
IN PUNICODE_STRING Name
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
CdInsertNameLink (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PRTL_SPLAY_LINKS *RootNode,
|
||||
IN PNAME_LINK NameLink
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdFindNameLink)
|
||||
#pragma alloc_text(PAGE, CdFindPrefix)
|
||||
#pragma alloc_text(PAGE, CdInsertNameLink)
|
||||
#pragma alloc_text(PAGE, CdInsertPrefix)
|
||||
#pragma alloc_text(PAGE, CdRemovePrefix)
|
||||
#endif
|
||||
|
||||
|
||||
VOID
|
||||
CdInsertPrefix (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb,
|
||||
IN PCD_NAME Name,
|
||||
IN BOOLEAN IgnoreCase,
|
||||
IN BOOLEAN ShortNameMatch,
|
||||
IN PFCB ParentFcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine inserts the names in the given Lcb into the links for the
|
||||
parent.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - This is the Fcb whose name is being inserted into the tree.
|
||||
|
||||
Name - This is the name for the component. The IgnoreCase flag tells
|
||||
us which entry this belongs to.
|
||||
|
||||
IgnoreCase - Indicates if we should insert the case-insensitive name.
|
||||
|
||||
ShortNameMatch - Indicates if this is the short name.
|
||||
|
||||
ParentFcb - This is the ParentFcb. The prefix tree is attached to this.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ULONG PrefixFlags;
|
||||
PNAME_LINK NameLink;
|
||||
PPREFIX_ENTRY PrefixEntry;
|
||||
PRTL_SPLAY_LINKS *TreeRoot;
|
||||
|
||||
PWCHAR NameBuffer;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Check if we need to allocate a prefix entry for the short name.
|
||||
// If we can't allocate one then fail quietly. We don't have to
|
||||
// insert the name.
|
||||
//
|
||||
|
||||
PrefixEntry = &Fcb->FileNamePrefix;
|
||||
|
||||
if (ShortNameMatch) {
|
||||
|
||||
if (Fcb->ShortNamePrefix == NULL) {
|
||||
|
||||
Fcb->ShortNamePrefix = ExAllocatePoolWithTag( CdPagedPool,
|
||||
sizeof( PREFIX_ENTRY ),
|
||||
TAG_PREFIX_ENTRY );
|
||||
|
||||
if (Fcb->ShortNamePrefix == NULL) { return; }
|
||||
|
||||
RtlZeroMemory( Fcb->ShortNamePrefix, sizeof( PREFIX_ENTRY ));
|
||||
}
|
||||
|
||||
PrefixEntry = Fcb->ShortNamePrefix;
|
||||
}
|
||||
|
||||
//
|
||||
// Capture the local variables for the separate cases.
|
||||
//
|
||||
|
||||
if (IgnoreCase) {
|
||||
|
||||
PrefixFlags = PREFIX_FLAG_IGNORE_CASE_IN_TREE;
|
||||
NameLink = &PrefixEntry->IgnoreCaseName;
|
||||
TreeRoot = &ParentFcb->IgnoreCaseRoot;
|
||||
|
||||
} else {
|
||||
|
||||
PrefixFlags = PREFIX_FLAG_EXACT_CASE_IN_TREE;
|
||||
NameLink = &PrefixEntry->ExactCaseName;
|
||||
TreeRoot = &ParentFcb->ExactCaseRoot;
|
||||
}
|
||||
|
||||
//
|
||||
// If neither name is in the tree then check whether we have a buffer for this
|
||||
// name
|
||||
//
|
||||
|
||||
if (!FlagOn( PrefixEntry->PrefixFlags,
|
||||
PREFIX_FLAG_EXACT_CASE_IN_TREE | PREFIX_FLAG_IGNORE_CASE_IN_TREE )) {
|
||||
|
||||
//
|
||||
// Allocate a new buffer if the embedded buffer is too small.
|
||||
//
|
||||
|
||||
NameBuffer = PrefixEntry->FileNameBuffer;
|
||||
|
||||
if (Name->FileName.Length > BYTE_COUNT_EMBEDDED_NAME) {
|
||||
|
||||
NameBuffer = ExAllocatePoolWithTag( CdPagedPool,
|
||||
Name->FileName.Length * 2,
|
||||
TAG_PREFIX_NAME );
|
||||
|
||||
//
|
||||
// Exit if no name buffer.
|
||||
//
|
||||
|
||||
if (NameBuffer == NULL) { return; }
|
||||
}
|
||||
|
||||
//
|
||||
// Split the buffer and fill in the separate components.
|
||||
//
|
||||
|
||||
PrefixEntry->ExactCaseName.FileName.Buffer = NameBuffer;
|
||||
PrefixEntry->IgnoreCaseName.FileName.Buffer = Add2Ptr( NameBuffer,
|
||||
Name->FileName.Length,
|
||||
PWCHAR );
|
||||
|
||||
PrefixEntry->IgnoreCaseName.FileName.MaximumLength =
|
||||
PrefixEntry->IgnoreCaseName.FileName.Length =
|
||||
PrefixEntry->ExactCaseName.FileName.MaximumLength =
|
||||
PrefixEntry->ExactCaseName.FileName.Length = Name->FileName.Length;
|
||||
}
|
||||
|
||||
//
|
||||
// Only insert the name if not already present.
|
||||
//
|
||||
|
||||
if (!FlagOn( PrefixEntry->PrefixFlags, PrefixFlags )) {
|
||||
|
||||
//
|
||||
// Initialize the name in the prefix entry.
|
||||
//
|
||||
|
||||
RtlCopyMemory( NameLink->FileName.Buffer,
|
||||
Name->FileName.Buffer,
|
||||
Name->FileName.Length );
|
||||
|
||||
CdInsertNameLink( IrpContext,
|
||||
TreeRoot,
|
||||
NameLink );
|
||||
|
||||
PrefixEntry->Fcb = Fcb;
|
||||
SetFlag( PrefixEntry->PrefixFlags, PrefixFlags );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdRemovePrefix (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PFCB Fcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to remove all of the previx entries of a
|
||||
given Fcb from its parent Fcb.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - Fcb whose entries are to be removed.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Start with the short name prefix entry.
|
||||
//
|
||||
|
||||
if (Fcb->ShortNamePrefix != NULL) {
|
||||
|
||||
if (FlagOn( Fcb->ShortNamePrefix->PrefixFlags, PREFIX_FLAG_IGNORE_CASE_IN_TREE )) {
|
||||
|
||||
Fcb->ParentFcb->IgnoreCaseRoot = RtlDelete( &Fcb->ShortNamePrefix->IgnoreCaseName.Links );
|
||||
}
|
||||
|
||||
if (FlagOn( Fcb->ShortNamePrefix->PrefixFlags, PREFIX_FLAG_EXACT_CASE_IN_TREE )) {
|
||||
|
||||
Fcb->ParentFcb->ExactCaseRoot = RtlDelete( &Fcb->ShortNamePrefix->ExactCaseName.Links );
|
||||
}
|
||||
|
||||
ClearFlag( Fcb->ShortNamePrefix->PrefixFlags,
|
||||
PREFIX_FLAG_IGNORE_CASE_IN_TREE | PREFIX_FLAG_EXACT_CASE_IN_TREE );
|
||||
}
|
||||
|
||||
//
|
||||
// Now do the long name prefix entries.
|
||||
//
|
||||
|
||||
if (FlagOn( Fcb->FileNamePrefix.PrefixFlags, PREFIX_FLAG_IGNORE_CASE_IN_TREE )) {
|
||||
|
||||
Fcb->ParentFcb->IgnoreCaseRoot = RtlDelete( &Fcb->FileNamePrefix.IgnoreCaseName.Links );
|
||||
}
|
||||
|
||||
if (FlagOn( Fcb->FileNamePrefix.PrefixFlags, PREFIX_FLAG_EXACT_CASE_IN_TREE )) {
|
||||
|
||||
Fcb->ParentFcb->ExactCaseRoot = RtlDelete( &Fcb->FileNamePrefix.ExactCaseName.Links );
|
||||
}
|
||||
|
||||
ClearFlag( Fcb->FileNamePrefix.PrefixFlags,
|
||||
PREFIX_FLAG_IGNORE_CASE_IN_TREE | PREFIX_FLAG_EXACT_CASE_IN_TREE );
|
||||
|
||||
//
|
||||
// Deallocate any buffer we may have allocated.
|
||||
//
|
||||
|
||||
if ((Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != (PWCHAR) &Fcb->FileNamePrefix.FileNameBuffer) &&
|
||||
(Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != NULL)) {
|
||||
|
||||
CdFreePool( &Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer );
|
||||
Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdFindPrefix (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN OUT PFCB *CurrentFcb,
|
||||
IN OUT PUNICODE_STRING RemainingName,
|
||||
IN BOOLEAN IgnoreCase
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine begins from the given CurrentFcb and walks through all of
|
||||
components of the name looking for the longest match in the prefix
|
||||
splay trees. The search is relative to the starting Fcb so the
|
||||
full name may not begin with a '\'. On return this routine will
|
||||
update Current Fcb with the lowest point it has travelled in the
|
||||
tree. It will also hold only that resource on return and it must
|
||||
hold that resource.
|
||||
|
||||
Arguments:
|
||||
|
||||
CurrentFcb - Address to store the lowest Fcb we find on this search.
|
||||
On return we will have acquired this Fcb. On entry this is the
|
||||
Fcb to examine.
|
||||
|
||||
RemainingName - Supplies a buffer to store the exact case of the name being
|
||||
searched for. Initially will contain the upcase name based on the
|
||||
IgnoreCase flag.
|
||||
|
||||
IgnoreCase - Indicates if we are doing a case-insensitive compare.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
UNICODE_STRING LocalRemainingName;
|
||||
|
||||
UNICODE_STRING FinalName;
|
||||
|
||||
PNAME_LINK NameLink;
|
||||
PPREFIX_ENTRY PrefixEntry;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Make a local copy of the input strings.
|
||||
//
|
||||
|
||||
LocalRemainingName = *RemainingName;
|
||||
|
||||
//
|
||||
// Loop until we find the longest matching prefix.
|
||||
//
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
//
|
||||
// If there are no characters left or we are not at an IndexFcb then
|
||||
// return immediately.
|
||||
//
|
||||
|
||||
if ((LocalRemainingName.Length == 0) ||
|
||||
(SafeNodeType( *CurrentFcb ) != CDFS_NTC_FCB_INDEX)) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Split off the next component from the name.
|
||||
//
|
||||
|
||||
CdDissectName( IrpContext,
|
||||
&LocalRemainingName,
|
||||
&FinalName );
|
||||
|
||||
//
|
||||
// Check if this name is in the splay tree for this Scb.
|
||||
//
|
||||
|
||||
if (IgnoreCase) {
|
||||
|
||||
NameLink = CdFindNameLink( IrpContext,
|
||||
&(*CurrentFcb)->IgnoreCaseRoot,
|
||||
&FinalName );
|
||||
|
||||
//
|
||||
// Get the prefix entry from this NameLink. Don't access any
|
||||
// fields within it until we verify we have a name link.
|
||||
//
|
||||
|
||||
PrefixEntry = (PPREFIX_ENTRY) CONTAINING_RECORD( NameLink,
|
||||
PREFIX_ENTRY,
|
||||
IgnoreCaseName );
|
||||
|
||||
} else {
|
||||
|
||||
NameLink = CdFindNameLink( IrpContext,
|
||||
&(*CurrentFcb)->ExactCaseRoot,
|
||||
&FinalName );
|
||||
|
||||
PrefixEntry = (PPREFIX_ENTRY) CONTAINING_RECORD( NameLink,
|
||||
PREFIX_ENTRY,
|
||||
ExactCaseName );
|
||||
}
|
||||
|
||||
//
|
||||
// If we didn't find a match then exit.
|
||||
//
|
||||
|
||||
if (NameLink == NULL) { return; }
|
||||
|
||||
//
|
||||
// If this is a case-insensitive match then copy the exact case of the name into
|
||||
// the input buffer.
|
||||
//
|
||||
|
||||
if (IgnoreCase) {
|
||||
|
||||
RtlCopyMemory( FinalName.Buffer,
|
||||
PrefixEntry->ExactCaseName.FileName.Buffer,
|
||||
PrefixEntry->ExactCaseName.FileName.Length );
|
||||
}
|
||||
|
||||
//
|
||||
// Update the caller's remaining name string to reflect the fact that we found
|
||||
// a match.
|
||||
//
|
||||
|
||||
*RemainingName = LocalRemainingName;
|
||||
|
||||
//
|
||||
// Move down to the next component in the tree. Acquire without waiting.
|
||||
// If this fails then lock the Fcb to reference this Fcb and then drop
|
||||
// the parent and acquire the child.
|
||||
//
|
||||
|
||||
if (!CdAcquireFcbExclusive( IrpContext, PrefixEntry->Fcb, TRUE )) {
|
||||
|
||||
//
|
||||
// If we can't wait then raise CANT_WAIT.
|
||||
//
|
||||
|
||||
if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
|
||||
}
|
||||
|
||||
CdLockVcb( IrpContext, IrpContext->Vcb );
|
||||
PrefixEntry->Fcb->FcbReference += 1;
|
||||
CdUnlockVcb( IrpContext, IrpContext->Vcb );
|
||||
|
||||
CdReleaseFcb( IrpContext, *CurrentFcb );
|
||||
CdAcquireFcbExclusive( IrpContext, PrefixEntry->Fcb, FALSE );
|
||||
|
||||
CdLockVcb( IrpContext, IrpContext->Vcb );
|
||||
PrefixEntry->Fcb->FcbReference -= 1;
|
||||
CdUnlockVcb( IrpContext, IrpContext->Vcb );
|
||||
|
||||
} else {
|
||||
|
||||
CdReleaseFcb( IrpContext, *CurrentFcb );
|
||||
}
|
||||
|
||||
*CurrentFcb = PrefixEntry->Fcb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
PNAME_LINK
|
||||
CdFindNameLink (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PRTL_SPLAY_LINKS *RootNode,
|
||||
IN PUNICODE_STRING Name
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine searches through a splay link tree looking for a match for the
|
||||
input name. If we find the corresponding name we will rebalance the
|
||||
tree.
|
||||
|
||||
Arguments:
|
||||
|
||||
RootNode - Supplies the parent to search.
|
||||
|
||||
Name - This is the name to search for. Note if we are doing a case
|
||||
insensitive search the name would have been upcased already.
|
||||
|
||||
Return Value:
|
||||
|
||||
PNAME_LINK - The name link found or NULL if there is no match.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FSRTL_COMPARISON_RESULT Comparison;
|
||||
PNAME_LINK Node;
|
||||
PRTL_SPLAY_LINKS Links;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
Links = *RootNode;
|
||||
|
||||
while (Links != NULL) {
|
||||
|
||||
Node = CONTAINING_RECORD( Links, NAME_LINK, Links );
|
||||
|
||||
//
|
||||
// Compare the prefix in the tree with the full name
|
||||
//
|
||||
|
||||
Comparison = CdFullCompareNames( IrpContext, &Node->FileName, Name );
|
||||
|
||||
//
|
||||
// See if they don't match
|
||||
//
|
||||
|
||||
if (Comparison == GreaterThan) {
|
||||
|
||||
//
|
||||
// The prefix is greater than the full name
|
||||
// so we go down the left child
|
||||
//
|
||||
|
||||
Links = RtlLeftChild( Links );
|
||||
|
||||
//
|
||||
// And continue searching down this tree
|
||||
//
|
||||
|
||||
} else if (Comparison == LessThan) {
|
||||
|
||||
//
|
||||
// The prefix is less than the full name
|
||||
// so we go down the right child
|
||||
//
|
||||
|
||||
Links = RtlRightChild( Links );
|
||||
|
||||
//
|
||||
// And continue searching down this tree
|
||||
//
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// We found it.
|
||||
//
|
||||
// Splay the tree and save the new root.
|
||||
//
|
||||
|
||||
*RootNode = RtlSplay( Links );
|
||||
|
||||
return Node;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// We didn't find the Link.
|
||||
//
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
BOOLEAN
|
||||
CdInsertNameLink (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PRTL_SPLAY_LINKS *RootNode,
|
||||
IN PNAME_LINK NameLink
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine will insert a name in the splay tree pointed to
|
||||
by RootNode.
|
||||
|
||||
The name could already exist in this tree for a case-insensitive tree.
|
||||
In that case we simply return FALSE and do nothing.
|
||||
|
||||
Arguments:
|
||||
|
||||
RootNode - Supplies a pointer to the table.
|
||||
|
||||
NameLink - Contains the new link to enter.
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - TRUE if the name is inserted, FALSE otherwise.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FSRTL_COMPARISON_RESULT Comparison;
|
||||
PNAME_LINK Node;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
RtlInitializeSplayLinks( &NameLink->Links );
|
||||
|
||||
//
|
||||
// If we are the first entry in the tree, just become the root.
|
||||
//
|
||||
|
||||
if (*RootNode == NULL) {
|
||||
|
||||
*RootNode = &NameLink->Links;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Node = CONTAINING_RECORD( *RootNode, NAME_LINK, Links );
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
//
|
||||
// Compare the prefix in the tree with the prefix we want
|
||||
// to insert.
|
||||
//
|
||||
|
||||
Comparison = CdFullCompareNames( IrpContext, &Node->FileName, &NameLink->FileName );
|
||||
|
||||
//
|
||||
// If we found the entry, return immediately.
|
||||
//
|
||||
|
||||
if (Comparison == EqualTo) { return FALSE; }
|
||||
|
||||
//
|
||||
// If the tree prefix is greater than the new prefix then
|
||||
// we go down the left subtree
|
||||
//
|
||||
|
||||
if (Comparison == GreaterThan) {
|
||||
|
||||
//
|
||||
// We want to go down the left subtree, first check to see
|
||||
// if we have a left subtree
|
||||
//
|
||||
|
||||
if (RtlLeftChild( &Node->Links ) == NULL) {
|
||||
|
||||
//
|
||||
// there isn't a left child so we insert ourselves as the
|
||||
// new left child
|
||||
//
|
||||
|
||||
RtlInsertAsLeftChild( &Node->Links, &NameLink->Links );
|
||||
|
||||
//
|
||||
// and exit the while loop
|
||||
//
|
||||
|
||||
break;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// there is a left child so simply go down that path, and
|
||||
// go back to the top of the loop
|
||||
//
|
||||
|
||||
Node = CONTAINING_RECORD( RtlLeftChild( &Node->Links ),
|
||||
NAME_LINK,
|
||||
Links );
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// The tree prefix is either less than or a proper prefix
|
||||
// of the new string. We treat both cases as less than when
|
||||
// we do insert. So we want to go down the right subtree,
|
||||
// first check to see if we have a right subtree
|
||||
//
|
||||
|
||||
if (RtlRightChild( &Node->Links ) == NULL) {
|
||||
|
||||
//
|
||||
// These isn't a right child so we insert ourselves as the
|
||||
// new right child
|
||||
//
|
||||
|
||||
RtlInsertAsRightChild( &Node->Links, &NameLink->Links );
|
||||
|
||||
//
|
||||
// and exit the while loop
|
||||
//
|
||||
|
||||
break;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// there is a right child so simply go down that path, and
|
||||
// go back to the top of the loop
|
||||
//
|
||||
|
||||
Node = CONTAINING_RECORD( RtlRightChild( &Node->Links ),
|
||||
NAME_LINK,
|
||||
Links );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Executable
+550
@@ -0,0 +1,550 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
Read.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the File Read routine for Read called by the
|
||||
Fsd/Fsp dispatch drivers.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_READ)
|
||||
|
||||
//
|
||||
// VOID
|
||||
// SafeZeroMemory (
|
||||
// IN PUCHAR At,
|
||||
// IN ULONG ByteCount
|
||||
// );
|
||||
//
|
||||
|
||||
//
|
||||
// This macro just puts a nice little try-except around RtlZeroMemory
|
||||
//
|
||||
|
||||
#define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
|
||||
try { \
|
||||
RtlZeroMemory( (AT), (BYTE_COUNT) ); \
|
||||
} except( EXCEPTION_EXECUTE_HANDLER ) { \
|
||||
CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
|
||||
} \
|
||||
}
|
||||
|
||||
//
|
||||
// Read ahead amount used for normal data files
|
||||
//
|
||||
|
||||
#define READ_AHEAD_GRANULARITY (0x10000)
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdCommonRead)
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdCommonRead (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the common entry point for NtReadFile calls. For synchronous requests,
|
||||
CommonRead will complete the request in the current thread. If not
|
||||
synchronous the request will be passed to the Fsp if there is a need to
|
||||
block.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Supplies the Irp to process
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The result of this operation.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
TYPE_OF_OPEN TypeOfOpen;
|
||||
PFCB Fcb;
|
||||
PCCB Ccb;
|
||||
|
||||
BOOLEAN Wait;
|
||||
ULONG PagingIo;
|
||||
ULONG SynchronousIo;
|
||||
ULONG NonCachedIo;
|
||||
PVOID UserBuffer;
|
||||
|
||||
LONGLONG StartingOffset;
|
||||
LONGLONG ByteRange;
|
||||
ULONG ByteCount;
|
||||
ULONG ReadByteCount;
|
||||
ULONG OriginalByteCount;
|
||||
|
||||
PVOID SystemBuffer;
|
||||
|
||||
BOOLEAN ReleaseFile = TRUE;
|
||||
|
||||
CD_IO_CONTEXT LocalIoContext;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// If this is a zero length read then return SUCCESS immediately.
|
||||
//
|
||||
|
||||
if (IrpSp->Parameters.Read.Length == 0) {
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Decode the file object and verify we support read on this. It
|
||||
// must be a user file, stream file or volume file (for a data disk).
|
||||
//
|
||||
|
||||
TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
|
||||
|
||||
if ((TypeOfOpen == UnopenedFileObject) ||
|
||||
(TypeOfOpen == UserDirectoryOpen)) {
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
//
|
||||
// Examine our input parameters to determine if this is noncached and/or
|
||||
// a paging io operation.
|
||||
//
|
||||
|
||||
Wait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
|
||||
PagingIo = FlagOn( Irp->Flags, IRP_PAGING_IO );
|
||||
NonCachedIo = FlagOn( Irp->Flags, IRP_NOCACHE );
|
||||
SynchronousIo = FlagOn( IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO );
|
||||
|
||||
|
||||
//
|
||||
// Extract the range of the Io.
|
||||
//
|
||||
|
||||
StartingOffset = IrpSp->Parameters.Read.ByteOffset.QuadPart;
|
||||
OriginalByteCount = ByteCount = IrpSp->Parameters.Read.Length;
|
||||
|
||||
ByteRange = StartingOffset + ByteCount;
|
||||
|
||||
//
|
||||
// Make sure that Dasd access is always non-cached.
|
||||
//
|
||||
|
||||
if (TypeOfOpen == UserVolumeOpen) {
|
||||
|
||||
NonCachedIo = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Acquire the file shared to perform the read. If we are doing paging IO,
|
||||
// it may be the case that we would have a deadlock imminent because we may
|
||||
// block on shared access, so starve out any exclusive waiters. This requires
|
||||
// a degree of caution - we believe that any paging IO bursts will recede and
|
||||
// allow the exclusive waiter in.
|
||||
//
|
||||
|
||||
if (PagingIo) {
|
||||
|
||||
CdAcquireFileSharedStarveExclusive( IrpContext, Fcb );
|
||||
|
||||
} else {
|
||||
|
||||
CdAcquireFileShared( IrpContext, Fcb );
|
||||
}
|
||||
|
||||
//
|
||||
// Use a try-finally to facilitate cleanup.
|
||||
//
|
||||
|
||||
try {
|
||||
|
||||
//
|
||||
// Verify the Fcb. Allow reads if this is a DASD handle that is
|
||||
// dismounting the volume.
|
||||
//
|
||||
|
||||
if ((TypeOfOpen != UserVolumeOpen) || (NULL == Ccb) ||
|
||||
!FlagOn( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE)) {
|
||||
|
||||
CdVerifyFcbOperation( IrpContext, Fcb );
|
||||
}
|
||||
|
||||
//
|
||||
// If this is a non-cached then check whether we need to post this
|
||||
// request if this thread can't block.
|
||||
//
|
||||
|
||||
if (!Wait && NonCachedIo) {
|
||||
|
||||
//
|
||||
// XA requests must always be waitable.
|
||||
//
|
||||
|
||||
if (FlagOn( Fcb->FcbState, FCB_STATE_RAWSECTOR_MASK )) {
|
||||
|
||||
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
|
||||
try_return( Status = STATUS_CANT_WAIT );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If this is a user request then verify the oplock and filelock state.
|
||||
//
|
||||
|
||||
if (TypeOfOpen == UserFileOpen) {
|
||||
|
||||
//
|
||||
// We check whether we can proceed
|
||||
// based on the state of the file oplocks.
|
||||
//
|
||||
|
||||
Status = FsRtlCheckOplock( &Fcb->Oplock,
|
||||
Irp,
|
||||
IrpContext,
|
||||
CdOplockComplete,
|
||||
CdPrePostIrp );
|
||||
|
||||
//
|
||||
// If the result is not STATUS_SUCCESS then the Irp was completed
|
||||
// elsewhere.
|
||||
//
|
||||
|
||||
if (Status != STATUS_SUCCESS) {
|
||||
|
||||
Irp = NULL;
|
||||
IrpContext = NULL;
|
||||
|
||||
try_return( NOTHING );
|
||||
}
|
||||
|
||||
if (!PagingIo &&
|
||||
(Fcb->FileLock != NULL) &&
|
||||
!FsRtlCheckLockForReadAccess( Fcb->FileLock, Irp )) {
|
||||
|
||||
try_return( Status = STATUS_FILE_LOCK_CONFLICT );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Complete the request if it begins beyond the end of file.
|
||||
//
|
||||
|
||||
if (StartingOffset >= Fcb->FileSize.QuadPart) {
|
||||
|
||||
try_return( Status = STATUS_END_OF_FILE );
|
||||
}
|
||||
|
||||
//
|
||||
// Truncate the read if it extends beyond the end of the file.
|
||||
//
|
||||
|
||||
if (ByteRange > Fcb->FileSize.QuadPart) {
|
||||
|
||||
ByteCount = (ULONG) (Fcb->FileSize.QuadPart - StartingOffset);
|
||||
ByteRange = Fcb->FileSize.QuadPart;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle the non-cached read first.
|
||||
//
|
||||
|
||||
if (NonCachedIo) {
|
||||
|
||||
//
|
||||
// If we have an unaligned transfer then post this request if
|
||||
// we can't wait. Unaligned means that the starting offset
|
||||
// is not on a sector boundary or the read is not integral
|
||||
// sectors.
|
||||
//
|
||||
|
||||
ReadByteCount = BlockAlign( Fcb->Vcb, ByteCount );
|
||||
|
||||
if (SectorOffset( StartingOffset ) ||
|
||||
SectorOffset( ReadByteCount ) ||
|
||||
(ReadByteCount > OriginalByteCount)) {
|
||||
|
||||
if (!Wait) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure we don't overwrite the buffer.
|
||||
//
|
||||
|
||||
ReadByteCount = ByteCount;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the IoContext for the read.
|
||||
// If there is a context pointer, we need to make sure it was
|
||||
// allocated and not a stale stack pointer.
|
||||
//
|
||||
|
||||
if (IrpContext->IoContext == NULL ||
|
||||
!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
|
||||
|
||||
//
|
||||
// If we can wait, use the context on the stack. Otherwise
|
||||
// we need to allocate one.
|
||||
//
|
||||
|
||||
if (Wait) {
|
||||
|
||||
IrpContext->IoContext = &LocalIoContext;
|
||||
ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
|
||||
|
||||
} else {
|
||||
|
||||
IrpContext->IoContext = CdAllocateIoContext();
|
||||
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
|
||||
}
|
||||
}
|
||||
|
||||
RtlZeroMemory( IrpContext->IoContext, sizeof( CD_IO_CONTEXT ));
|
||||
|
||||
//
|
||||
// Store whether we allocated this context structure in the structure
|
||||
// itself.
|
||||
//
|
||||
|
||||
IrpContext->IoContext->AllocatedContext =
|
||||
BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
|
||||
|
||||
if (Wait) {
|
||||
|
||||
KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
|
||||
NotificationEvent,
|
||||
FALSE );
|
||||
|
||||
} else {
|
||||
|
||||
IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread();
|
||||
IrpContext->IoContext->Resource = Fcb->Resource;
|
||||
IrpContext->IoContext->RequestedByteCount = ByteCount;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = ReadByteCount;
|
||||
|
||||
//
|
||||
// Call one of the NonCacheIo routines to perform the actual
|
||||
// read.
|
||||
//
|
||||
|
||||
if (FlagOn( Fcb->FcbState, FCB_STATE_RAWSECTOR_MASK )) {
|
||||
|
||||
Status = CdNonCachedXARead( IrpContext, Fcb, StartingOffset, ReadByteCount );
|
||||
|
||||
} else {
|
||||
|
||||
Status = CdNonCachedRead( IrpContext, Fcb, StartingOffset, ReadByteCount );
|
||||
}
|
||||
|
||||
//
|
||||
// Don't complete this request now if STATUS_PENDING was returned.
|
||||
//
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
|
||||
Irp = NULL;
|
||||
ReleaseFile = FALSE;
|
||||
|
||||
//
|
||||
// Test is we should zero part of the buffer or update the
|
||||
// synchronous file position.
|
||||
//
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Convert any unknown error code to IO_ERROR.
|
||||
//
|
||||
|
||||
if (!NT_SUCCESS( Status )) {
|
||||
|
||||
//
|
||||
// Set the information field to zero.
|
||||
//
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
//
|
||||
// Raise if this is a user induced error.
|
||||
//
|
||||
|
||||
if (IoIsErrorUserInduced( Status )) {
|
||||
|
||||
CdRaiseStatus( IrpContext, Status );
|
||||
}
|
||||
|
||||
Status = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR );
|
||||
|
||||
//
|
||||
// Check if there is any portion of the user's buffer to zero.
|
||||
//
|
||||
|
||||
} else if (ReadByteCount != ByteCount) {
|
||||
|
||||
CdMapUserBuffer( IrpContext, &UserBuffer);
|
||||
|
||||
SafeZeroMemory( IrpContext,
|
||||
Add2Ptr( UserBuffer,
|
||||
ByteCount,
|
||||
PVOID ),
|
||||
ReadByteCount - ByteCount );
|
||||
|
||||
Irp->IoStatus.Information = ByteCount;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the file position if this is a synchronous request.
|
||||
//
|
||||
|
||||
if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
|
||||
|
||||
IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
|
||||
}
|
||||
}
|
||||
|
||||
try_return( NOTHING );
|
||||
}
|
||||
|
||||
//
|
||||
// Handle the cached case. Start by initializing the private
|
||||
// cache map.
|
||||
//
|
||||
|
||||
if (IrpSp->FileObject->PrivateCacheMap == NULL) {
|
||||
|
||||
//
|
||||
// Now initialize the cache map.
|
||||
//
|
||||
|
||||
CcInitializeCacheMap( IrpSp->FileObject,
|
||||
(PCC_FILE_SIZES) &Fcb->AllocationSize,
|
||||
FALSE,
|
||||
&CdData.CacheManagerCallbacks,
|
||||
Fcb );
|
||||
|
||||
CcSetReadAheadGranularity( IrpSp->FileObject, READ_AHEAD_GRANULARITY );
|
||||
}
|
||||
|
||||
//
|
||||
// Read from the cache if this is not an Mdl read.
|
||||
//
|
||||
|
||||
if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
|
||||
|
||||
//
|
||||
// If we are in the Fsp now because we had to wait earlier,
|
||||
// we must map the user buffer, otherwise we can use the
|
||||
// user's buffer directly.
|
||||
//
|
||||
|
||||
CdMapUserBuffer( IrpContext, &SystemBuffer );
|
||||
|
||||
//
|
||||
// Now try to do the copy.
|
||||
//
|
||||
|
||||
if (!CcCopyRead( IrpSp->FileObject,
|
||||
(PLARGE_INTEGER) &StartingOffset,
|
||||
ByteCount,
|
||||
Wait,
|
||||
SystemBuffer,
|
||||
&Irp->IoStatus )) {
|
||||
|
||||
try_return( Status = STATUS_CANT_WAIT );
|
||||
}
|
||||
|
||||
//
|
||||
// If the call didn't succeed, raise the error status
|
||||
//
|
||||
|
||||
if (!NT_SUCCESS( Irp->IoStatus.Status )) {
|
||||
|
||||
CdNormalizeAndRaiseStatus( IrpContext, Irp->IoStatus.Status );
|
||||
}
|
||||
|
||||
//
|
||||
// Otherwise perform the MdlRead operation.
|
||||
//
|
||||
|
||||
} else {
|
||||
|
||||
CcMdlRead( IrpSp->FileObject,
|
||||
(PLARGE_INTEGER) &StartingOffset,
|
||||
ByteCount,
|
||||
&Irp->MdlAddress,
|
||||
&Irp->IoStatus );
|
||||
|
||||
Status = Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the current file position in the user file object.
|
||||
//
|
||||
|
||||
if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
|
||||
|
||||
IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
|
||||
}
|
||||
|
||||
try_exit: NOTHING;
|
||||
} finally {
|
||||
|
||||
//
|
||||
// Release the Fcb.
|
||||
//
|
||||
|
||||
if (ReleaseFile) {
|
||||
|
||||
CdReleaseFile( IrpContext, Fcb );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Post the request if we got CANT_WAIT.
|
||||
//
|
||||
|
||||
if (Status == STATUS_CANT_WAIT) {
|
||||
|
||||
Status = CdFsdPostRequest( IrpContext, Irp );
|
||||
|
||||
//
|
||||
// Otherwise complete the request.
|
||||
//
|
||||
|
||||
} else {
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, Status );
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
ResrcSup.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the Cdfs Resource acquisition routines
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_RESRCSUP)
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdAcquireForCache)
|
||||
#pragma alloc_text(PAGE, CdAcquireForCreateSection)
|
||||
#pragma alloc_text(PAGE, CdAcquireResource)
|
||||
#pragma alloc_text(PAGE, CdNoopAcquire)
|
||||
#pragma alloc_text(PAGE, CdNoopRelease)
|
||||
#pragma alloc_text(PAGE, CdReleaseForCreateSection)
|
||||
#pragma alloc_text(PAGE, CdReleaseFromCache)
|
||||
#endif
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdAcquireResource (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PERESOURCE Resource,
|
||||
IN BOOLEAN IgnoreWait,
|
||||
IN TYPE_OF_ACQUIRE Type
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the single routine used to acquire file system resources. It
|
||||
looks at the IgnoreWait flag to determine whether to try to acquire the
|
||||
resource without waiting. Returning TRUE/FALSE to indicate success or
|
||||
failure. Otherwise it is driven by the WAIT flag in the IrpContext and
|
||||
will raise CANT_WAIT on a failure.
|
||||
|
||||
Arguments:
|
||||
|
||||
Resource - This is the resource to try and acquire.
|
||||
|
||||
IgnoreWait - If TRUE then this routine will not wait to acquire the
|
||||
resource and will return a boolean indicating whether the resource was
|
||||
acquired. Otherwise we use the flag in the IrpContext and raise
|
||||
if the resource is not acquired.
|
||||
|
||||
Type - Indicates how we should try to get the resource.
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - TRUE if the resource is acquired. FALSE if not acquired and
|
||||
IgnoreWait is specified. Otherwise we raise CANT_WAIT.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
BOOLEAN Wait = FALSE;
|
||||
BOOLEAN Acquired;
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// We look first at the IgnoreWait flag, next at the flag in the Irp
|
||||
// Context to decide how to acquire this resource.
|
||||
//
|
||||
|
||||
if (!IgnoreWait && FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
|
||||
|
||||
Wait = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Attempt to acquire the resource either shared or exclusively.
|
||||
//
|
||||
|
||||
switch (Type) {
|
||||
case AcquireExclusive:
|
||||
|
||||
Acquired = ExAcquireResourceExclusiveLite( Resource, Wait );
|
||||
break;
|
||||
|
||||
case AcquireShared:
|
||||
|
||||
Acquired = ExAcquireResourceSharedLite( Resource, Wait );
|
||||
break;
|
||||
|
||||
case AcquireSharedStarveExclusive:
|
||||
|
||||
Acquired = ExAcquireSharedStarveExclusive( Resource, Wait );
|
||||
break;
|
||||
|
||||
default:
|
||||
Acquired = FALSE;
|
||||
ASSERT( FALSE );
|
||||
}
|
||||
|
||||
//
|
||||
// If not acquired and the user didn't specifiy IgnoreWait then
|
||||
// raise CANT_WAIT.
|
||||
//
|
||||
|
||||
if (!Acquired && !IgnoreWait) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
|
||||
}
|
||||
|
||||
return Acquired;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdAcquireForCache (
|
||||
IN PFCB Fcb,
|
||||
IN BOOLEAN Wait
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The address of this routine is specified when creating a CacheMap for
|
||||
a file. It is subsequently called by the Lazy Writer for synchronization.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - The pointer supplied as context to the cache initialization
|
||||
routine.
|
||||
|
||||
Wait - TRUE if the caller is willing to block.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT(IoGetTopLevelIrp() == NULL);
|
||||
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
|
||||
return ExAcquireResourceSharedLite( Fcb->Resource, Wait );
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdReleaseFromCache (
|
||||
IN PFCB Fcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The address of this routine is specified when creating a CacheMap for
|
||||
a virtual file. It is subsequently called by the Lazy Writer to release
|
||||
a resource acquired above.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - The pointer supplied as context to the cache initialization
|
||||
routine.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
IoSetTopLevelIrp( NULL );
|
||||
|
||||
ExReleaseResourceLite( Fcb->Resource );
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdNoopAcquire (
|
||||
IN PVOID Fcb,
|
||||
IN BOOLEAN Wait
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine does nothing.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - The Fcb/Vcb which was specified as a context parameter for this
|
||||
routine.
|
||||
|
||||
Wait - TRUE if the caller is willing to block.
|
||||
|
||||
Return Value:
|
||||
|
||||
TRUE
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdNoopRelease (
|
||||
IN PVOID Fcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine does nothing.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fcb - The Fcb/Vcb which was specified as a context parameter for this
|
||||
routine.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdAcquireForCreateSection (
|
||||
IN PFILE_OBJECT FileObject
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the callback routine for MM to use to acquire the file exclusively.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - File object for a Cdfs stream.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
|
||||
//
|
||||
// Get the Fcb resource exclusively.
|
||||
//
|
||||
|
||||
ExAcquireResourceExclusiveLite( &((PFCB) FileObject->FsContext)->FcbNonpaged->FcbResource,
|
||||
TRUE );
|
||||
|
||||
//
|
||||
// Take the File resource shared. We need this later on when MM calls
|
||||
// QueryStandardInfo to get the file size.
|
||||
//
|
||||
// If we don't use StarveExclusive, then we can get wedged behind an
|
||||
// exclusive waiter who is waiting on someone else holding it shared in the
|
||||
// read->initializecachemap path (which calls createsection) who is in turn
|
||||
// waiting on us to finish the create section.
|
||||
//
|
||||
|
||||
ExAcquireSharedStarveExclusive( ((PFCB) FileObject->FsContext)->Resource,
|
||||
TRUE );
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdReleaseForCreateSection (
|
||||
IN PFILE_OBJECT FileObject
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the callback routine for MM to use to release a file acquired with
|
||||
the AcquireForCreateSection call above.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - File object for a Cdfs stream.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Release the resources.
|
||||
//
|
||||
|
||||
ExReleaseResourceLite( &((PFCB) FileObject->FsContext)->FcbNonpaged->FcbResource );
|
||||
ExReleaseResourceLite( ((PFCB) FileObject->FsContext)->Resource);
|
||||
}
|
||||
|
||||
+2766
File diff suppressed because it is too large
Load Diff
+954
@@ -0,0 +1,954 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
VerfySup.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the Cdfs Verification routines.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_VERFYSUP)
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdVerifyFcbOperation)
|
||||
#pragma alloc_text(PAGE, CdVerifyVcb)
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdPerformVerify (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp,
|
||||
IN PDEVICE_OBJECT DeviceToVerify
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routines performs an IoVerifyVolume operation and takes the
|
||||
appropriate action. If the verify is successful then we send the originating
|
||||
Irp off to an Ex Worker Thread. This routine is called from the exception handler.
|
||||
|
||||
No file system resources are held when this routine is called.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - The irp to send off after all is well and done.
|
||||
|
||||
Device - The real device needing verification.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PVCB Vcb;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_IRP( Irp );
|
||||
|
||||
//
|
||||
// Check if this Irp has a status of Verify required and if it does
|
||||
// then call the I/O system to do a verify.
|
||||
//
|
||||
// Skip the IoVerifyVolume if this is a mount or verify request
|
||||
// itself. Trying a recursive mount will cause a deadlock with
|
||||
// the DeviceObject->DeviceLock.
|
||||
//
|
||||
|
||||
if ((IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
|
||||
((IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) ||
|
||||
(IrpContext->MinorFunction == IRP_MN_VERIFY_VOLUME))) {
|
||||
|
||||
return CdFsdPostRequest( IrpContext, Irp );
|
||||
}
|
||||
|
||||
//
|
||||
// Extract a pointer to the Vcb from the VolumeDeviceObject.
|
||||
// Note that since we have specifically excluded mount,
|
||||
// requests, we know that IrpSp->DeviceObject is indeed a
|
||||
// volume device object.
|
||||
//
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
Vcb = &CONTAINING_RECORD( IrpSp->DeviceObject,
|
||||
VOLUME_DEVICE_OBJECT,
|
||||
DeviceObject )->Vcb;
|
||||
try {
|
||||
|
||||
//
|
||||
// Send down the verify FSCTL. Note that this is sent to the
|
||||
// currently mounted volume, which may not be this one.
|
||||
//
|
||||
// We will allow Raw to mount this volume if we were doing a
|
||||
// an absolute DASD open.
|
||||
//
|
||||
|
||||
Status = IoVerifyVolume( DeviceToVerify, CdOperationIsDasdOpen( IrpContext));
|
||||
|
||||
//
|
||||
// Acquire the Vcb so we're working with a stable VcbCondition.
|
||||
//
|
||||
|
||||
CdAcquireVcbShared( IrpContext, Vcb, FALSE);
|
||||
|
||||
//
|
||||
// If the verify operation completed it will return
|
||||
// either STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly.
|
||||
//
|
||||
// If CdVerifyVolume encountered an error during
|
||||
// processing, it will return that error. If we got
|
||||
// STATUS_WRONG_VOLUME from the verify, and our volume
|
||||
// is now mounted, commute the status to STATUS_SUCCESS.
|
||||
//
|
||||
|
||||
if ((Status == STATUS_WRONG_VOLUME) &&
|
||||
(Vcb->VcbCondition == VcbMounted)) {
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
else if ((STATUS_SUCCESS == Status) && (Vcb->VcbCondition != VcbMounted)) {
|
||||
|
||||
//
|
||||
// If the verify succeeded, but our volume is not mounted,
|
||||
// then some other volume is on the device.
|
||||
//
|
||||
|
||||
Status = STATUS_WRONG_VOLUME;
|
||||
}
|
||||
|
||||
//
|
||||
// Do a quick unprotected check here. The routine will do
|
||||
// a safe check. After here we can release the resource.
|
||||
// Note that if the volume really went away, we will be taking
|
||||
// the Reparse path.
|
||||
//
|
||||
|
||||
//
|
||||
// If the device might need to go away then call our dismount routine.
|
||||
//
|
||||
|
||||
if (((Vcb->VcbCondition == VcbNotMounted) ||
|
||||
(Vcb->VcbCondition == VcbInvalid) ||
|
||||
(Vcb->VcbCondition == VcbDismountInProgress)) &&
|
||||
(Vcb->VcbReference <= CDFS_RESIDUAL_REFERENCE)) {
|
||||
|
||||
CdReleaseVcb( IrpContext, Vcb);
|
||||
|
||||
CdAcquireCdData( IrpContext );
|
||||
CdCheckForDismount( IrpContext, Vcb, FALSE );
|
||||
CdReleaseCdData( IrpContext );
|
||||
}
|
||||
else {
|
||||
|
||||
CdReleaseVcb( IrpContext, Vcb);
|
||||
}
|
||||
|
||||
//
|
||||
// If this is a create and the verify succeeded then complete the
|
||||
// request with a REPARSE status.
|
||||
//
|
||||
|
||||
if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
|
||||
(IrpSp->FileObject->RelatedFileObject == NULL) &&
|
||||
((Status == STATUS_SUCCESS) || (Status == STATUS_WRONG_VOLUME))) {
|
||||
|
||||
Irp->IoStatus.Information = IO_REMOUNT;
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_REPARSE );
|
||||
Status = STATUS_REPARSE;
|
||||
Irp = NULL;
|
||||
IrpContext = NULL;
|
||||
|
||||
//
|
||||
// If there is still an error to process then call the Io system
|
||||
// for a popup.
|
||||
//
|
||||
|
||||
} else if ((Irp != NULL) && !NT_SUCCESS( Status )) {
|
||||
|
||||
//
|
||||
// Fill in the device object if required.
|
||||
//
|
||||
|
||||
if (IoIsErrorUserInduced( Status ) ) {
|
||||
|
||||
IoSetHardErrorOrVerifyDevice( Irp, DeviceToVerify );
|
||||
}
|
||||
|
||||
CdNormalizeAndRaiseStatus( IrpContext, Status );
|
||||
}
|
||||
|
||||
//
|
||||
// If there is still an Irp, send it off to an Ex Worker thread.
|
||||
//
|
||||
|
||||
if (IrpContext != NULL) {
|
||||
|
||||
Status = CdFsdPostRequest( IrpContext, Irp );
|
||||
}
|
||||
|
||||
} except(CdExceptionFilter( IrpContext, GetExceptionInformation() )) {
|
||||
|
||||
//
|
||||
// We had some trouble trying to perform the verify or raised
|
||||
// an error ourselves. So we'll abort the I/O request with
|
||||
// the error status that we get back from the execption code.
|
||||
//
|
||||
|
||||
Status = CdProcessException( IrpContext, Irp, GetExceptionCode() );
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdCheckForDismount (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN BOOLEAN Force
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to check if a volume is ready for dismount. This
|
||||
occurs when only file system references are left on the volume.
|
||||
|
||||
If the dismount is not currently underway and the user reference count
|
||||
has gone to zero then we can begin the dismount.
|
||||
|
||||
If the dismount is in progress and there are no references left on the
|
||||
volume (we check the Vpb for outstanding references as well to catch
|
||||
any create calls dispatched to the file system) then we can delete
|
||||
the Vcb.
|
||||
|
||||
Arguments:
|
||||
|
||||
Vcb - Vcb for the volume to try to dismount.
|
||||
|
||||
Force - Whether we will force this volume to be dismounted.
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - True if the Vcb was not gone by the time this function finished,
|
||||
False if it was deleted.
|
||||
|
||||
This is only a trustworthy indication to the caller if it had the vcb
|
||||
exclusive itself.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
BOOLEAN UnlockVcb = TRUE;
|
||||
BOOLEAN VcbPresent = TRUE;
|
||||
KIRQL SavedIrql;
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_VCB( Vcb );
|
||||
|
||||
ASSERT_EXCLUSIVE_CDDATA;
|
||||
|
||||
//
|
||||
// Acquire and lock this Vcb to check the dismount state.
|
||||
//
|
||||
|
||||
CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
|
||||
|
||||
//
|
||||
// Lets get rid of any pending closes for this volume.
|
||||
//
|
||||
|
||||
CdFspClose( Vcb );
|
||||
|
||||
CdLockVcb( IrpContext, Vcb );
|
||||
|
||||
//
|
||||
// If the dismount is not already underway then check if the
|
||||
// user reference count has gone to zero or we are being forced
|
||||
// to disconnect. If so start the teardown on the Vcb.
|
||||
//
|
||||
|
||||
if (Vcb->VcbCondition != VcbDismountInProgress) {
|
||||
|
||||
if (Vcb->VcbUserReference <= CDFS_RESIDUAL_USER_REFERENCE || Force) {
|
||||
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
UnlockVcb = FALSE;
|
||||
VcbPresent = CdDismountVcb( IrpContext, Vcb );
|
||||
}
|
||||
|
||||
//
|
||||
// If the teardown is underway and there are absolutely no references
|
||||
// remaining then delete the Vcb. References here include the
|
||||
// references in the Vcb and Vpb.
|
||||
//
|
||||
|
||||
} else if (Vcb->VcbReference == 0) {
|
||||
|
||||
IoAcquireVpbSpinLock( &SavedIrql );
|
||||
|
||||
//
|
||||
// If there are no file objects and no reference counts in the
|
||||
// Vpb we can delete the Vcb. Don't forget that we have the
|
||||
// last reference in the Vpb.
|
||||
//
|
||||
|
||||
if (Vcb->Vpb->ReferenceCount == 1) {
|
||||
|
||||
IoReleaseVpbSpinLock( SavedIrql );
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
UnlockVcb = FALSE;
|
||||
CdDeleteVcb( IrpContext, Vcb );
|
||||
VcbPresent = FALSE;
|
||||
|
||||
} else {
|
||||
|
||||
IoReleaseVpbSpinLock( SavedIrql );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Unlock the Vcb if still held.
|
||||
//
|
||||
|
||||
if (UnlockVcb) {
|
||||
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
}
|
||||
|
||||
//
|
||||
// Release any resources still acquired.
|
||||
//
|
||||
|
||||
if (VcbPresent) {
|
||||
|
||||
CdReleaseVcb( IrpContext, Vcb );
|
||||
}
|
||||
|
||||
return VcbPresent;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdMarkDevForVerifyIfVcbMounted(
|
||||
IN PVCB Vcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine checks to see if the specified Vcb is currently mounted on
|
||||
the device or not. If it is, it sets the verify flag on the device, if
|
||||
not then the state is noted in the Vcb.
|
||||
|
||||
Arguments:
|
||||
|
||||
Vcb - This is the volume to check.
|
||||
|
||||
Return Value:
|
||||
|
||||
TRUE if the device has been marked for verify here, FALSE otherwise.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
BOOLEAN Marked = FALSE;
|
||||
KIRQL SavedIrql;
|
||||
|
||||
IoAcquireVpbSpinLock( &SavedIrql );
|
||||
|
||||
if (Vcb->Vpb->RealDevice->Vpb == Vcb->Vpb) {
|
||||
|
||||
CdMarkRealDevForVerify( Vcb->Vpb->RealDevice);
|
||||
Marked = TRUE;
|
||||
}
|
||||
else {
|
||||
|
||||
//
|
||||
// Flag this to avoid the VPB spinlock in future passes.
|
||||
//
|
||||
|
||||
SetFlag( Vcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE);
|
||||
}
|
||||
|
||||
IoReleaseVpbSpinLock( SavedIrql );
|
||||
|
||||
return Marked;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdVerifyVcb (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine checks that the current Vcb is valid and currently mounted
|
||||
on the device. It will raise on an error condition.
|
||||
|
||||
We check whether the volume needs verification and the current state
|
||||
of the Vcb.
|
||||
|
||||
Arguments:
|
||||
|
||||
Vcb - This is the volume to verify.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
IO_STATUS_BLOCK Iosb;
|
||||
ULONG MediaChangeCount = 0;
|
||||
BOOLEAN ForceVerify = FALSE;
|
||||
BOOLEAN DevMarkedForVerify;
|
||||
KIRQL SavedIrql;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Fail immediately if the volume is in the progress of being dismounted
|
||||
// or has been marked invalid.
|
||||
//
|
||||
|
||||
if ((Vcb->VcbCondition == VcbInvalid) ||
|
||||
((Vcb->VcbCondition == VcbDismountInProgress) &&
|
||||
(IrpContext->MajorFunction != IRP_MJ_CREATE))) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_FILE_INVALID );
|
||||
}
|
||||
|
||||
if (FlagOn( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA )) {
|
||||
|
||||
//
|
||||
// Capture the real device verify state.
|
||||
//
|
||||
|
||||
DevMarkedForVerify = CdRealDevNeedsVerify( Vcb->Vpb->RealDevice);
|
||||
|
||||
//
|
||||
// If the media is removable and the verify volume flag in the
|
||||
// device object is not set then we want to ping the device
|
||||
// to see if it needs to be verified.
|
||||
//
|
||||
|
||||
if (Vcb->VcbCondition != VcbMountInProgress) {
|
||||
|
||||
Status = CdPerformDevIoCtrl( IrpContext,
|
||||
IOCTL_CDROM_CHECK_VERIFY,
|
||||
Vcb->TargetDeviceObject,
|
||||
&MediaChangeCount,
|
||||
sizeof(ULONG),
|
||||
FALSE,
|
||||
FALSE,
|
||||
&Iosb );
|
||||
|
||||
if (Iosb.Information != sizeof(ULONG)) {
|
||||
|
||||
//
|
||||
// Be safe about the count in case the driver didn't fill it in
|
||||
//
|
||||
|
||||
MediaChangeCount = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// There are four cases when we want to do a verify. These are the
|
||||
// first three.
|
||||
//
|
||||
// 1. We are mounted, and the device has become empty
|
||||
// 2. The device has returned verify required (=> DO_VERIFY_VOL flag is
|
||||
// set, but could be due to hardware condition)
|
||||
// 3. Media change count doesn't match the one in the Vcb
|
||||
//
|
||||
|
||||
if (((Vcb->VcbCondition == VcbMounted) &&
|
||||
CdIsRawDevice( IrpContext, Status ))
|
||||
||
|
||||
(Status == STATUS_VERIFY_REQUIRED)
|
||||
||
|
||||
(NT_SUCCESS(Status) &&
|
||||
(Vcb->MediaChangeCount != MediaChangeCount))) {
|
||||
|
||||
//
|
||||
// If we are currently the volume on the device then it is our
|
||||
// responsibility to set the verify flag. If we're not on the device,
|
||||
// then we shouldn't touch the flag.
|
||||
//
|
||||
|
||||
if (!FlagOn( Vcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE) &&
|
||||
!DevMarkedForVerify) {
|
||||
|
||||
DevMarkedForVerify = CdMarkDevForVerifyIfVcbMounted( Vcb);
|
||||
}
|
||||
|
||||
ForceVerify = TRUE;
|
||||
|
||||
//
|
||||
// NOTE that we no longer update the media change count here. We
|
||||
// do so only when we've actually completed a verify at a particular
|
||||
// change count value.
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// This is the 4th verify case.
|
||||
//
|
||||
// We ALWAYS force CREATE requests on unmounted volumes through the
|
||||
// verify path. These requests could have been in limbo between
|
||||
// IoCheckMountedVpb and us when a verify/mount took place and caused
|
||||
// a completely different fs/volume to be mounted. In this case the
|
||||
// checks above may not have caught the condition, since we may already
|
||||
// have verified (wrong volume) and decided that we have nothing to do.
|
||||
// We want the requests to be re routed to the currently mounted volume,
|
||||
// since they were directed at the 'drive', not our volume.
|
||||
//
|
||||
|
||||
if (NT_SUCCESS( Status) && !ForceVerify &&
|
||||
(IrpContext->MajorFunction == IRP_MJ_CREATE)) {
|
||||
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->Irp);
|
||||
|
||||
ForceVerify = (IrpSp->FileObject->RelatedFileObject == NULL) &&
|
||||
((Vcb->VcbCondition == VcbDismountInProgress) ||
|
||||
(Vcb->VcbCondition == VcbNotMounted));
|
||||
|
||||
//
|
||||
// Note that we don't touch the device verify flag here. It required
|
||||
// it would have been caught and set by the first set of checks.
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
// Raise the verify / error if neccessary.
|
||||
//
|
||||
|
||||
if (ForceVerify || !NT_SUCCESS( Status)) {
|
||||
|
||||
IoSetHardErrorOrVerifyDevice( IrpContext->Irp,
|
||||
Vcb->Vpb->RealDevice );
|
||||
|
||||
CdRaiseStatus( IrpContext, ForceVerify ? STATUS_VERIFY_REQUIRED : Status);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Based on the condition of the Vcb we'll either return to our
|
||||
// caller or raise an error condition
|
||||
//
|
||||
|
||||
switch (Vcb->VcbCondition) {
|
||||
|
||||
case VcbNotMounted:
|
||||
|
||||
IoSetHardErrorOrVerifyDevice( IrpContext->Irp, Vcb->Vpb->RealDevice );
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_WRONG_VOLUME );
|
||||
break;
|
||||
|
||||
case VcbInvalid:
|
||||
case VcbDismountInProgress :
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_FILE_INVALID );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdVerifyFcbOperation (
|
||||
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
||||
IN PFCB Fcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to verify that the state of the Fcb is valid
|
||||
to allow the current operation to continue. We use the state of the
|
||||
Vcb, target device and type of operation to determine this.
|
||||
|
||||
Arguments:
|
||||
|
||||
IrpContext - IrpContext for the request. If not present then we
|
||||
were called from the fast IO path.
|
||||
|
||||
Fcb - Fcb to perform the request on.
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - TRUE if the request can continue, FALSE otherwise.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PVCB Vcb = Fcb->Vcb;
|
||||
PDEVICE_OBJECT RealDevice = Vcb->Vpb->RealDevice;
|
||||
PIRP Irp;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Check that the fileobject has not been cleaned up.
|
||||
//
|
||||
|
||||
if ( ARGUMENT_PRESENT( IrpContext )) {
|
||||
|
||||
PFILE_OBJECT FileObject;
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
FileObject = IoGetCurrentIrpStackLocation( Irp)->FileObject;
|
||||
|
||||
if ( FileObject && FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE)) {
|
||||
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
//
|
||||
// Following FAT, we allow certain operations even on cleaned up
|
||||
// file objects. Everything else, we fail.
|
||||
//
|
||||
|
||||
if ( (FlagOn(Irp->Flags, IRP_PAGING_IO)) ||
|
||||
(IrpSp->MajorFunction == IRP_MJ_CLOSE ) ||
|
||||
(IrpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) ||
|
||||
( (IrpSp->MajorFunction == IRP_MJ_READ) &&
|
||||
FlagOn(IrpSp->MinorFunction, IRP_MN_COMPLETE) ) ) {
|
||||
|
||||
NOTHING;
|
||||
|
||||
} else {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_FILE_CLOSED );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Fail immediately if the volume is in the progress of being dismounted
|
||||
// or has been marked invalid.
|
||||
//
|
||||
|
||||
if ((Vcb->VcbCondition == VcbInvalid) ||
|
||||
(Vcb->VcbCondition == VcbDismountInProgress)) {
|
||||
|
||||
if (ARGUMENT_PRESENT( IrpContext )) {
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_FILE_INVALID );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Always fail if the volume needs to be verified.
|
||||
//
|
||||
|
||||
if (CdRealDevNeedsVerify( RealDevice)) {
|
||||
|
||||
if (ARGUMENT_PRESENT( IrpContext )) {
|
||||
|
||||
IoSetHardErrorOrVerifyDevice( IrpContext->Irp,
|
||||
RealDevice );
|
||||
|
||||
CdRaiseStatus( IrpContext, STATUS_VERIFY_REQUIRED );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
//
|
||||
//
|
||||
// All operations are allowed on mounted.
|
||||
//
|
||||
|
||||
} else if ((Vcb->VcbCondition == VcbMounted) ||
|
||||
(Vcb->VcbCondition == VcbMountInProgress)) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
//
|
||||
// Fail all requests for fast Io on other Vcb conditions.
|
||||
//
|
||||
|
||||
} else if (!ARGUMENT_PRESENT( IrpContext )) {
|
||||
|
||||
return FALSE;
|
||||
|
||||
//
|
||||
// The remaining case is VcbNotMounted.
|
||||
// Mark the device to be verified and raise WRONG_VOLUME.
|
||||
//
|
||||
|
||||
} else if (Vcb->VcbCondition == VcbNotMounted) {
|
||||
|
||||
if (ARGUMENT_PRESENT( IrpContext )) {
|
||||
|
||||
IoSetHardErrorOrVerifyDevice( IrpContext->Irp, RealDevice );
|
||||
CdRaiseStatus( IrpContext, STATUS_WRONG_VOLUME );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
CdDismountVcb (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called when all of the user references to a volume are
|
||||
gone. We will initiate all of the teardown any system resources.
|
||||
|
||||
If all of the references to this volume are gone at the end of this routine
|
||||
then we will complete the teardown of this Vcb and mark the current Vpb
|
||||
as not mounted. Otherwise we will allocated a new Vpb for this device
|
||||
and keep the current Vpb attached to the Vcb.
|
||||
|
||||
Arguments:
|
||||
|
||||
Vcb - Vcb for the volume to dismount.
|
||||
|
||||
Return Value:
|
||||
|
||||
BOOLEAN - TRUE if we didn't delete the Vcb, FALSE otherwise.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PVPB OldVpb;
|
||||
BOOLEAN VcbPresent = TRUE;
|
||||
KIRQL SavedIrql;
|
||||
|
||||
BOOLEAN FinalReference;
|
||||
|
||||
ASSERT_EXCLUSIVE_CDDATA;
|
||||
ASSERT_EXCLUSIVE_VCB( Vcb );
|
||||
|
||||
CdLockVcb( IrpContext, Vcb );
|
||||
|
||||
//
|
||||
// We should only take this path once.
|
||||
//
|
||||
|
||||
ASSERT( Vcb->VcbCondition != VcbDismountInProgress );
|
||||
|
||||
//
|
||||
// Mark the Vcb as DismountInProgress.
|
||||
//
|
||||
|
||||
Vcb->VcbCondition = VcbDismountInProgress;
|
||||
|
||||
if (Vcb->XASector != NULL) {
|
||||
|
||||
CdFreePool( &Vcb->XASector );
|
||||
Vcb->XASector = 0;
|
||||
Vcb->XADiskOffset = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Remove our reference to the internal Fcb's. The Fcb's will then
|
||||
// be removed in the purge path below.
|
||||
//
|
||||
|
||||
if (Vcb->RootIndexFcb != NULL) {
|
||||
|
||||
Vcb->RootIndexFcb->FcbReference -= 1;
|
||||
Vcb->RootIndexFcb->FcbUserReference -= 1;
|
||||
}
|
||||
|
||||
if (Vcb->PathTableFcb != NULL) {
|
||||
|
||||
Vcb->PathTableFcb->FcbReference -= 1;
|
||||
Vcb->PathTableFcb->FcbUserReference -= 1;
|
||||
}
|
||||
|
||||
if (Vcb->VolumeDasdFcb != NULL) {
|
||||
|
||||
Vcb->VolumeDasdFcb->FcbReference -= 1;
|
||||
Vcb->VolumeDasdFcb->FcbUserReference -= 1;
|
||||
}
|
||||
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
|
||||
//
|
||||
// Purge the volume.
|
||||
//
|
||||
|
||||
CdPurgeVolume( IrpContext, Vcb, TRUE );
|
||||
|
||||
//
|
||||
// Empty the delayed and async close queues.
|
||||
//
|
||||
|
||||
CdFspClose( Vcb );
|
||||
|
||||
OldVpb = Vcb->Vpb;
|
||||
|
||||
//
|
||||
// Remove the mount volume reference.
|
||||
//
|
||||
|
||||
CdLockVcb( IrpContext, Vcb );
|
||||
Vcb->VcbReference -= 1;
|
||||
|
||||
//
|
||||
// Acquire the Vpb spinlock to check for Vpb references.
|
||||
//
|
||||
|
||||
IoAcquireVpbSpinLock( &SavedIrql );
|
||||
|
||||
//
|
||||
// Remember if this is the last reference on this Vcb. We incremented
|
||||
// the count on the Vpb earlier so we get one last crack it. If our
|
||||
// reference has gone to zero but the vpb reference count is greater
|
||||
// than zero then the Io system will be responsible for deleting the
|
||||
// Vpb.
|
||||
//
|
||||
|
||||
FinalReference = (BOOLEAN) ((Vcb->VcbReference == 0) &&
|
||||
(OldVpb->ReferenceCount == 1));
|
||||
|
||||
//
|
||||
// There is a reference count in the Vpb and in the Vcb. We have
|
||||
// incremented the reference count in the Vpb to make sure that
|
||||
// we have last crack at it. If this is a failed mount then we
|
||||
// want to return the Vpb to the IO system to use for the next
|
||||
// mount request.
|
||||
//
|
||||
|
||||
if (OldVpb->RealDevice->Vpb == OldVpb) {
|
||||
|
||||
//
|
||||
// If not the final reference then swap out the Vpb. We must
|
||||
// preserve the REMOVE_PENDING flag so that the device is
|
||||
// not remounted in the middle of a PnP remove operation.
|
||||
//
|
||||
|
||||
if (!FinalReference) {
|
||||
|
||||
ASSERT( Vcb->SwapVpb != NULL );
|
||||
|
||||
Vcb->SwapVpb->Type = IO_TYPE_VPB;
|
||||
Vcb->SwapVpb->Size = sizeof( VPB );
|
||||
Vcb->SwapVpb->RealDevice = OldVpb->RealDevice;
|
||||
|
||||
Vcb->SwapVpb->RealDevice->Vpb = Vcb->SwapVpb;
|
||||
|
||||
Vcb->SwapVpb->Flags = FlagOn( OldVpb->Flags, VPB_REMOVE_PENDING );
|
||||
|
||||
IoReleaseVpbSpinLock( SavedIrql );
|
||||
|
||||
//
|
||||
// Indicate we used up the swap.
|
||||
//
|
||||
|
||||
Vcb->SwapVpb = NULL;
|
||||
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
|
||||
//
|
||||
// We want to leave the Vpb for the IO system. Mark it
|
||||
// as being not mounted. Go ahead and delete the Vcb as
|
||||
// well.
|
||||
//
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Make sure to remove the last reference on the Vpb.
|
||||
//
|
||||
|
||||
OldVpb->ReferenceCount -= 1;
|
||||
|
||||
OldVpb->DeviceObject = NULL;
|
||||
ClearFlag( Vcb->Vpb->Flags, VPB_MOUNTED );
|
||||
ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED );
|
||||
|
||||
//
|
||||
// Clear the Vpb flag so we know not to delete it.
|
||||
//
|
||||
|
||||
Vcb->Vpb = NULL;
|
||||
|
||||
IoReleaseVpbSpinLock( SavedIrql );
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
CdDeleteVcb( IrpContext, Vcb );
|
||||
VcbPresent = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Someone has already swapped in a new Vpb. If this is the final reference
|
||||
// then the file system is responsible for deleting the Vpb.
|
||||
//
|
||||
|
||||
} else if (FinalReference) {
|
||||
|
||||
//
|
||||
// Make sure to remove the last reference on the Vpb.
|
||||
//
|
||||
|
||||
OldVpb->ReferenceCount -= 1;
|
||||
|
||||
IoReleaseVpbSpinLock( SavedIrql );
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
CdDeleteVcb( IrpContext, Vcb );
|
||||
VcbPresent = FALSE;
|
||||
|
||||
//
|
||||
// The current Vpb is no longer the Vpb for the device (the IO system
|
||||
// has already allocated a new one). We leave our reference in the
|
||||
// Vpb and will be responsible for deleting it at a later time.
|
||||
//
|
||||
|
||||
} else {
|
||||
|
||||
IoReleaseVpbSpinLock( SavedIrql );
|
||||
CdUnlockVcb( IrpContext, Vcb );
|
||||
}
|
||||
|
||||
//
|
||||
// Let our caller know whether the Vcb is still present.
|
||||
//
|
||||
|
||||
return VcbPresent;
|
||||
}
|
||||
|
||||
+502
@@ -0,0 +1,502 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
VolInfo.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the volume information routines for Cdfs called by
|
||||
the dispatch driver.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_VOLINFO)
|
||||
|
||||
//
|
||||
// Local support routines
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
CdQueryFsVolumeInfo (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PFILE_FS_VOLUME_INFORMATION Buffer,
|
||||
IN OUT PULONG Length
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdQueryFsSizeInfo (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PFILE_FS_SIZE_INFORMATION Buffer,
|
||||
IN OUT PULONG Length
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdQueryFsDeviceInfo (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PFILE_FS_DEVICE_INFORMATION Buffer,
|
||||
IN OUT PULONG Length
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdQueryFsAttributeInfo (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
|
||||
IN OUT PULONG Length
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdCommonQueryVolInfo)
|
||||
#pragma alloc_text(PAGE, CdQueryFsAttributeInfo)
|
||||
#pragma alloc_text(PAGE, CdQueryFsDeviceInfo)
|
||||
#pragma alloc_text(PAGE, CdQueryFsSizeInfo)
|
||||
#pragma alloc_text(PAGE, CdQueryFsVolumeInfo)
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdCommonQueryVolInfo (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the common routine for querying volume information called by both
|
||||
the fsd and fsp threads.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Supplies the Irp being processed
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - The return status for the operation
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
ULONG Length;
|
||||
|
||||
TYPE_OF_OPEN TypeOfOpen;
|
||||
PFCB Fcb;
|
||||
PCCB Ccb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Reference our input parameters to make things easier
|
||||
//
|
||||
|
||||
Length = IrpSp->Parameters.QueryVolume.Length;
|
||||
|
||||
//
|
||||
// Decode the file object and fail if this an unopened file object.
|
||||
//
|
||||
|
||||
TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
|
||||
|
||||
if (TypeOfOpen == UnopenedFileObject) {
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Acquire the Vcb for this volume.
|
||||
//
|
||||
|
||||
CdAcquireVcbShared( IrpContext, Fcb->Vcb, FALSE );
|
||||
|
||||
//
|
||||
// Use a try-finally to facilitate cleanup.
|
||||
//
|
||||
|
||||
try {
|
||||
|
||||
//
|
||||
// Verify the Vcb.
|
||||
//
|
||||
|
||||
CdVerifyVcb( IrpContext, Fcb->Vcb );
|
||||
|
||||
//
|
||||
// Based on the information class we'll do different actions. Each
|
||||
// of the procedures that we're calling fills up the output buffer
|
||||
// if possible and returns true if it successfully filled the buffer
|
||||
// and false if it couldn't wait for any I/O to complete.
|
||||
//
|
||||
|
||||
switch (IrpSp->Parameters.QueryVolume.FsInformationClass) {
|
||||
|
||||
case FileFsSizeInformation:
|
||||
|
||||
Status = CdQueryFsSizeInfo( IrpContext, Fcb->Vcb, Irp->AssociatedIrp.SystemBuffer, &Length );
|
||||
break;
|
||||
|
||||
case FileFsVolumeInformation:
|
||||
|
||||
Status = CdQueryFsVolumeInfo( IrpContext, Fcb->Vcb, Irp->AssociatedIrp.SystemBuffer, &Length );
|
||||
break;
|
||||
|
||||
case FileFsDeviceInformation:
|
||||
|
||||
Status = CdQueryFsDeviceInfo( IrpContext, Fcb->Vcb, Irp->AssociatedIrp.SystemBuffer, &Length );
|
||||
break;
|
||||
|
||||
case FileFsAttributeInformation:
|
||||
|
||||
Status = CdQueryFsAttributeInfo( IrpContext, Fcb->Vcb, Irp->AssociatedIrp.SystemBuffer, &Length );
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the information field to the number of bytes actually filled in
|
||||
//
|
||||
|
||||
Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length;
|
||||
|
||||
} finally {
|
||||
|
||||
//
|
||||
// Release the Vcb.
|
||||
//
|
||||
|
||||
CdReleaseVcb( IrpContext, Fcb->Vcb );
|
||||
}
|
||||
|
||||
//
|
||||
// Complete the request if we didn't raise.
|
||||
//
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, Status );
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
CdQueryFsVolumeInfo (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PFILE_FS_VOLUME_INFORMATION Buffer,
|
||||
IN OUT PULONG Length
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine implements the query volume info call
|
||||
|
||||
Arguments:
|
||||
|
||||
Vcb - Vcb for this volume.
|
||||
|
||||
Buffer - Supplies a pointer to the output buffer where the information
|
||||
is to be returned
|
||||
|
||||
Length - Supplies the length of the buffer in byte. This variable
|
||||
upon return recieves the remaining bytes free in the buffer
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - Returns the status for the query
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ULONG BytesToCopy;
|
||||
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Fill in the data from the Vcb.
|
||||
//
|
||||
|
||||
Buffer->VolumeCreationTime = *((PLARGE_INTEGER) &Vcb->VolumeDasdFcb->CreationTime);
|
||||
Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
|
||||
|
||||
Buffer->SupportsObjects = FALSE;
|
||||
|
||||
*Length -= FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel[0] );
|
||||
|
||||
//
|
||||
// Check if the buffer we're given is long enough
|
||||
//
|
||||
|
||||
if (*Length >= (ULONG) Vcb->Vpb->VolumeLabelLength) {
|
||||
|
||||
BytesToCopy = Vcb->Vpb->VolumeLabelLength;
|
||||
|
||||
} else {
|
||||
|
||||
BytesToCopy = *Length;
|
||||
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
//
|
||||
// Copy over what we can of the volume label, and adjust *Length
|
||||
//
|
||||
|
||||
Buffer->VolumeLabelLength = BytesToCopy;
|
||||
|
||||
if (BytesToCopy) {
|
||||
|
||||
RtlCopyMemory( &Buffer->VolumeLabel[0],
|
||||
&Vcb->Vpb->VolumeLabel[0],
|
||||
BytesToCopy );
|
||||
}
|
||||
|
||||
*Length -= BytesToCopy;
|
||||
|
||||
//
|
||||
// Set our status and return to our caller
|
||||
//
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
CdQueryFsSizeInfo (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PFILE_FS_SIZE_INFORMATION Buffer,
|
||||
IN OUT PULONG Length
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine implements the query volume size call.
|
||||
|
||||
Arguments:
|
||||
|
||||
Vcb - Vcb for this volume.
|
||||
|
||||
Buffer - Supplies a pointer to the output buffer where the information
|
||||
is to be returned
|
||||
|
||||
Length - Supplies the length of the buffer in byte. This variable
|
||||
upon return recieves the remaining bytes free in the buffer
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - Returns the status for the query
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Fill in the output buffer.
|
||||
//
|
||||
|
||||
Buffer->TotalAllocationUnits.QuadPart = LlSectorsFromBytes( Vcb->VolumeDasdFcb->AllocationSize.QuadPart );
|
||||
|
||||
Buffer->AvailableAllocationUnits.QuadPart = 0;
|
||||
Buffer->SectorsPerAllocationUnit = 1;
|
||||
Buffer->BytesPerSector = SECTOR_SIZE;
|
||||
|
||||
//
|
||||
// Adjust the length variable
|
||||
//
|
||||
|
||||
*Length -= sizeof( FILE_FS_SIZE_INFORMATION );
|
||||
|
||||
//
|
||||
// And return success to our caller
|
||||
//
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
CdQueryFsDeviceInfo (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PFILE_FS_DEVICE_INFORMATION Buffer,
|
||||
IN OUT PULONG Length
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine implements the query volume device call.
|
||||
|
||||
Arguments:
|
||||
|
||||
Vcb - Vcb for this volume.
|
||||
|
||||
Buffer - Supplies a pointer to the output buffer where the information
|
||||
is to be returned
|
||||
|
||||
Length - Supplies the length of the buffer in byte. This variable
|
||||
upon return recieves the remaining bytes free in the buffer
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - Returns the status for the query
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Update the output buffer.
|
||||
//
|
||||
|
||||
Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics;
|
||||
Buffer->DeviceType = FILE_DEVICE_CD_ROM;
|
||||
|
||||
//
|
||||
// Adjust the length variable
|
||||
//
|
||||
|
||||
*Length -= sizeof( FILE_FS_DEVICE_INFORMATION );
|
||||
|
||||
//
|
||||
// And return success to our caller
|
||||
//
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
CdQueryFsAttributeInfo (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PVCB Vcb,
|
||||
IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
|
||||
IN OUT PULONG Length
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine implements the query volume attribute call.
|
||||
|
||||
Arguments:
|
||||
|
||||
Vcb - Vcb for this volume.
|
||||
|
||||
Buffer - Supplies a pointer to the output buffer where the information
|
||||
is to be returned
|
||||
|
||||
Length - Supplies the length of the buffer in byte. This variable
|
||||
upon return recieves the remaining bytes free in the buffer
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - Returns the status for the query
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ULONG BytesToCopy;
|
||||
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Fill out the fixed portion of the buffer.
|
||||
//
|
||||
|
||||
Buffer->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH |
|
||||
FILE_READ_ONLY_VOLUME;
|
||||
|
||||
if (FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_JOLIET )) {
|
||||
|
||||
SetFlag( Buffer->FileSystemAttributes, FILE_UNICODE_ON_DISK );
|
||||
|
||||
Buffer->MaximumComponentNameLength = 110;
|
||||
|
||||
} else {
|
||||
|
||||
Buffer->MaximumComponentNameLength = 221;
|
||||
}
|
||||
|
||||
*Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName );
|
||||
|
||||
//
|
||||
// Make sure we can copy full unicode characters.
|
||||
//
|
||||
|
||||
ClearFlag( *Length, 1 );
|
||||
|
||||
//
|
||||
// Determine how much of the file system name will fit.
|
||||
//
|
||||
|
||||
if (*Length >= 8) {
|
||||
|
||||
BytesToCopy = 8;
|
||||
|
||||
} else {
|
||||
|
||||
BytesToCopy = *Length;
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
*Length -= BytesToCopy;
|
||||
|
||||
//
|
||||
// Do the file system name.
|
||||
//
|
||||
|
||||
Buffer->FileSystemNameLength = BytesToCopy;
|
||||
|
||||
RtlCopyMemory( &Buffer->FileSystemName[0], L"CDFS", BytesToCopy );
|
||||
|
||||
//
|
||||
// And return to our caller
|
||||
//
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
+398
@@ -0,0 +1,398 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 1989-2000 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
WorkQue.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the Work queue routines for the Cdfs File
|
||||
system.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "CdProcs.h"
|
||||
|
||||
//
|
||||
// The Bug check file id for this module
|
||||
//
|
||||
|
||||
#define BugCheckFileId (CDFS_BUG_CHECK_WORKQUE)
|
||||
|
||||
//
|
||||
// The following constant is the maximum number of ExWorkerThreads that we
|
||||
// will allow to be servicing a particular target device at any one time.
|
||||
//
|
||||
|
||||
#define FSP_PER_DEVICE_THRESHOLD (2)
|
||||
|
||||
//
|
||||
// Local support routines
|
||||
//
|
||||
|
||||
VOID
|
||||
CdAddToWorkque (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, CdFsdPostRequest)
|
||||
#pragma alloc_text(PAGE, CdOplockComplete)
|
||||
#pragma alloc_text(PAGE, CdPrePostIrp)
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdFsdPostRequest (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine enqueues the request packet specified by IrpContext to the
|
||||
work queue associated with the FileSystemDeviceObject. This is a FSD
|
||||
routine.
|
||||
|
||||
Arguments:
|
||||
|
||||
IrpContext - Pointer to the IrpContext to be queued to the Fsp.
|
||||
|
||||
Irp - I/O Request Packet.
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_PENDING
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_IRP( Irp );
|
||||
|
||||
//
|
||||
// Posting is a three step operation. First lock down any buffers
|
||||
// in the Irp. Next cleanup the IrpContext for the post and finally
|
||||
// add this to a workque.
|
||||
//
|
||||
|
||||
CdPrePostIrp( IrpContext, Irp );
|
||||
|
||||
CdAddToWorkque( IrpContext, Irp );
|
||||
|
||||
//
|
||||
// And return to our caller
|
||||
//
|
||||
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdPrePostIrp (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine performs any neccessary work before STATUS_PENDING is
|
||||
returned with the Fsd thread. This routine is called within the
|
||||
filesystem and by the oplock package.
|
||||
|
||||
Arguments:
|
||||
|
||||
Context - Pointer to the IrpContext to be queued to the Fsp
|
||||
|
||||
Irp - I/O Request Packet.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
BOOLEAN RemovedFcb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT_IRP_CONTEXT( IrpContext );
|
||||
ASSERT_IRP( Irp );
|
||||
|
||||
//
|
||||
// Case on the type of the operation.
|
||||
//
|
||||
|
||||
switch (IrpContext->MajorFunction) {
|
||||
|
||||
case IRP_MJ_CREATE :
|
||||
|
||||
//
|
||||
// If called from the oplock package then there is an
|
||||
// Fcb to possibly teardown. We will call the teardown
|
||||
// routine and release the Fcb if still present. The cleanup
|
||||
// code in create will know not to release this Fcb because
|
||||
// we will clear the pointer.
|
||||
//
|
||||
|
||||
if ((IrpContext->TeardownFcb != NULL) &&
|
||||
*(IrpContext->TeardownFcb) != NULL) {
|
||||
|
||||
CdTeardownStructures( IrpContext, *(IrpContext->TeardownFcb), &RemovedFcb );
|
||||
|
||||
if (!RemovedFcb) {
|
||||
|
||||
CdReleaseFcb( IrpContext, *(IrpContext->TeardownFcb) );
|
||||
}
|
||||
|
||||
*(IrpContext->TeardownFcb) = NULL;
|
||||
IrpContext->TeardownFcb = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// We need to lock the user's buffer, unless this is an MDL-read,
|
||||
// in which case there is no user buffer.
|
||||
//
|
||||
|
||||
case IRP_MJ_READ :
|
||||
|
||||
if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
|
||||
|
||||
CdLockUserBuffer( IrpContext, IrpSp->Parameters.Read.Length );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// We also need to check whether this is a query file operation.
|
||||
//
|
||||
|
||||
case IRP_MJ_DIRECTORY_CONTROL :
|
||||
|
||||
if (IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
|
||||
|
||||
CdLockUserBuffer( IrpContext, IrpSp->Parameters.QueryDirectory.Length );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Cleanup the IrpContext for the post.
|
||||
//
|
||||
|
||||
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
|
||||
CdCleanupIrpContext( IrpContext, TRUE );
|
||||
|
||||
//
|
||||
// Mark the Irp to show that we've already returned pending to the user.
|
||||
//
|
||||
|
||||
IoMarkIrpPending( Irp );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CdOplockComplete (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called by the oplock package when an oplock break has
|
||||
completed, allowing an Irp to resume execution. If the status in
|
||||
the Irp is STATUS_SUCCESS, then we queue the Irp to the Fsp queue.
|
||||
Otherwise we complete the Irp with the status in the Irp.
|
||||
|
||||
If we are completing due to an error then check if there is any
|
||||
cleanup to do.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - I/O Request Packet.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
BOOLEAN RemovedFcb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Check on the return value in the Irp. If success then we
|
||||
// are to post this request.
|
||||
//
|
||||
|
||||
if (Irp->IoStatus.Status == STATUS_SUCCESS) {
|
||||
|
||||
//
|
||||
// Check if there is any cleanup work to do.
|
||||
//
|
||||
|
||||
switch (IrpContext->MajorFunction) {
|
||||
|
||||
case IRP_MJ_CREATE :
|
||||
|
||||
//
|
||||
// If called from the oplock package then there is an
|
||||
// Fcb to possibly teardown. We will call the teardown
|
||||
// routine and release the Fcb if still present. The cleanup
|
||||
// code in create will know not to release this Fcb because
|
||||
// we will clear the pointer.
|
||||
//
|
||||
|
||||
if (IrpContext->TeardownFcb != NULL) {
|
||||
|
||||
CdTeardownStructures( IrpContext, *(IrpContext->TeardownFcb), &RemovedFcb );
|
||||
|
||||
if (!RemovedFcb) {
|
||||
|
||||
CdReleaseFcb( IrpContext, *(IrpContext->TeardownFcb) );
|
||||
}
|
||||
|
||||
*(IrpContext->TeardownFcb) = NULL;
|
||||
IrpContext->TeardownFcb = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Insert the Irp context in the workqueue.
|
||||
//
|
||||
|
||||
CdAddToWorkque( IrpContext, Irp );
|
||||
|
||||
//
|
||||
// Otherwise complete the request.
|
||||
//
|
||||
|
||||
} else {
|
||||
|
||||
CdCompleteRequest( IrpContext, Irp, Irp->IoStatus.Status );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local support routine
|
||||
//
|
||||
|
||||
VOID
|
||||
CdAddToWorkque (
|
||||
IN PIRP_CONTEXT IrpContext,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to acually store the posted Irp to the Fsp
|
||||
workque.
|
||||
|
||||
Arguments:
|
||||
|
||||
IrpContext - Pointer to the IrpContext to be queued to the Fsp
|
||||
|
||||
Irp - I/O Request Packet.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PVOLUME_DEVICE_OBJECT Vdo;
|
||||
KIRQL SavedIrql;
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||||
|
||||
//
|
||||
// Check if this request has an associated file object, and thus volume
|
||||
// device object.
|
||||
//
|
||||
|
||||
if (IrpSp->FileObject != NULL) {
|
||||
|
||||
|
||||
Vdo = CONTAINING_RECORD( IrpSp->DeviceObject,
|
||||
VOLUME_DEVICE_OBJECT,
|
||||
DeviceObject );
|
||||
|
||||
//
|
||||
// Check to see if this request should be sent to the overflow
|
||||
// queue. If not, then send it off to an exworker thread.
|
||||
//
|
||||
|
||||
KeAcquireSpinLock( &Vdo->OverflowQueueSpinLock, &SavedIrql );
|
||||
|
||||
if (Vdo->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
|
||||
|
||||
//
|
||||
// We cannot currently respond to this IRP so we'll just enqueue it
|
||||
// to the overflow queue on the volume.
|
||||
//
|
||||
|
||||
InsertTailList( &Vdo->OverflowQueue,
|
||||
&IrpContext->WorkQueueItem.List );
|
||||
|
||||
Vdo->OverflowQueueCount += 1;
|
||||
|
||||
KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// We are going to send this Irp to an ex worker thread so up
|
||||
// the count.
|
||||
//
|
||||
|
||||
Vdo->PostedRequestCount += 1;
|
||||
|
||||
KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Send it off.....
|
||||
//
|
||||
|
||||
ExInitializeWorkItem( &IrpContext->WorkQueueItem,
|
||||
CdFspDispatch,
|
||||
IrpContext );
|
||||
|
||||
ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user