[CDFS_NEW]

- Resurrect back 7 years later (revert commit 34622).
- Add correct MS-PL (Public) License. Not added to build/used, but I need some of the headers/data structures in here.
- Source: https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/cdfs

svn path=/trunk/; revision=69180
This commit is contained in:
Alex Ionescu 2015-09-11 04:02:21 +00:00
parent fca682a62e
commit 51d5eadd25
35 changed files with 35640 additions and 0 deletions

View file

@ -0,0 +1,23 @@
The Microsoft Public License (MS-PL)
Copyright (c) 2015 Microsoft
This license governs use of the accompanying software. If you use the software, you
accept this license. If you do not accept the license, do not use the software.
1. Definitions
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
same meaning here as under U.S. copyright law.
A "contribution" is the original software, or any additions or changes to the software.
A "contributor" is any person that distributes its contribution under this license.
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
2. Grant of Rights
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
3. Conditions and Limitations
(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.

View file

@ -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 = NULL; /* ReactOS Change: GCC uninitialized variable bug */
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;
}

View file

@ -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;
}

View file

@ -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_

File diff suppressed because it is too large Load diff

View file

@ -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_

View file

@ -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>

View file

@ -0,0 +1,372 @@
/*++
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
VOID
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
CdUnload(
IN PDRIVER_OBJECT DriverObject
);
NTSTATUS
CdInitializeGlobalData (
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT FileSystemDeviceObject
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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 = (PVOID)&CdAcquireForCache;/* ReactOS Change: GCC "assignment from incompatible pointer type" */
CdData.CacheManagerCallbacks.ReleaseFromLazyWrite = (PVOID)&CdReleaseFromCache;/* ReactOS Change: GCC "assignment from incompatible pointer type" */
CdData.CacheManagerCallbacks.AcquireForReadAhead = (PVOID)&CdAcquireForCache;/* ReactOS Change: GCC "assignment from incompatible pointer type" */
CdData.CacheManagerCallbacks.ReleaseFromReadAhead = (PVOID)&CdReleaseFromCache;/* ReactOS Change: GCC "assignment from incompatible pointer type" */
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;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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 { /* ReactOS Change: Manual removal of SEH since macros to hack around it don't allow multiple SEH usage within one function */
//
// 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 { /* ReactOS Change: Manual removal of SEH since macros to hack around it don't allow multiple SEH usage within one function */
CdReleaseFcb( IrpContext, Fcb );
if (SendUnlockNotification) {
FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_UNLOCK );
}
//} /* ReactOS Change: Manual removal of SEH since macros to hack around it don't allow multiple SEH usage within one function */
//
// 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;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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; /* ReactOS Change: GCC unused variable */
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 );
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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 );
}
}

File diff suppressed because it is too large Load diff

View file

@ -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( (*(PULONG_PTR)&FileObject->FsContext2), TypeOfOpen ); /* ReactOS Change: GCC "invalid lvalue in assignment" */
//
// 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( (*(PULONG_PTR)Ccb), TYPE_OF_OPEN_MASK ); /* ReactOS Change: GCC "invalid lvalue in assignment" */
}
//
// 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 );
}

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -0,0 +1,678 @@
/*++
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,
(PVOID)CdOplockComplete,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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.
//
/* ReactOS Change: GCC "suggest parentheses around assignment used as truth value" */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,105 @@
/*++
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)
/* ReactOS Change: Need to add to reactos.mc */
#define CDFS_FILE_SYSTEM ((ULONG)0x00000026L)
#define CdBugCheck(A,B,C) { KeBugCheckEx(CDFS_FILE_SYSTEM, BugCheckFileId | __LINE__, A, B, C ); }
#endif // _NODETYPE_

View file

@ -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 = (PCHAR)RawPathEntry->DirId; /* ReactOS Change: GCC "assignment makes pointer from integer without a cast" */
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;
}

View file

@ -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 );
}

View file

@ -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;
}

View file

@ -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 = STATUS_SUCCESS; /* ReactOS Change: GCC Uninit var */
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,
(PVOID)CdOplockComplete,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
(PVOID)CdPrePostIrp );/* ReactOS Change: GCC "assignment from incompatible pointer type" */
//
// 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;
}

View file

@ -0,0 +1,338 @@
/*++
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,957 @@
/*++
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; /* ReactOS Change: GCC Unused variable */
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;
/* ReactOS Change: GCC "enumeration value not handled in switch" */
default: 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; /* ReactOS Change: GCC Unused variable */
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;
}

View file

@ -0,0 +1,505 @@
/*++
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;
/* ReactOS Change: GCC "enumeration value not handled in switch" */
default: 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;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,400 @@
/*++
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
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,
(PVOID)CdFspDispatch,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
IrpContext );
ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
return;
}