[CDFS_NEW]
authorAlex Ionescu <aionescu@gmail.com>
Fri, 11 Sep 2015 04:02:21 +0000 (04:02 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Fri, 11 Sep 2015 04:02:21 +0000 (04:02 +0000)
- 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

35 files changed:
reactos/drivers/filesystems/cdfs_new/LICENSE [new file with mode: 0644]
reactos/drivers/filesystems/cdfs_new/allocsup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/cachesup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/cd.h [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/cddata.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/cddata.h [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/cdfs.rc [new file with mode: 0644]
reactos/drivers/filesystems/cdfs_new/cdinit.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/cdprocs.h [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/cdstruc.h [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/cleanup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/close.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/create.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/devctrl.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/deviosup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/dirctrl.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/dirsup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/fieldoff.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/fileinfo.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/filobsup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/fsctrl.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/fspdisp.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/lockctrl.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/namesup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/nodetype.h [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/pathsup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/pnp.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/prefxsup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/read.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/resrcsup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/strucsup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/verfysup.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/volinfo.c [new file with mode: 0755]
reactos/drivers/filesystems/cdfs_new/wdk_wnet_to_ros.diff [new file with mode: 0644]
reactos/drivers/filesystems/cdfs_new/workque.c [new file with mode: 0755]

diff --git a/reactos/drivers/filesystems/cdfs_new/LICENSE b/reactos/drivers/filesystems/cdfs_new/LICENSE
new file mode 100644 (file)
index 0000000..efcd4c4
--- /dev/null
@@ -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.
\ No newline at end of file
diff --git a/reactos/drivers/filesystems/cdfs_new/allocsup.c b/reactos/drivers/filesystems/cdfs_new/allocsup.c
new file mode 100755 (executable)
index 0000000..181d247
--- /dev/null
@@ -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
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+//
+//  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;
+}
+
+\f
+//
+//  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;
+}
+
diff --git a/reactos/drivers/filesystems/cdfs_new/cachesup.c b/reactos/drivers/filesystems/cdfs_new/cachesup.c
new file mode 100755 (executable)
index 0000000..b31422f
--- /dev/null
@@ -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
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/cd.h b/reactos/drivers/filesystems/cdfs_new/cd.h
new file mode 100755 (executable)
index 0000000..69dc11d
--- /dev/null
@@ -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)
+
+\f
+//
+//  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)
+
+\f
+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;
+
+\f
+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;
+
+\f
+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      \
+)
+
+\f
+//
+//  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;     \
+        }                                                       \
+}
+
+\f
+//
+//  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                                    \
+)
+
+\f
+//
+//  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_
+
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/cddata.c b/reactos/drivers/filesystems/cdfs_new/cddata.c
new file mode 100755 (executable)
index 0000000..db9d894
--- /dev/null
@@ -0,0 +1,1150 @@
+
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    CdData.c
+
+Abstract:
+
+    This module declares the global data used by the Cdfs file system.
+
+    This module also handles the dispath routines in the Fsd threads as well as
+    handling the IrpContext and Irp through the exception path.
+
+
+--*/
+
+#include "CdProcs.h"
+
+#ifdef CD_SANITY
+BOOLEAN CdTestTopLevel = TRUE;
+BOOLEAN CdTestRaisedStatus = TRUE;
+BOOLEAN CdBreakOnAnyRaise = FALSE;
+BOOLEAN CdTraceRaises = FALSE;
+NTSTATUS CdInterestingExceptionCodes[] = { STATUS_DISK_CORRUPT_ERROR, 
+                                           STATUS_FILE_CORRUPT_ERROR,
+                                           0, 0, 0, 0, 0, 0, 0, 0 };
+#endif
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (CDFS_BUG_CHECK_CDDATA)
+
+//
+//  Global data structures
+//
+
+CD_DATA CdData;
+FAST_IO_DISPATCH CdFastIoDispatch;
+
+//
+//  Reserved directory strings.
+//
+
+WCHAR CdUnicodeSelfArray[] = { L'.' };
+WCHAR CdUnicodeParentArray[] = { L'.', L'.' };
+
+UNICODE_STRING CdUnicodeDirectoryNames[] = {
+    { 2, 2, CdUnicodeSelfArray},
+    { 4, 4, CdUnicodeParentArray}
+};
+
+//
+//  Volume descriptor identifier strings.
+//
+
+CHAR CdHsgId[] = { 'C', 'D', 'R', 'O', 'M' };
+CHAR CdIsoId[] = { 'C', 'D', '0', '0', '1' };
+CHAR CdXaId[] = { 'C', 'D', '-', 'X', 'A', '0', '0', '1' };
+
+//
+//  Volume label for audio disks.
+//
+
+WCHAR CdAudioLabel[] = { L'A', L'u', L'd', L'i', L'o', L' ', L'C', L'D' };
+USHORT CdAudioLabelLength = sizeof( CdAudioLabel );
+
+//
+//  Pseudo file names for audio disks.
+//
+
+CHAR CdAudioFileName[] = { 'T', 'r', 'a', 'c', 'k', '0', '0', '.', 'c', 'd', 'a' };
+UCHAR CdAudioFileNameLength = sizeof( CdAudioFileName );
+ULONG CdAudioDirentSize = FIELD_OFFSET( RAW_DIRENT, FileId ) + sizeof( CdAudioFileName ) + sizeof( SYSTEM_USE_XA );
+ULONG CdAudioDirentsPerSector = SECTOR_SIZE / (FIELD_OFFSET( RAW_DIRENT, FileId ) + sizeof( CdAudioFileName ) + sizeof( SYSTEM_USE_XA ));
+ULONG CdAudioSystemUseOffset = FIELD_OFFSET( RAW_DIRENT, FileId ) + sizeof( CdAudioFileName );
+
+//
+//  Escape sequences for mounting Unicode volumes.
+//
+
+PCHAR CdJolietEscape[] = { "%/@", "%/C", "%/E" };
+
+//
+//  Audio Play Files consist completely of this header block.  These
+//  files are readable in the root of any audio disc regardless of
+//  the capabilities of the drive.
+//
+//  The "Unique Disk ID Number" is a calculated value consisting of
+//  a combination of parameters, including the number of tracks and
+//  the starting locations of those tracks.
+//
+//  Applications interpreting CDDA RIFF files should be advised that
+//  additional RIFF file chunks may be added to this header in the
+//  future in order to add information, such as the disk and song title.
+//
+
+LONG CdAudioPlayHeader[] = {
+    0x46464952,                         // Chunk ID = 'RIFF'
+    4 * 11 - 8,                         // Chunk Size = (file size - 8)
+    0x41444443,                         // 'CDDA'
+    0x20746d66,                         // 'fmt '
+    24,                                 // Chunk Size (of 'fmt ' subchunk) = 24
+    0x00000001,                         // WORD Format Tag, WORD Track Number
+    0x00000000,                         // DWORD Unique Disk ID Number
+    0x00000000,                         // DWORD Track Starting Sector (LBN)
+    0x00000000,                         // DWORD Track Length (LBN count)
+    0x00000000,                         // DWORD Track Starting Sector (MSF)
+    0x00000000                          // DWORD Track Length (MSF)
+};
+
+//  Audio Philes begin with this header block to identify the data as a
+//  PCM waveform.  AudioPhileHeader is coded as if it has no data included
+//  in the waveform.  Data must be added in 2352-byte multiples.
+//
+//  Fields marked 'ADJUST' need to be adjusted based on the size of the
+//  data: Add (nSectors*2352) to the DWORDs at offsets 1*4 and 10*4.
+//
+//  File Size of TRACK??.WAV = nSectors*2352 + sizeof(AudioPhileHeader)
+//  RIFF('WAVE' fmt(1, 2, 44100, 176400, 16, 4) data( <CD Audio Raw Data> )
+//
+//  The number of sectors in a CD-XA CD-DA file is (DataLen/2048).
+//  CDFS will expose these files to applications as if they were just
+//  'WAVE' files, adjusting the file size so that the RIFF file is valid.
+//
+//  NT NOTE: We do not do any fidelity adjustment. These are presented as raw
+//  2352 byte sectors - 95 has the glimmer of an idea to allow CDFS to expose
+//  the CDXA CDDA data at different sampling rates in a virtual directory
+//  structure, but we will never do that.
+//
+
+LONG CdXAAudioPhileHeader[] = {
+    0x46464952,                         // Chunk ID = 'RIFF'
+    -8,                                 // Chunk Size = (file size - 8) ADJUST1
+    0x45564157,                         // 'WAVE'
+    0x20746d66,                         // 'fmt '
+    16,                                 // Chunk Size (of 'fmt ' subchunk) = 16
+    0x00020001,                         // WORD Format Tag WORD nChannels
+    44100,                              // DWORD nSamplesPerSecond
+    2352 * 75,                          // DWORD nAvgBytesPerSec
+    0x00100004,                         // WORD nBlockAlign WORD nBitsPerSample
+    0x61746164,                         // 'data'
+    -44                                 // <CD Audio Raw Data>          ADJUST2
+};
+
+//
+//  XA Files begin with this RIFF header block to identify the data as
+//  raw CD-XA sectors.  Data must be added in 2352-byte multiples.
+//
+//  This header is added to all CD-XA files which are marked as having
+//  mode2form2 sectors.
+//
+//  Fields marked 'ADJUST' need to be adjusted based on the size of the
+//  data: Add file size to the marked DWORDS.
+//
+//  File Size of TRACK??.WAV = nSectors*2352 + sizeof(XAFileHeader)
+//
+//  RIFF('CDXA' FMT(Owner, Attr, 'X', 'A', FileNum, 0) data ( <CDXA Raw Data> )
+//
+
+LONG CdXAFileHeader[] = {
+    0x46464952,                         // Chunk ID = 'RIFF'
+    -8,                                 // Chunk Size = (file size - 8) ADJUST
+    0x41584443,                         // 'CDXA'
+    0x20746d66,                         // 'fmt '
+    16,                                 // Chunk Size (of CDXA chunk) = 16
+    0,                                  // DWORD Owner ID
+    0x41580000,                         // WORD Attributes
+                                        // BYTE Signature byte 1 'X'
+                                        // BYTE Signature byte 2 'A'
+    0,                                  // BYTE File Number
+    0,                                  // BYTE Reserved[7]
+    0x61746164,                         // 'data'
+    -44                                 // <CD-XA Raw Sectors>          ADJUST
+};
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdFastIoCheckIfPossible)
+#pragma alloc_text(PAGE, CdSerial32)
+#endif
+
+\f
+NTSTATUS
+CdFsdDispatch (
+    IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This is the driver entry to all of the Fsd dispatch points.
+
+    Conceptually the Io routine will call this routine on all requests
+    to the file system.  We case on the type of request and invoke the
+    correct handler for this type of request.  There is an exception filter
+    to catch any exceptions in the CDFS code as well as the CDFS process
+    exception routine.
+
+    This routine allocates and initializes the IrpContext for this request as
+    well as updating the top-level thread context as necessary.  We may loop
+    in this routine if we need to retry the request for any reason.  The
+    status code STATUS_CANT_WAIT is used to indicate this.  Suppose the disk
+    in the drive has changed.  An Fsd request will proceed normally until it
+    recognizes this condition.  STATUS_VERIFY_REQUIRED is raised at that point
+    and the exception code will handle the verify and either return
+    STATUS_CANT_WAIT or STATUS_PENDING depending on whether the request was
+    posted.
+
+Arguments:
+
+    VolumeDeviceObject - Supplies the volume device object for this request
+
+    Irp - Supplies the Irp being processed
+
+Return Value:
+
+    NTSTATUS - The FSD status for the IRP
+
+--*/
+
+{
+    THREAD_CONTEXT ThreadContext;
+    PIRP_CONTEXT IrpContext = NULL;
+    BOOLEAN Wait;
+
+#ifdef CD_SANITY
+    PVOID PreviousTopLevel;
+#endif
+
+    NTSTATUS Status;
+
+#if DBG
+
+    KIRQL SaveIrql = KeGetCurrentIrql();
+
+#endif
+
+    ASSERT_OPTIONAL_IRP( Irp );
+
+    FsRtlEnterFileSystem();
+
+#ifdef CD_SANITY
+    PreviousTopLevel = IoGetTopLevelIrp();
+#endif
+
+    //
+    //  Loop until this request has been completed or posted.
+    //
+
+    do {
+
+        //
+        //  Use a try-except to handle the exception cases.
+        //
+
+        try {
+
+            //
+            //  If the IrpContext is NULL then this is the first pass through
+            //  this loop.
+            //
+
+            if (IrpContext == NULL) {
+
+                //
+                //  Decide if this request is waitable an allocate the IrpContext.
+                //  If the file object in the stack location is NULL then this
+                //  is a mount which is always waitable.  Otherwise we look at
+                //  the file object flags.
+                //
+
+                if (IoGetCurrentIrpStackLocation( Irp )->FileObject == NULL) {
+
+                    Wait = TRUE;
+
+                } else {
+
+                    Wait = CanFsdWait( Irp );
+                }
+
+                IrpContext = CdCreateIrpContext( Irp, Wait );
+
+                //
+                //  Update the thread context information.
+                //
+
+                CdSetThreadContext( IrpContext, &ThreadContext );
+
+#ifdef CD_SANITY
+                ASSERT( !CdTestTopLevel ||
+                        SafeNodeType( IrpContext->TopLevel ) == CDFS_NTC_IRP_CONTEXT );
+#endif
+
+            //
+            //  Otherwise cleanup the IrpContext for the retry.
+            //
+
+            } else {
+
+                //
+                //  Set the MORE_PROCESSING flag to make sure the IrpContext
+                //  isn't inadvertently deleted here.  Then cleanup the
+                //  IrpContext to perform the retry.
+                //
+
+                SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
+                CdCleanupIrpContext( IrpContext, FALSE );
+            }
+
+            //
+            //  Case on the major irp code.
+            //
+
+            switch (IrpContext->MajorFunction) {
+
+            case IRP_MJ_CREATE :
+
+                Status = CdCommonCreate( IrpContext, Irp );
+                break;
+
+            case IRP_MJ_CLOSE :
+
+                Status = CdCommonClose( IrpContext, Irp );
+                break;
+
+            case IRP_MJ_READ :
+
+                //
+                //  If this is an Mdl complete request, don't go through
+                //  common read.
+                //
+
+                if (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE )) {
+
+                    Status = CdCompleteMdl( IrpContext, Irp );
+
+                } else {
+
+                    Status = CdCommonRead( IrpContext, Irp );
+                }
+
+                break;
+
+            case IRP_MJ_QUERY_INFORMATION :
+
+                Status = CdCommonQueryInfo( IrpContext, Irp );
+                break;
+
+            case IRP_MJ_SET_INFORMATION :
+
+                Status = CdCommonSetInfo( IrpContext, Irp );
+                break;
+
+            case IRP_MJ_QUERY_VOLUME_INFORMATION :
+
+                Status = CdCommonQueryVolInfo( IrpContext, Irp );
+                break;
+
+            case IRP_MJ_DIRECTORY_CONTROL :
+
+                Status = CdCommonDirControl( IrpContext, Irp );
+                break;
+
+            case IRP_MJ_FILE_SYSTEM_CONTROL :
+
+                Status = CdCommonFsControl( IrpContext, Irp );
+                break;
+
+            case IRP_MJ_DEVICE_CONTROL :
+
+                Status = CdCommonDevControl( IrpContext, Irp );
+                break;
+
+            case IRP_MJ_LOCK_CONTROL :
+
+                Status = CdCommonLockControl( IrpContext, Irp );
+                break;
+
+            case IRP_MJ_CLEANUP :
+
+                Status = CdCommonCleanup( IrpContext, Irp );
+                break;
+
+            case IRP_MJ_PNP :
+
+                Status = CdCommonPnp( IrpContext, Irp );
+                break;
+
+            default :
+
+                Status = STATUS_INVALID_DEVICE_REQUEST;
+                CdCompleteRequest( IrpContext, Irp, Status );
+            }
+
+        } except( CdExceptionFilter( IrpContext, GetExceptionInformation() )) {
+
+            Status = CdProcessException( IrpContext, Irp, GetExceptionCode() );
+        }
+
+    } while (Status == STATUS_CANT_WAIT);
+
+#ifdef CD_SANITY
+    ASSERT( !CdTestTopLevel ||
+            (PreviousTopLevel == IoGetTopLevelIrp()) );
+#endif
+
+    FsRtlExitFileSystem();
+
+    ASSERT( SaveIrql == KeGetCurrentIrql( ));
+
+    return Status;
+}
+
+#ifdef CD_SANITY
+
+VOID
+CdRaiseStatusEx(
+    IN PIRP_CONTEXT IrpContext,
+    IN NTSTATUS Status,
+    IN BOOLEAN NormalizeStatus,
+    IN OPTIONAL ULONG FileId,
+    IN OPTIONAL ULONG Line
+    )
+{
+    BOOLEAN BreakIn = FALSE;
+    
+    AssertVerifyDevice( IrpContext, Status);
+
+    if (CdTraceRaises)  {
+
+        DbgPrint( "%p CdRaiseStatusEx 0x%x @ fid %d, line %d\n", PsGetCurrentThread(), Status, FileId, Line);
+    }
+
+    if (CdTestRaisedStatus && !CdBreakOnAnyRaise)  {
+
+        ULONG Index;
+
+        for (Index = 0; 
+             Index < (sizeof( CdInterestingExceptionCodes) / sizeof( CdInterestingExceptionCodes[0])); 
+             Index++)  {
+
+            if ((STATUS_SUCCESS != CdInterestingExceptionCodes[Index]) &&
+                (CdInterestingExceptionCodes[Index] == Status))  {
+
+                BreakIn = TRUE;
+                break;
+            }
+        }
+    }
+
+    if (BreakIn || CdBreakOnAnyRaise)  {
+        
+        DbgPrint( "CDFS: Breaking on raised status %08x  (BI=%d,BA=%d)\n", Status, BreakIn, CdBreakOnAnyRaise);
+        DbgPrint( "CDFS: (FILEID %d LINE %d)\n", FileId, Line);
+        DbgPrint( "CDFS: Contact CDFS.SYS component owner for triage.\n");
+        DbgPrint( "CDFS: 'eb %p 0;eb %p 0' to disable this alert.\n", &CdTestRaisedStatus, &CdBreakOnAnyRaise);
+
+        DbgBreakPoint();
+    }
+    
+    if (NormalizeStatus)  {
+
+        IrpContext->ExceptionStatus = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR);
+    }
+    else {
+
+        IrpContext->ExceptionStatus = Status;
+    }
+
+    IrpContext->RaisedAtLineFile = (FileId << 16) | Line;
+    
+    ExRaiseStatus( IrpContext->ExceptionStatus);
+}
+
+#endif
+
+LONG
+CdExceptionFilter (
+    IN PIRP_CONTEXT IrpContext,
+    IN PEXCEPTION_POINTERS ExceptionPointer
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is used to decide whether we will handle a raised exception
+    status.  If CDFS explicitly raised an error then this status is already
+    in the IrpContext.  We choose which is the correct status code and
+    either indicate that we will handle the exception or bug-check the system.
+
+Arguments:
+
+    ExceptionCode - Supplies the exception code to being checked.
+
+Return Value:
+
+    ULONG - returns EXCEPTION_EXECUTE_HANDLER or bugchecks
+
+--*/
+
+{
+    NTSTATUS ExceptionCode;
+    BOOLEAN TestStatus = TRUE;
+
+    ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
+
+    ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode;
+
+    //
+    // If the exception is STATUS_IN_PAGE_ERROR, get the I/O error code
+    // from the exception record.
+    //
+
+    if ((ExceptionCode == STATUS_IN_PAGE_ERROR) &&
+        (ExceptionPointer->ExceptionRecord->NumberParameters >= 3)) {
+
+        ExceptionCode =
+            (NTSTATUS)ExceptionPointer->ExceptionRecord->ExceptionInformation[2];
+    }
+
+    //
+    //  If there is an Irp context then check which status code to use.
+    //
+
+    if (ARGUMENT_PRESENT( IrpContext )) {
+
+        if (IrpContext->ExceptionStatus == STATUS_SUCCESS) {
+
+            //
+            //  Store the real status into the IrpContext.
+            //
+
+            IrpContext->ExceptionStatus = ExceptionCode;
+
+        } else {
+
+            //
+            //  No need to test the status code if we raised it ourselves.
+            //
+
+            TestStatus = FALSE;
+        }
+    }
+
+    AssertVerifyDevice( IrpContext, IrpContext->ExceptionStatus );
+    
+    //
+    //  Bug check if this status is not supported.
+    //
+
+    if (TestStatus && !FsRtlIsNtstatusExpected( ExceptionCode )) {
+
+        CdBugCheck( (ULONG_PTR) ExceptionPointer->ExceptionRecord,
+                    (ULONG_PTR) ExceptionPointer->ContextRecord,
+                    (ULONG_PTR) ExceptionPointer->ExceptionRecord->ExceptionAddress );
+
+    }
+
+    return EXCEPTION_EXECUTE_HANDLER;
+}
+
+\f
+NTSTATUS
+CdProcessException (
+    IN PIRP_CONTEXT IrpContext OPTIONAL,
+    IN PIRP Irp,
+    IN NTSTATUS ExceptionCode
+    )
+
+/*++
+
+Routine Description:
+
+    This routine processes an exception.  It either completes the request
+    with the exception status in the IrpContext, sends this off to the Fsp
+    workque or causes it to be retried in the current thread if a verification
+    is needed.
+
+    If the volume needs to be verified (STATUS_VERIFY_REQUIRED) and we can
+    do the work in the current thread we will translate the status code
+    to STATUS_CANT_WAIT to indicate that we need to retry the request.
+
+Arguments:
+
+    Irp - Supplies the Irp being processed
+
+    ExceptionCode - Supplies the normalized exception status being handled
+
+Return Value:
+
+    NTSTATUS - Returns the results of either posting the Irp or the
+        saved completion status.
+
+--*/
+
+{
+    PDEVICE_OBJECT Device;
+    PVPB Vpb;
+    PETHREAD Thread;
+
+    ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
+    ASSERT_IRP( Irp );
+    
+    //
+    //  If there is not an irp context, then complete the request with the
+    //  current status code.
+    //
+
+    if (!ARGUMENT_PRESENT( IrpContext )) {
+
+        CdCompleteRequest( NULL, Irp, ExceptionCode );
+        return ExceptionCode;
+    }
+
+    //
+    //  Get the real exception status from the IrpContext.
+    //
+
+    ExceptionCode = IrpContext->ExceptionStatus;
+
+    //
+    //  If we are not a top level request then we just complete the request
+    //  with the current status code.
+    //
+
+    if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) {
+
+        CdCompleteRequest( IrpContext, Irp, ExceptionCode );
+        return ExceptionCode;
+    }
+
+    //
+    //  Check if we are posting this request.  One of the following must be true
+    //  if we are to post a request.
+    //
+    //      - Status code is STATUS_CANT_WAIT and the request is asynchronous
+    //          or we are forcing this to be posted.
+    //
+    //      - Status code is STATUS_VERIFY_REQUIRED and we are at APC level
+    //          or higher.  Can't wait for IO in the verify path in this case.
+    //
+    //  Set the MORE_PROCESSING flag in the IrpContext to keep if from being
+    //  deleted if this is a retryable condition.
+    //
+    //
+    //  Note that (children of) CdFsdPostRequest can raise (Mdl allocation).
+    //
+
+    try {
+    
+        if (ExceptionCode == STATUS_CANT_WAIT) {
+
+            if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST )) {
+
+                ExceptionCode = CdFsdPostRequest( IrpContext, Irp );
+            }
+
+        } else if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
+
+            if (KeGetCurrentIrql() >= APC_LEVEL) {
+
+                ExceptionCode = CdFsdPostRequest( IrpContext, Irp );
+            }
+        }
+    }
+    except( CdExceptionFilter( IrpContext, GetExceptionInformation() ))  {
+    
+        ExceptionCode = GetExceptionCode();        
+    }
+    
+    //
+    //  If we posted the request or our caller will retry then just return here.
+    //
+
+    if ((ExceptionCode == STATUS_PENDING) ||
+        (ExceptionCode == STATUS_CANT_WAIT)) {
+
+        return ExceptionCode;
+    }
+
+    ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
+
+    //
+    //  Store this error into the Irp for posting back to the Io system.
+    //
+
+    Irp->IoStatus.Status = ExceptionCode;
+
+    if (IoIsErrorUserInduced( ExceptionCode )) {
+
+        //
+        //  Check for the various error conditions that can be caused by,
+        //  and possibly resolved my the user.
+        //
+
+        if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
+
+            //
+            //  Now we are at the top level file system entry point.
+            //
+            //  If we have already posted this request then the device to
+            //  verify is in the original thread.  Find this via the Irp.
+            //
+
+            Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread );
+            IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL );
+            
+            //
+            //  If there is no device in that location then check in the
+            //  current thread.
+            //
+
+            if (Device == NULL) {
+
+                Device = IoGetDeviceToVerify( PsGetCurrentThread() );
+                IoSetDeviceToVerify( PsGetCurrentThread(), NULL );
+
+                ASSERT( Device != NULL );
+
+                //
+                //  Let's not BugCheck just because the driver messes up.
+                //
+
+                if (Device == NULL) {
+
+                    ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR;
+
+                    CdCompleteRequest( IrpContext, Irp, ExceptionCode );
+
+                    return ExceptionCode;
+                }
+            }
+
+            //
+            //  CdPerformVerify() will do the right thing with the Irp.
+            //  If we return STATUS_CANT_WAIT then the current thread
+            //  can retry the request.
+            //
+
+            return CdPerformVerify( IrpContext, Irp, Device );
+        }
+
+        //
+        //  The other user induced conditions generate an error unless
+        //  they have been disabled for this request.
+        //
+
+        if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS )) {
+
+            CdCompleteRequest( IrpContext, Irp, ExceptionCode );
+
+            return ExceptionCode;
+
+        } 
+        //
+        //  Generate a pop-up.
+        //
+        else {
+
+            if (IoGetCurrentIrpStackLocation( Irp )->FileObject != NULL) {
+
+                Vpb = IoGetCurrentIrpStackLocation( Irp )->FileObject->Vpb;
+
+            } else {
+
+                Vpb = NULL;
+            }
+
+            //
+            //  The device to verify is either in my thread local storage
+            //  or that of the thread that owns the Irp.
+            //
+
+            Thread = Irp->Tail.Overlay.Thread;
+            Device = IoGetDeviceToVerify( Thread );
+
+            if (Device == NULL) {
+
+                Thread = PsGetCurrentThread();
+                Device = IoGetDeviceToVerify( Thread );
+
+                ASSERT( Device != NULL );
+
+                //
+                //  Let's not BugCheck just because the driver messes up.
+                //
+
+                if (Device == NULL) {
+
+                    CdCompleteRequest( IrpContext, Irp, ExceptionCode );
+
+                    return ExceptionCode;
+                }
+            }
+
+            //
+            //  This routine actually causes the pop-up.  It usually
+            //  does this by queuing an APC to the callers thread,
+            //  but in some cases it will complete the request immediately,
+            //  so it is very important to IoMarkIrpPending() first.
+            //
+
+            IoMarkIrpPending( Irp );
+            IoRaiseHardError( Irp, Vpb, Device );
+
+            //
+            //  We will be handing control back to the caller here, so
+            //  reset the saved device object.
+            //
+
+            IoSetDeviceToVerify( Thread, NULL );
+
+            //
+            //  The Irp will be completed by Io or resubmitted.  In either
+            //  case we must clean up the IrpContext here.
+            //
+
+            CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
+            return STATUS_PENDING;
+        }
+    }
+
+    //
+    //  This is just a run of the mill error.
+    //
+
+    CdCompleteRequest( IrpContext, Irp, ExceptionCode );
+
+    return ExceptionCode;
+}
+
+\f
+VOID
+CdCompleteRequest (
+    IN PIRP_CONTEXT IrpContext OPTIONAL,
+    IN PIRP Irp OPTIONAL,
+    IN NTSTATUS Status
+    )
+
+/*++
+
+Routine Description:
+
+    This routine completes a Irp and cleans up the IrpContext.  Either or
+    both of these may not be specified.
+
+Arguments:
+
+    Irp - Supplies the Irp being processed.
+
+    Status - Supplies the status to complete the Irp with
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
+    ASSERT_OPTIONAL_IRP( Irp );
+
+    //
+    //  Cleanup the IrpContext if passed in here.
+    //
+
+    if (ARGUMENT_PRESENT( IrpContext )) {
+
+        CdCleanupIrpContext( IrpContext, FALSE );
+    }
+
+    //
+    //  If we have an Irp then complete the irp.
+    //
+
+    if (ARGUMENT_PRESENT( Irp )) {
+
+        //
+        //  Clear the information field in case we have used this Irp
+        //  internally.
+        //
+
+        if (NT_ERROR( Status ) &&
+            FlagOn( Irp->Flags, IRP_INPUT_OPERATION )) {
+
+            Irp->IoStatus.Information = 0;
+        }
+
+        Irp->IoStatus.Status = Status;
+
+        AssertVerifyDeviceIrp( Irp );
+        
+        IoCompleteRequest( Irp, IO_CD_ROM_INCREMENT );
+    }
+
+    return;
+}
+
+\f
+VOID
+CdSetThreadContext (
+    IN PIRP_CONTEXT IrpContext,
+    IN PTHREAD_CONTEXT ThreadContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called at each Fsd/Fsp entry point set up the IrpContext
+    and thread local storage to track top level requests.  If there is
+    not a Cdfs context in the thread local storage then we use the input one.
+    Otherwise we use the one already there.  This routine also updates the
+    IrpContext based on the state of the top-level context.
+
+    If the TOP_LEVEL flag in the IrpContext is already set when we are called
+    then we force this request to appear top level.
+
+Arguments:
+
+    ThreadContext - Address on stack for local storage if not already present.
+
+    ForceTopLevel - We force this request to appear top level regardless of
+        any previous stack value.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PTHREAD_CONTEXT CurrentThreadContext;
+    ULONG_PTR StackTop;
+    ULONG_PTR StackBottom;
+
+    PAGED_CODE();
+
+    ASSERT_IRP_CONTEXT( IrpContext );
+
+    //
+    //  Get the current top-level irp out of the thread storage.
+    //  If NULL then this is the top-level request.
+    //
+
+    CurrentThreadContext = (PTHREAD_CONTEXT) IoGetTopLevelIrp();
+
+    if (CurrentThreadContext == NULL) {
+
+        SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL );
+    }
+
+    //
+    //  Initialize the input context unless we are using the current
+    //  thread context block.  We use the new block if our caller
+    //  specified this or the existing block is invalid.
+    //
+    //  The following must be true for the current to be a valid Cdfs context.
+    //
+    //      Structure must lie within current stack.
+    //      Address must be ULONG aligned.
+    //      Cdfs signature must be present.
+    //
+    //  If this is not a valid Cdfs context then use the input thread
+    //  context and store it in the top level context.
+    //
+
+    IoGetStackLimits( &StackTop, &StackBottom);
+
+    if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL ) ||
+        (((ULONG_PTR) CurrentThreadContext > StackBottom - sizeof( THREAD_CONTEXT )) ||
+         ((ULONG_PTR) CurrentThreadContext <= StackTop) ||
+         FlagOn( (ULONG_PTR) CurrentThreadContext, 0x3 ) ||
+         (CurrentThreadContext->Cdfs != 0x53464443))) {
+
+        ThreadContext->Cdfs = 0x53464443;
+        ThreadContext->SavedTopLevelIrp = (PIRP) CurrentThreadContext;
+        ThreadContext->TopLevelIrpContext = IrpContext;
+        IoSetTopLevelIrp( (PIRP) ThreadContext );
+
+        IrpContext->TopLevel = IrpContext;
+        IrpContext->ThreadContext = ThreadContext;
+
+        SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS );
+
+    //
+    //  Otherwise use the IrpContext in the thread context.
+    //
+
+    } else {
+
+        IrpContext->TopLevel = CurrentThreadContext->TopLevelIrpContext;
+    }
+
+    return;
+}
+
+\f
+BOOLEAN
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdFastIoCheckIfPossible (
+    IN PFILE_OBJECT FileObject,
+    IN PLARGE_INTEGER FileOffset,
+    IN ULONG Length,
+    IN BOOLEAN Wait,
+    IN ULONG LockKey,
+    IN BOOLEAN CheckForReadOperation,
+    OUT PIO_STATUS_BLOCK IoStatus,
+    IN PDEVICE_OBJECT DeviceObject
+    )
+
+/*++
+
+Routine Description:
+
+    This routine checks if fast i/o is possible for a read/write operation
+
+Arguments:
+
+    FileObject - Supplies the file object used in the query
+
+    FileOffset - Supplies the starting byte offset for the read/write operation
+
+    Length - Supplies the length, in bytes, of the read/write operation
+
+    Wait - Indicates if we can wait
+
+    LockKey - Supplies the lock key
+
+    CheckForReadOperation - Indicates if this is a check for a read or write
+        operation
+
+    IoStatus - Receives the status of the operation if our return value is
+        FastIoReturnError
+
+Return Value:
+
+    BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs
+        to take the long route.
+
+--*/
+
+{
+    PFCB Fcb;
+    TYPE_OF_OPEN TypeOfOpen;
+    LARGE_INTEGER LargeLength;
+
+    PAGED_CODE();
+
+    //
+    //  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) || !CheckForReadOperation) {
+
+        IoStatus->Status = STATUS_INVALID_PARAMETER;
+        return TRUE;
+    }
+
+    LargeLength.QuadPart = Length;
+
+    //
+    //  Check whether the file locks will allow for fast io.
+    //
+
+    if ((Fcb->FileLock == NULL) ||
+        FsRtlFastCheckLockForRead( Fcb->FileLock,
+                                   FileOffset,
+                                   &LargeLength,
+                                   LockKey,
+                                   FileObject,
+                                   PsGetCurrentProcess() )) {
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+\f
+ULONG
+CdSerial32 (
+    IN PCHAR Buffer,
+    IN ULONG ByteCount
+    )
+/*++
+
+Routine Description:
+
+    This routine is called to generate a 32 bit serial number.  This is
+    done by doing four separate checksums into an array of bytes and
+    then treating the bytes as a ULONG.
+
+Arguments:
+
+    Buffer - Pointer to the buffer to generate the ID for.
+
+    ByteCount - Number of bytes in the buffer.
+
+Return Value:
+
+    ULONG - The 32 bit serial number.
+
+--*/
+
+{
+    union {
+        UCHAR   Bytes[4];
+        ULONG   SerialId;
+    } Checksum;
+
+    PAGED_CODE();
+
+    //
+    //  Initialize the serial number.
+    //
+
+    Checksum.SerialId = 0;
+
+    //
+    //  Continue while there are more bytes to use.
+    //
+
+    while (ByteCount--) {
+
+        //
+        //  Increment this sub-checksum.
+        //
+
+        Checksum.Bytes[ByteCount & 0x3] += *(Buffer++);
+    }
+
+    //
+    //  Return the checksums as a ULONG.
+    //
+
+    return Checksum.SerialId;
+}
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/cddata.h b/reactos/drivers/filesystems/cdfs_new/cddata.h
new file mode 100755 (executable)
index 0000000..0577a4c
--- /dev/null
@@ -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[];
+
+\f
+//
+//  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
+
+\f
+//
+//  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_
+
diff --git a/reactos/drivers/filesystems/cdfs_new/cdfs.rc b/reactos/drivers/filesystems/cdfs_new/cdfs.rc
new file mode 100644 (file)
index 0000000..1cf70c6
--- /dev/null
@@ -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>
diff --git a/reactos/drivers/filesystems/cdfs_new/cdinit.c b/reactos/drivers/filesystems/cdfs_new/cdinit.c
new file mode 100755 (executable)
index 0000000..f0faef6
--- /dev/null
@@ -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
+
+\f
+//
+//  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);
+}
+\f
+//
+//  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;
+}
+
diff --git a/reactos/drivers/filesystems/cdfs_new/cdprocs.h b/reactos/drivers/filesystems/cdfs_new/cdprocs.h
new file mode 100755 (executable)
index 0000000..87fcc5a
--- /dev/null
@@ -0,0 +1,1918 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    CdProcs.h
+
+Abstract:
+
+    This module defines all of the globally used procedures in the Cdfs
+    file system.
+
+
+--*/
+
+#ifndef _CDPROCS_
+#define _CDPROCS_
+
+#include <ntifs.h>
+
+#include <ntddcdrm.h>
+#include <ntdddisk.h>
+#include <ntddscsi.h>
+
+#ifndef INLINE
+#define INLINE __inline
+#endif
+
+#include "nodetype.h"
+#include "Cd.h"
+#include "CdStruc.h"
+#include "CdData.h"
+
+
+//**** x86 compiler bug ****
+
+#if defined(_M_IX86)
+#undef Int64ShraMod32
+#define Int64ShraMod32(a, b) ((LONGLONG)(a) >> (b))
+#endif
+
+//
+//  Here are the different pool tags.
+//
+
+/* ReactOS Change: GCC doesn't understand this, use TAG macro */
+#include <reactos/helper.h>
+#define TAG_CCB                 TAG('c','c','d','C')      //  Ccb
+#define TAG_CDROM_TOC           TAG('c','t','d','C')      //  TOC
+#define TAG_DIRENT_NAME         TAG('n','d','d','C')      //  CdName in dirent
+#define TAG_ENUM_EXPRESSION     TAG('e','e','d','C')      //  Search expression for enumeration
+#define TAG_FCB_DATA            TAG('d','f','d','C')      //  Data Fcb
+#define TAG_FCB_INDEX           TAG('i','f','d','C')      //  Index Fcb
+#define TAG_FCB_NONPAGED        TAG('n','f','d','C')      //  Nonpaged Fcb
+#define TAG_FCB_TABLE           TAG('t','f','d','C')      //  Fcb Table entry
+#define TAG_FILE_NAME           TAG('n','F','d','C')      //  Filename buffer
+#define TAG_GEN_SHORT_NAME      TAG('s','g','d','C')      //  Generated short name
+#define TAG_IO_BUFFER           TAG('f','b','d','C')      //  Temporary IO buffer
+#define TAG_IO_CONTEXT          TAG('o','i','d','C')      //  Io context for async reads
+#define TAG_IRP_CONTEXT         TAG('c','i','d','C')      //  Irp Context
+#define TAG_IRP_CONTEXT_LITE    TAG('l','i','d','C')      //  Irp Context lite
+#define TAG_MCB_ARRAY           TAG('a','m','d','C')      //  Mcb array
+#define TAG_PATH_ENTRY_NAME     TAG('n','P','d','C')      //  CdName in path entry
+#define TAG_PREFIX_ENTRY        TAG('e','p','d','C')      //  Prefix Entry
+#define TAG_PREFIX_NAME         TAG('n','p','d','C')      //  Prefix Entry name
+#define TAG_SPANNING_PATH_TABLE TAG('p','s','d','C')      //  Buffer for spanning path table
+#define TAG_UPCASE_NAME         TAG('n','u','d','C')      //  Buffer for upcased name
+#define TAG_VOL_DESC            TAG('d','v','d','C')      //  Buffer for volume descriptor
+#define TAG_VPB                 TAG('p','v','d','C')      //  Vpb allocated in filesystem
+
+//
+//  Tag all of our allocations if tagging is turned on
+//
+
+#ifdef POOL_TAGGING
+
+#undef FsRtlAllocatePool
+#undef FsRtlAllocatePoolWithQuota
+#define FsRtlAllocatePool(a,b) FsRtlAllocatePoolWithTag(a,b,'sfdC')
+#define FsRtlAllocatePoolWithQuota(a,b) FsRtlAllocatePoolWithQuotaTag(a,b,'sfdC')
+
+#endif // POOL_TAGGING
+
+
+//
+//  File access check routine, implemented in AcChkSup.c
+//
+
+//
+//  BOOLEAN
+//  CdIllegalFcbAccess (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN TYPE_OF_OPEN TypeOfOpen,
+//      IN ACCESS_MASK DesiredAccess
+//      );
+//
+
+#define CdIllegalFcbAccess(IC,T,DA) (                           \
+           BooleanFlagOn( (DA),                                 \
+                          ((T) != UserVolumeOpen ?              \
+                           (FILE_WRITE_ATTRIBUTES           |   \
+                            FILE_WRITE_DATA                 |   \
+                            FILE_WRITE_EA                   |   \
+                            FILE_ADD_FILE                   |   \
+                            FILE_ADD_SUBDIRECTORY           |   \
+                            FILE_APPEND_DATA) : 0)          |   \
+                          FILE_DELETE_CHILD                 |   \
+                          DELETE                            |   \
+                          WRITE_DAC ))
+
+\f
+//
+//  Allocation support routines, implemented in AllocSup.c
+//
+//  These routines are for querying allocation on individual streams.
+//
+
+VOID
+CdLookupAllocation (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN LONGLONG FileOffset,
+    OUT PLONGLONG DiskOffset,
+    OUT PULONG ByteCount
+    );
+
+VOID
+CdAddAllocationFromDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN ULONG McbEntryOffset,
+    IN LONGLONG StartingFileOffset,
+    IN PDIRENT Dirent
+    );
+
+VOID
+CdAddInitialAllocation (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN ULONG StartingBlock,
+    IN LONGLONG DataLength
+    );
+
+VOID
+CdTruncateAllocation (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN LONGLONG StartingFileOffset
+    );
+
+VOID
+CdInitializeMcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb
+    );
+
+VOID
+CdUninitializeMcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb
+    );
+
+\f
+//
+//   Buffer control routines for data caching, implemented in CacheSup.c
+//
+
+VOID
+CdCreateInternalStream (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PFCB Fcb
+    );
+
+VOID
+CdDeleteInternalStream (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb
+    );
+
+NTSTATUS
+CdCompleteMdl (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdPurgeVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN BOOLEAN DismountUnderway
+    );
+
+//
+//  VOID
+//  CdUnpinData (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN OUT PBCB *Bcb
+//      );
+//
+
+#define CdUnpinData(IC,B)   \
+    if (*(B) != NULL) { CcUnpinData( *(B) ); *(B) = NULL; }
+
+\f
+//
+//  Device I/O routines, implemented in DevIoSup.c
+//
+//  These routines perform the actual device read and writes.  They only affect
+//  the on disk structure and do not alter any other data structures.
+//
+
+NTSTATUS
+CdNonCachedRead (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount
+    );
+
+NTSTATUS
+CdNonCachedXARead (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount
+    );
+
+BOOLEAN
+CdReadSectors (
+    IN PIRP_CONTEXT IrpContext,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount,
+    IN BOOLEAN RaiseOnError,
+    IN OUT PVOID Buffer,
+    IN PDEVICE_OBJECT TargetDeviceObject
+    );
+
+NTSTATUS
+CdCreateUserMdl (
+    IN PIRP_CONTEXT IrpContext,
+    IN ULONG BufferLength,
+    IN BOOLEAN RaiseOnError
+    );
+
+NTSTATUS
+CdPerformDevIoCtrl (
+    IN PIRP_CONTEXT IrpContext,
+    IN ULONG IoControlCode,
+    IN PDEVICE_OBJECT Device,
+    OUT PVOID OutputBuffer OPTIONAL,
+    IN ULONG OutputBufferLength,
+    IN BOOLEAN InternalDeviceIoControl,
+    IN BOOLEAN OverrideVerify,
+    OUT PIO_STATUS_BLOCK Iosb OPTIONAL
+    );
+
+//
+//  VOID
+//  CdMapUserBuffer (
+//      IN PIRP_CONTEXT IrpContext
+//      OUT PVOID UserBuffer
+//      );
+//
+//  Returns pointer to sys address.  Will raise on failure.
+//
+//
+//  VOID
+//  CdLockUserBuffer (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN ULONG BufferLength
+//      );
+//
+
+#define CdMapUserBuffer(IC, UB) {                                               \
+            *(UB) = (PVOID) ( ((IC)->Irp->MdlAddress == NULL) ?                 \
+                    (IC)->Irp->UserBuffer :                                     \
+                    (MmGetSystemAddressForMdlSafe( (IC)->Irp->MdlAddress, NormalPagePriority)));   \
+            if (NULL == *(UB))  {                         \
+                CdRaiseStatus( (IC), STATUS_INSUFFICIENT_RESOURCES);            \
+            }                                                                   \
+        }                                                                       
+        
+
+#define CdLockUserBuffer(IC,BL) {                   \
+    if ((IC)->Irp->MdlAddress == NULL) {            \
+        (VOID) CdCreateUserMdl( (IC), (BL), TRUE ); \
+    }                                               \
+}
+
+\f
+//
+//  Dirent support routines, implemented in DirSup.c
+//
+
+VOID
+CdLookupDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN ULONG DirentOffset,
+    OUT PDIRENT_ENUM_CONTEXT DirContext
+    );
+
+BOOLEAN
+CdLookupNextDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PDIRENT_ENUM_CONTEXT CurrentDirContext,
+    OUT PDIRENT_ENUM_CONTEXT NextDirContext
+    );
+
+VOID
+CdUpdateDirentFromRawDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PDIRENT_ENUM_CONTEXT DirContext,
+    IN OUT PDIRENT Dirent
+    );
+
+VOID
+CdUpdateDirentName (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PDIRENT Dirent,
+    IN ULONG IgnoreCase
+    );
+
+BOOLEAN
+CdFindFile (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PCD_NAME Name,
+    IN BOOLEAN IgnoreCase,
+    IN OUT PFILE_ENUM_CONTEXT FileContext,
+    OUT PCD_NAME *MatchingName
+    );
+
+BOOLEAN
+CdFindDirectory (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PCD_NAME Name,
+    IN BOOLEAN IgnoreCase,
+    IN OUT PFILE_ENUM_CONTEXT FileContext
+    );
+
+BOOLEAN
+CdFindFileByShortName (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PCD_NAME Name,
+    IN BOOLEAN IgnoreCase,
+    IN ULONG ShortNameDirentOffset,
+    IN OUT PFILE_ENUM_CONTEXT FileContext
+    );
+
+BOOLEAN
+CdLookupNextInitialFileDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_ENUM_CONTEXT FileContext
+    );
+
+VOID
+CdLookupLastFileDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PFILE_ENUM_CONTEXT FileContext
+    );
+
+VOID
+CdCleanupFileContext (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFILE_ENUM_CONTEXT FileContext
+    );
+
+//
+//  VOID
+//  CdInitializeFileContext (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFILE_ENUM_CONTEXT FileContext
+//      );
+//
+//
+//  VOID
+//  CdInitializeDirent (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PDIRENT Dirent
+//      );
+//
+//  VOID
+//  CdInitializeDirContext (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PDIRENT_ENUM_CONTEXT DirContext
+//      );
+//
+//  VOID
+//  CdCleanupDirent (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PDIRENT Dirent
+//      );
+//
+//  VOID
+//  CdCleanupDirContext (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PDIRENT_ENUM_CONTEXT DirContext
+//      );
+//
+//  VOID
+//  CdLookupInitialFileDirent (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb,
+//      IN PFILE_ENUM_CONTEXT FileContext,
+//      IN ULONG DirentOffset
+//      );
+//
+
+#define CdInitializeFileContext(IC,FC) {                                \
+    RtlZeroMemory( FC, sizeof( FILE_ENUM_CONTEXT ));                    \
+    (FC)->PriorDirent = &(FC)->Dirents[0];                              \
+    (FC)->InitialDirent = &(FC)->Dirents[1];                            \
+    (FC)->CurrentDirent = &(FC)->Dirents[2];                            \
+    (FC)->ShortName.FileName.MaximumLength = BYTE_COUNT_8_DOT_3;        \
+    (FC)->ShortName.FileName.Buffer = (FC)->ShortNameBuffer;            \
+}
+
+#define CdInitializeDirent(IC,D)                                \
+    RtlZeroMemory( D, sizeof( DIRENT ))
+
+#define CdInitializeDirContext(IC,DC)                           \
+    RtlZeroMemory( DC, sizeof( DIRENT_ENUM_CONTEXT ))
+
+#define CdCleanupDirent(IC,D)  {                                \
+    if (FlagOn( (D)->Flags, DIRENT_FLAG_ALLOC_BUFFER )) {       \
+        CdFreePool( &(D)->CdFileName.FileName.Buffer );          \
+    }                                                           \
+}
+
+#define CdCleanupDirContext(IC,DC)                              \
+    CdUnpinData( (IC), &(DC)->Bcb )
+
+#define CdLookupInitialFileDirent(IC,F,FC,DO)                       \
+    CdLookupDirent( IC,                                             \
+                    F,                                              \
+                    DO,                                             \
+                    &(FC)->InitialDirent->DirContext );             \
+    CdUpdateDirentFromRawDirent( IC,                                \
+                                 F,                                 \
+                                 &(FC)->InitialDirent->DirContext,  \
+                                 &(FC)->InitialDirent->Dirent )
+
+\f
+//
+//  The following routines are used to manipulate the fscontext fields
+//  of the file object, implemented in FilObSup.c
+//
+
+//
+//  Type of opens.  FilObSup.c depends on this order.
+//
+
+typedef enum _TYPE_OF_OPEN {
+
+    UnopenedFileObject = 0,
+    StreamFileOpen,
+    UserVolumeOpen,
+    UserDirectoryOpen,
+    UserFileOpen,
+    BeyondValidType
+
+} TYPE_OF_OPEN;
+typedef TYPE_OF_OPEN *PTYPE_OF_OPEN;
+
+VOID
+CdSetFileObject (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFILE_OBJECT FileObject,
+    IN TYPE_OF_OPEN TypeOfOpen,
+    IN PFCB Fcb OPTIONAL,
+    IN PCCB Ccb OPTIONAL
+    );
+
+TYPE_OF_OPEN
+CdDecodeFileObject (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFILE_OBJECT FileObject,
+    OUT PFCB *Fcb,
+    OUT PCCB *Ccb
+    );
+
+TYPE_OF_OPEN
+CdFastDecodeFileObject (
+    IN PFILE_OBJECT FileObject,
+    OUT PFCB *Fcb
+    );
+
+\f
+//
+//  Name support routines, implemented in NameSup.c
+//
+
+VOID
+CdConvertNameToCdName (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PCD_NAME CdName
+    );
+
+VOID
+CdConvertBigToLittleEndian (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCHAR BigEndian,
+    IN ULONG ByteCount,
+    OUT PCHAR LittleEndian
+    );
+
+VOID
+CdUpcaseName (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCD_NAME Name,
+    IN OUT PCD_NAME UpcaseName
+    );
+
+VOID
+CdDissectName (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PUNICODE_STRING RemainingName,
+    OUT PUNICODE_STRING FinalName
+    );
+
+BOOLEAN
+CdIs8dot3Name (
+    IN PIRP_CONTEXT IrpContext,
+    IN UNICODE_STRING FileName
+    );
+
+VOID
+CdGenerate8dot3Name (
+    IN PIRP_CONTEXT IrpContext,
+    IN PUNICODE_STRING FileName,
+    IN ULONG DirentOffset,
+    OUT PWCHAR ShortFileName,
+    OUT PUSHORT ShortByteCount
+    );
+
+BOOLEAN
+CdIsNameInExpression (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCD_NAME CurrentName,
+    IN PCD_NAME SearchExpression,
+    IN ULONG  WildcardFlags,
+    IN BOOLEAN CheckVersion
+    );
+
+ULONG
+CdShortNameDirentOffset (
+    IN PIRP_CONTEXT IrpContext,
+    IN PUNICODE_STRING Name
+    );
+
+FSRTL_COMPARISON_RESULT
+CdFullCompareNames (
+    IN PIRP_CONTEXT IrpContext,
+    IN PUNICODE_STRING NameA,
+    IN PUNICODE_STRING NameB
+    );
+
+\f
+//
+//  Filesystem control operations.  Implemented in Fsctrl.c
+//
+
+NTSTATUS
+CdLockVolumeInternal (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PFILE_OBJECT FileObject OPTIONAL
+    );
+
+NTSTATUS
+CdUnlockVolumeInternal (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PFILE_OBJECT FileObject OPTIONAL
+    );
+
+\f
+//
+//  Path table enumeration routines.  Implemented in PathSup.c
+//
+
+VOID
+CdLookupPathEntry (
+    IN PIRP_CONTEXT IrpContext,
+    IN ULONG PathEntryOffset,
+    IN ULONG Ordinal,
+    IN BOOLEAN VerifyBounds,
+    IN OUT PCOMPOUND_PATH_ENTRY CompoundPathEntry
+    );
+
+BOOLEAN
+CdLookupNextPathEntry (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PPATH_ENUM_CONTEXT PathContext,
+    IN OUT PPATH_ENTRY PathEntry
+    );
+
+BOOLEAN
+CdFindPathEntry (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB ParentFcb,
+    IN PCD_NAME DirName,
+    IN BOOLEAN IgnoreCase,
+    IN OUT PCOMPOUND_PATH_ENTRY CompoundPathEntry
+    );
+
+VOID
+CdUpdatePathEntryName (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PPATH_ENTRY PathEntry,
+    IN BOOLEAN IgnoreCase
+    );
+
+//
+//  VOID
+//  CdInitializeCompoundPathEntry (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PCOMPOUND_PATH_ENTRY CompoundPathEntry
+//      );
+//
+//  VOID
+//  CdCleanupCompoundPathEntry (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PCOMPOUND_PATH_ENTRY CompoundPathEntry
+//      );
+//
+
+#define CdInitializeCompoundPathEntry(IC,CP)                                    \
+    RtlZeroMemory( CP, sizeof( COMPOUND_PATH_ENTRY ))
+
+#define CdCleanupCompoundPathEntry(IC,CP)     {                                 \
+    CdUnpinData( (IC), &(CP)->PathContext.Bcb );                                \
+    if ((CP)->PathContext.AllocatedData) {                                      \
+        CdFreePool( &(CP)->PathContext.Data );                                   \
+    }                                                                           \
+    if (FlagOn( (CP)->PathEntry.Flags, PATH_ENTRY_FLAG_ALLOC_BUFFER )) {        \
+        CdFreePool( &(CP)->PathEntry.CdDirName.FileName.Buffer );                \
+    }                                                                           \
+}
+
+\f
+//
+//  Largest matching prefix searching routines, implemented in PrefxSup.c
+//
+
+VOID
+CdInsertPrefix (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PCD_NAME Name,
+    IN BOOLEAN IgnoreCase,
+    IN BOOLEAN ShortNameMatch,
+    IN PFCB ParentFcb
+    );
+
+VOID
+CdRemovePrefix (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb
+    );
+
+VOID
+CdFindPrefix (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PFCB *CurrentFcb,
+    IN OUT PUNICODE_STRING RemainingName,
+    IN BOOLEAN IgnoreCase
+    );
+
+\f
+//
+//  Synchronization routines.  Implemented in Resrcsup.c
+//
+//  The following routines/macros are used to synchronize the in-memory structures.
+//
+//      Routine/Macro               Synchronizes                            Subsequent
+//
+//      CdAcquireCdData             Volume Mounts/Dismounts,Vcb Queue       CdReleaseCdData
+//      CdAcquireVcbExclusive       Vcb for open/close                      CdReleaseVcb
+//      CdAcquireVcbShared          Vcb for open/close                      CdReleaseVcb
+//      CdAcquireAllFiles           Locks out operations to all files       CdReleaseAllFiles
+//      CdAcquireFileExclusive      Locks out file operations               CdReleaseFile
+//      CdAcquireFileShared         Files for file operations               CdReleaseFile
+//      CdAcquireFcbExclusive       Fcb for open/close                      CdReleaseFcb
+//      CdAcquireFcbShared          Fcb for open/close                      CdReleaseFcb
+//      CdLockCdData                Fields in CdData                        CdUnlockCdData
+//      CdLockVcb                   Vcb fields, FcbReference, FcbTable      CdUnlockVcb
+//      CdLockFcb                   Fcb fields, prefix table, Mcb           CdUnlockFcb
+//
+
+typedef enum _TYPE_OF_ACQUIRE {
+    
+    AcquireExclusive,
+    AcquireShared,
+    AcquireSharedStarveExclusive
+
+} TYPE_OF_ACQUIRE, *PTYPE_OF_ACQUIRE;
+
+BOOLEAN
+CdAcquireResource (
+    IN PIRP_CONTEXT IrpContext,
+    IN PERESOURCE Resource,
+    IN BOOLEAN IgnoreWait,
+    IN TYPE_OF_ACQUIRE Type
+    );
+
+//
+//  BOOLEAN
+//  CdAcquireCdData (
+//      IN PIRP_CONTEXT IrpContext
+//      );
+//
+//  VOID
+//  CdReleaseCdData (
+//      IN PIRP_CONTEXT IrpContext
+//    );
+//
+//  BOOLEAN
+//  CdAcquireVcbExclusive (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PVCB Vcb,
+//      IN BOOLEAN IgnoreWait
+//      );
+//
+//  BOOLEAN
+//  CdAcquireVcbShared (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PVCB Vcb,
+//      IN BOOLEAN IgnoreWait
+//      );
+//
+//  VOID
+//  CdReleaseVcb (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PVCB Vcb
+//      );
+//
+//  VOID
+//  CdAcquireAllFiles (
+//      IN PIRP_CONTEXT,
+//      IN PVCB Vcb
+//      );
+//
+//  VOID
+//  CdReleaseAllFiles (
+//      IN PIRP_CONTEXT,
+//      IN PVCB Vcb
+//      );
+//
+//  VOID
+//  CdAcquireFileExclusive (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb,
+//      );
+//
+//  VOID
+//  CdAcquireFileShared (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+//  VOID
+//  CdReleaseFile (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//    );
+//
+//  BOOLEAN
+//  CdAcquireFcbExclusive (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb,
+//      IN BOOLEAN IgnoreWait
+//      );
+//
+//  BOOLEAN
+//  CdAcquireFcbShared (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb,
+//      IN BOOLEAN IgnoreWait
+//      );
+//
+//  BOOLEAN
+//  CdReleaseFcb (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+//  VOID
+//  CdLockCdData (
+//      );
+//
+//  VOID
+//  CdUnlockCdData (
+//      );
+//
+//  VOID
+//  CdLockVcb (
+//      IN PIRP_CONTEXT IrpContext
+//      );
+//
+//  VOID
+//  CdUnlockVcb (
+//      IN PIRP_CONTEXT IrpContext
+//      );
+//
+//  VOID
+//  CdLockFcb (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+//  VOID
+//  CdUnlockFcb (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+
+#define CdAcquireCdData(IC)                                                             \
+    ExAcquireResourceExclusiveLite( &CdData.DataResource, TRUE )
+
+#define CdReleaseCdData(IC)                                                             \
+    ExReleaseResourceLite( &CdData.DataResource )
+
+#define CdAcquireVcbExclusive(IC,V,I)                                                   \
+    CdAcquireResource( (IC), &(V)->VcbResource, (I), AcquireExclusive )
+
+#define CdAcquireVcbShared(IC,V,I)                                                      \
+    CdAcquireResource( (IC), &(V)->VcbResource, (I), AcquireShared )
+
+#define CdReleaseVcb(IC,V)                                                              \
+    ExReleaseResourceLite( &(V)->VcbResource )
+
+#define CdAcquireAllFiles(IC,V)                                                         \
+    CdAcquireResource( (IC), &(V)->FileResource, FALSE, AcquireExclusive )
+
+#define CdReleaseAllFiles(IC,V)                                                         \
+    ExReleaseResourceLite( &(V)->FileResource )
+
+#define CdAcquireFileExclusive(IC,F)                                                    \
+    CdAcquireResource( (IC), (F)->Resource, FALSE, AcquireExclusive )
+
+#define CdAcquireFileShared(IC,F)                                                       \
+    CdAcquireResource( (IC), (F)->Resource, FALSE, AcquireShared )
+
+#define CdAcquireFileSharedStarveExclusive(IC,F)                                        \
+    CdAcquireResource( (IC), (F)->Resource, FALSE, AcquireSharedStarveExclusive )
+
+#define CdReleaseFile(IC,F)                                                             \
+    ExReleaseResourceLite( (F)->Resource )
+
+#define CdAcquireFcbExclusive(IC,F,I)                                                   \
+    CdAcquireResource( (IC), &(F)->FcbNonpaged->FcbResource, (I), AcquireExclusive )
+
+#define CdAcquireFcbShared(IC,F,I)                                                      \
+    CdAcquireResource( (IC), &(F)->FcbNonpaged->FcbResource, (I), AcquireShared )
+
+#define CdReleaseFcb(IC,F)                                                              \
+    ExReleaseResourceLite( &(F)->FcbNonpaged->FcbResource )
+
+#define CdLockCdData()                                                                  \
+    ExAcquireFastMutex( &CdData.CdDataMutex );                                          \
+    CdData.CdDataLockThread = PsGetCurrentThread()
+
+#define CdUnlockCdData()                                                                \
+    CdData.CdDataLockThread = NULL;                                                     \
+    ExReleaseFastMutex( &CdData.CdDataMutex )
+
+#define CdLockVcb(IC,V)                                                                 \
+    ExAcquireFastMutex( &(V)->VcbMutex );                                               \
+    ASSERT( NULL == (V)->VcbLockThread);                                                \
+    (V)->VcbLockThread = PsGetCurrentThread()
+
+#define CdUnlockVcb(IC,V)                                                               \
+    ASSERT( NULL != (V)->VcbLockThread);                                                \
+    (V)->VcbLockThread = NULL;                                                          \
+    ExReleaseFastMutex( &(V)->VcbMutex )
+
+#define CdLockFcb(IC,F) {                                                               \
+    PVOID _CurrentThread = PsGetCurrentThread();                                        \
+    if (_CurrentThread != (F)->FcbLockThread) {                                         \
+        ExAcquireFastMutex( &(F)->FcbNonpaged->FcbMutex );                              \
+        ASSERT( (F)->FcbLockCount == 0 );                                               \
+        (F)->FcbLockThread = _CurrentThread;                                            \
+    }                                                                                   \
+    (F)->FcbLockCount += 1;                                                             \
+}
+
+#define CdUnlockFcb(IC,F) {                                                             \
+    (F)->FcbLockCount -= 1;                                                             \
+    if ((F)->FcbLockCount == 0) {                                                       \
+        (F)->FcbLockThread = NULL;                                                      \
+        ExReleaseFastMutex( &(F)->FcbNonpaged->FcbMutex );                              \
+    }                                                                                   \
+}
+
+BOOLEAN
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdNoopAcquire (
+    IN PVOID Fcb,
+    IN BOOLEAN Wait
+    );
+
+VOID
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdNoopRelease (
+    IN PVOID Fcb
+    );
+
+BOOLEAN
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdAcquireForCache (
+    IN PFCB Fcb,
+    IN BOOLEAN Wait
+    );
+
+VOID
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdReleaseFromCache (
+    IN PFCB Fcb
+    );
+
+VOID
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdAcquireForCreateSection (
+    IN PFILE_OBJECT FileObject
+    );
+
+VOID
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdReleaseForCreateSection (
+    IN PFILE_OBJECT FileObject
+    );
+
+\f
+//
+//  In-memory structure support routines.  Implemented in StrucSup.c
+//
+
+VOID
+CdInitializeVcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PVCB Vcb,
+    IN PDEVICE_OBJECT TargetDeviceObject,
+    IN PVPB Vpb,
+    IN PCDROM_TOC CdromToc,
+    IN ULONG TocLength,
+    IN ULONG TocTrackCount,
+    IN ULONG TocDiskFlags,
+    IN ULONG BlockFactor,
+    IN ULONG MediaChangeCount
+    );
+
+VOID
+CdUpdateVcbFromVolDescriptor (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PVCB Vcb,
+    IN PCHAR RawIsoVd OPTIONAL
+    );
+
+VOID
+CdDeleteVcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PVCB Vcb
+    );
+
+PFCB
+CdCreateFcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN FILE_ID FileId,
+    IN NODE_TYPE_CODE NodeTypeCode,
+    OUT PBOOLEAN FcbExisted OPTIONAL
+    );
+
+VOID
+CdInitializeFcbFromPathEntry (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PFCB ParentFcb OPTIONAL,
+    IN PPATH_ENTRY PathEntry
+    );
+
+VOID
+CdInitializeFcbFromFileContext (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PFCB ParentFcb OPTIONAL,
+    IN PFILE_ENUM_CONTEXT FileContext
+    );
+
+PCCB
+CdCreateCcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN ULONG Flags
+    );
+
+VOID
+CdDeleteCcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCCB Ccb
+    );
+
+BOOLEAN
+CdCreateFileLock (
+    IN PIRP_CONTEXT IrpContext OPTIONAL,
+    IN PFCB Fcb,
+    IN BOOLEAN RaiseOnError
+    );
+
+VOID
+CdDeleteFileLock (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFILE_LOCK FileLock
+    );
+
+PIRP_CONTEXT
+CdCreateIrpContext (
+    IN PIRP Irp,
+    IN BOOLEAN Wait
+    );
+
+VOID
+CdCleanupIrpContext (
+    IN PIRP_CONTEXT IrpContext,
+    IN BOOLEAN Post
+    );
+
+VOID
+CdInitializeStackIrpContext (
+    OUT PIRP_CONTEXT IrpContext,
+    IN PIRP_CONTEXT_LITE IrpContextLite
+    );
+
+//
+//  PIRP_CONTEXT_LITE
+//  CdCreateIrpContextLite (
+//      IN PIRP_CONTEXT IrpContext
+//      );
+//
+//  VOID
+//  CdFreeIrpContextLite (
+//      IN PIRP_CONTEXT_LITE IrpContextLite
+//      );
+//
+
+#define CdCreateIrpContextLite(IC)  \
+    ExAllocatePoolWithTag( CdNonPagedPool, sizeof( IRP_CONTEXT_LITE ), TAG_IRP_CONTEXT_LITE )
+
+#define CdFreeIrpContextLite(ICL)  \
+    CdFreePool( &(ICL) )
+
+VOID
+CdTeardownStructures (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB StartingFcb,
+    OUT PBOOLEAN RemovedStartingFcb
+    );
+
+//
+//  VOID
+//  CdIncrementCleanupCounts (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+//  VOID
+//  CdDecrementCleanupCounts (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+//  VOID
+//  CdIncrementReferenceCounts (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb,
+//      IN ULONG ReferenceCount
+//      IN ULONG UserReferenceCount
+//      );
+//
+//  VOID
+//  CdDecrementReferenceCounts (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb,
+//      IN ULONG ReferenceCount
+//      IN ULONG UserReferenceCount
+//      );
+//
+//  VOID
+//  CdIncrementFcbReference (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+//  VOID
+//  CdDecrementFcbReference (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+
+#define CdIncrementCleanupCounts(IC,F) {        \
+    ASSERT_LOCKED_VCB( (F)->Vcb );              \
+    (F)->FcbCleanup += 1;                       \
+    (F)->Vcb->VcbCleanup += 1;                  \
+}
+
+#define CdDecrementCleanupCounts(IC,F) {        \
+    ASSERT_LOCKED_VCB( (F)->Vcb );              \
+    (F)->FcbCleanup -= 1;                       \
+    (F)->Vcb->VcbCleanup -= 1;                  \
+}
+
+#define CdIncrementReferenceCounts(IC,F,C,UC) { \
+    ASSERT_LOCKED_VCB( (F)->Vcb );              \
+    (F)->FcbReference += (C);                   \
+    (F)->FcbUserReference += (UC);              \
+    (F)->Vcb->VcbReference += (C);              \
+    (F)->Vcb->VcbUserReference += (UC);         \
+}
+
+#define CdDecrementReferenceCounts(IC,F,C,UC) { \
+    ASSERT_LOCKED_VCB( (F)->Vcb );              \
+    (F)->FcbReference -= (C);                   \
+    (F)->FcbUserReference -= (UC);              \
+    (F)->Vcb->VcbReference -= (C);              \
+    (F)->Vcb->VcbUserReference -= (UC);         \
+}
+
+//
+//  PCD_IO_CONTEXT
+//  CdAllocateIoContext (
+//      );
+//
+//  VOID
+//  CdFreeIoContext (
+//      PCD_IO_CONTEXT IoContext
+//      );
+//
+
+#define CdAllocateIoContext()                           \
+    FsRtlAllocatePoolWithTag( CdNonPagedPool,           \
+                              sizeof( CD_IO_CONTEXT ),  \
+                              TAG_IO_CONTEXT )
+
+#define CdFreeIoContext(IO)     CdFreePool( &(IO) )
+
+PFCB
+CdLookupFcbTable (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN FILE_ID FileId
+    );
+
+PFCB
+CdGetNextFcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PVOID *RestartKey
+    );
+
+NTSTATUS
+CdProcessToc (
+    IN PIRP_CONTEXT IrpContext,
+    IN PDEVICE_OBJECT TargetDeviceObject,
+    IN PCDROM_TOC CdromToc,
+    IN OUT PULONG Length,
+    OUT PULONG TrackCount,
+    OUT PULONG DiskFlags
+    );
+
+//
+//  For debugging purposes we sometimes want to allocate our structures from nonpaged
+//  pool so that in the kernel debugger we can walk all the structures.
+//
+
+#define CdPagedPool                 PagedPool
+#define CdNonPagedPool              NonPagedPool
+#define CdNonPagedPoolCacheAligned  NonPagedPoolCacheAligned
+
+
+//
+//  Verification support routines.  Contained in verfysup.c
+//
+
+/* ReactOS Change: "LD multiple definition of `_CdOperationIsDasdOpen'" */
+static inline
+BOOLEAN
+CdOperationIsDasdOpen(
+    IN PIRP_CONTEXT IrpContext
+    )
+{
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->Irp);
+    
+    return ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
+            (IrpSp->FileObject->FileName.Length == 0) &&
+            (IrpSp->FileObject->RelatedFileObject == NULL));
+}
+
+
+NTSTATUS
+CdPerformVerify (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp,
+    IN PDEVICE_OBJECT DeviceToVerify
+    );
+
+BOOLEAN
+CdCheckForDismount (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB,
+    IN BOOLEAN Force
+    );
+
+VOID
+CdVerifyVcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb
+    );
+
+BOOLEAN
+CdVerifyFcbOperation (
+    IN PIRP_CONTEXT IrpContext OPTIONAL,
+    IN PFCB Fcb
+    );
+
+BOOLEAN
+CdDismountVcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb
+    );
+
+
+//
+//  Macros to abstract device verify flag changes.
+//
+
+#define CdUpdateMediaChangeCount( V, C)  (V)->MediaChangeCount = (C)
+#define CdUpdateVcbCondition( V, C)      (V)->VcbCondition = (C)
+
+#define CdMarkRealDevForVerify( DO)  SetFlag( (DO)->Flags, DO_VERIFY_VOLUME)
+                                     
+#define CdMarkRealDevVerifyOk( DO)   ClearFlag( (DO)->Flags, DO_VERIFY_VOLUME)
+
+
+#define CdRealDevNeedsVerify( DO)    BooleanFlagOn( (DO)->Flags, DO_VERIFY_VOLUME)
+
+//
+//  BOOLEAN
+//  CdIsRawDevice (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN NTSTATUS Status
+//      );
+//
+
+#define CdIsRawDevice(IC,S) (           \
+    ((S) == STATUS_DEVICE_NOT_READY) || \
+    ((S) == STATUS_NO_MEDIA_IN_DEVICE)  \
+)
+
+\f
+//
+//  Work queue routines for posting and retrieving an Irp, implemented in
+//  workque.c
+//
+
+NTSTATUS
+CdFsdPostRequest(
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+VOID
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdPrePostIrp (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+VOID
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdOplockComplete (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+\f
+//
+//  Miscellaneous support routines
+//
+
+//
+//  This macro returns TRUE if a flag in a set of flags is on and FALSE
+//  otherwise
+//
+
+/* ReactOS Change: GCC doesn't understand the comment style */
+/*
+ //#ifndef BooleanFlagOn
+//#define BooleanFlagOn(F,SF) (    \
+//    (BOOLEAN)(((F) & (SF)) != 0) \
+//)
+//#endif
+
+//#ifndef SetFlag
+//#define SetFlag(Flags,SingleFlag) { \
+//    (Flags) |= (SingleFlag);        \
+//}
+//#endif
+
+//#ifndef ClearFlag
+//#define ClearFlag(Flags,SingleFlag) { \
+//    (Flags) &= ~(SingleFlag);         \
+//}
+//#endif
+*/
+
+//
+//      CAST
+//      Add2Ptr (
+//          IN PVOID Pointer,
+//          IN ULONG Increment
+//          IN (CAST)
+//          );
+//
+//      ULONG
+//      PtrOffset (
+//          IN PVOID BasePtr,
+//          IN PVOID OffsetPtr
+//          );
+//
+
+#define Add2Ptr(PTR,INC,CAST) ((CAST)((PUCHAR)(PTR) + (INC)))
+
+#define PtrOffset(BASE,OFFSET) ((ULONG)((ULONG_PTR)(OFFSET) - (ULONG_PTR)(BASE)))
+
+//
+//  This macro takes a pointer (or ulong) and returns its rounded up word
+//  value
+//
+
+#define WordAlign(Ptr) (                \
+    ((((ULONG)(Ptr)) + 1) & 0xfffffffe) \
+    )
+
+//
+//  This macro takes a pointer (or ulong) and returns its rounded up longword
+//  value
+//
+
+#define LongAlign(Ptr) (                \
+    ((((ULONG)(Ptr)) + 3) & 0xfffffffc) \
+    )
+
+//
+//  This macro takes a pointer (or ulong) and returns its rounded up quadword
+//  value
+//
+
+#define QuadAlign(Ptr) (                \
+    ((((ULONG)(Ptr)) + 7) & 0xfffffff8) \
+    )
+
+//
+//  The following macros round up and down to sector boundaries.
+//
+
+#define SectorAlign(L) (                                                \
+    ((((ULONG)(L)) + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))           \
+)
+
+#define LlSectorAlign(L) (                                              \
+    ((((LONGLONG)(L)) + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))        \
+)
+
+#define SectorTruncate(L) (                                             \
+    ((ULONG)(L)) & ~(SECTOR_SIZE - 1)                                   \
+)
+
+#define LlSectorTruncate(L) (                                           \
+    ((LONGLONG)(L)) & ~(SECTOR_SIZE - 1)                                \
+)
+
+#define BytesFromSectors(L) (                                           \
+    ((ULONG) (L)) << SECTOR_SHIFT                                       \
+)
+
+#define SectorsFromBytes(L) (                                           \
+    ((ULONG) (L)) >> SECTOR_SHIFT                                       \
+)
+
+#define LlBytesFromSectors(L) (                                         \
+    Int64ShllMod32( (LONGLONG)(L), SECTOR_SHIFT )                       \
+)
+
+#define LlSectorsFromBytes(L) (                                         \
+    Int64ShraMod32( (LONGLONG)(L), SECTOR_SHIFT )                       \
+)
+
+#define SectorOffset(L) (                                               \
+    ((ULONG)(ULONG_PTR) (L)) & SECTOR_MASK                              \
+)
+
+#define SectorBlockOffset(V,LB) (                                       \
+    ((ULONG) (LB)) & ((V)->BlocksPerSector - 1)                         \
+)
+
+#define BytesFromBlocks(V,B) (                                          \
+    (ULONG) (B) << (V)->BlockToByteShift                                \
+)
+
+#define LlBytesFromBlocks(V,B) (                                        \
+    Int64ShllMod32( (LONGLONG) (B), (V)->BlockToByteShift )             \
+)
+
+#define BlockAlign(V,L) (                                               \
+    ((ULONG)(L) + (V)->BlockMask) & (V)->BlockInverseMask               \
+)
+
+//
+//  Carefully make sure the mask is sign extended to 64bits
+//
+
+#define LlBlockAlign(V,L) (                                                     \
+    ((LONGLONG)(L) + (V)->BlockMask) & (LONGLONG)((LONG)(V)->BlockInverseMask)  \
+)
+
+#define BlockOffset(V,L) (                                              \
+    ((ULONG) (L)) & (V)->BlockMask                                      \
+)
+
+#define RawSectorAlign( B) ((((B)+(RAW_SECTOR_SIZE - 1)) / RAW_SECTOR_SIZE) * RAW_SECTOR_SIZE)
+
+//
+//  The following types and macros are used to help unpack the packed and
+//  misaligned fields found in the Bios parameter block
+//
+
+typedef union _UCHAR1 {
+    UCHAR  Uchar[1];
+    UCHAR  ForceAlignment;
+} UCHAR1, *PUCHAR1;
+
+typedef union _UCHAR2 {
+    UCHAR  Uchar[2];
+    USHORT ForceAlignment;
+} UCHAR2, *PUCHAR2;
+
+typedef union _UCHAR4 {
+    UCHAR  Uchar[4];
+    ULONG  ForceAlignment;
+} UCHAR4, *PUCHAR4;
+
+typedef union _USHORT2 {
+    USHORT Ushort[2];
+    ULONG  ForceAlignment;
+} USHORT2, *PUSHORT2;
+
+//
+//  This macro copies an unaligned src byte to an aligned dst byte
+//
+
+#define CopyUchar1(Dst,Src) {                           \
+    *((UCHAR1 *)(Dst)) = *((UNALIGNED UCHAR1 *)(Src));  \
+    }
+
+//
+//  This macro copies an unaligned src word to an aligned dst word
+//
+
+#define CopyUchar2(Dst,Src) {                           \
+    *((UCHAR2 *)(Dst)) = *((UNALIGNED UCHAR2 *)(Src));  \
+    }
+
+//
+//  This macro copies an unaligned src longword to an aligned dsr longword
+//
+
+#define CopyUchar4(Dst,Src) {                           \
+    *((UCHAR4 *)(Dst)) = *((UNALIGNED UCHAR4 *)(Src));  \
+    }
+
+//
+//  This macro copies an unaligned src longword to an aligned dsr longword
+//  accessing the source on a word boundary.
+//
+
+#define CopyUshort2(Dst,Src) {                          \
+    *((USHORT2 *)(Dst)) = *((UNALIGNED USHORT2 *)(Src));\
+    }
+
+\f
+//
+//  Following routines handle entry in and out of the filesystem.  They are
+//  contained in CdData.c
+//
+
+NTSTATUS
+CdFsdDispatch (
+    IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
+    IN PIRP Irp
+    );
+
+LONG
+CdExceptionFilter (
+    IN PIRP_CONTEXT IrpContext,
+    IN PEXCEPTION_POINTERS ExceptionPointer
+    );
+
+NTSTATUS
+CdProcessException (
+    IN PIRP_CONTEXT IrpContext OPTIONAL,
+    IN PIRP Irp,
+    IN NTSTATUS ExceptionCode
+    );
+
+VOID
+CdCompleteRequest (
+    IN PIRP_CONTEXT IrpContext OPTIONAL,
+    IN PIRP Irp OPTIONAL,
+    IN NTSTATUS Status
+    );
+
+//
+//  VOID
+//  CdRaiseStatus (
+//      IN PRIP_CONTEXT IrpContext,
+//      IN NT_STATUS Status
+//      );
+//
+//  VOID
+//  CdNormalizeAndRaiseStatus (
+//      IN PRIP_CONTEXT IrpContext,
+//      IN NT_STATUS Status
+//      );
+//
+
+#if 0
+#define AssertVerifyDevice(C, S)                                                    \
+    ASSERT( (C) == NULL ||                                                          \
+            FlagOn( (C)->Flags, IRP_CONTEXT_FLAG_IN_FSP ) ||                        \
+            !((S) == STATUS_VERIFY_REQUIRED &&                                      \
+              IoGetDeviceToVerify( PsGetCurrentThread() ) == NULL ));
+
+#define AssertVerifyDeviceIrp(I)                                                    \
+    ASSERT( (I) == NULL ||                                                          \
+            !(((I)->IoStatus.Status) == STATUS_VERIFY_REQUIRED &&                   \
+              ((I)->Tail.Overlay.Thread == NULL ||                                  \
+                IoGetDeviceToVerify( (I)->Tail.Overlay.Thread ) == NULL )));
+#else
+#define AssertVerifyDevice(C, S)
+#define AssertVerifyDeviceIrp(I)
+#endif
+
+
+#ifdef CD_SANITY
+
+DECLSPEC_NORETURN
+VOID
+CdRaiseStatusEx(
+    IN PIRP_CONTEXT IrpContext,
+    IN NTSTATUS Status,
+    IN BOOLEAN NormalizeStatus,
+    IN OPTIONAL ULONG FileId,
+    IN OPTIONAL ULONG Line
+    );
+
+#else
+
+INLINE
+DECLSPEC_NORETURN
+VOID
+CdRaiseStatusEx(
+    IN PIRP_CONTEXT IrpContext,
+    IN NTSTATUS Status,
+    IN BOOLEAN NormalizeStatus,
+    IN ULONG Fileid,
+    IN ULONG Line
+    )
+{
+    if (NormalizeStatus)  {
+
+        IrpContext->ExceptionStatus = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR);
+    }
+    else {
+
+        IrpContext->ExceptionStatus = Status;
+    }
+
+    IrpContext->RaisedAtLineFile = (Fileid << 16) | Line;
+
+    ExRaiseStatus( IrpContext->ExceptionStatus );
+}
+
+#endif
+
+#define CdRaiseStatus( IC, S)               CdRaiseStatusEx( (IC), (S), FALSE, BugCheckFileId, __LINE__);
+#define CdNormalizeAndRaiseStatus( IC, S)   CdRaiseStatusEx( (IC), (S), TRUE, BugCheckFileId, __LINE__);
+
+//
+//  Following are the fast entry points.
+//
+
+BOOLEAN
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdFastQueryBasicInfo (
+    IN PFILE_OBJECT FileObject,
+    IN BOOLEAN Wait,
+    IN OUT PFILE_BASIC_INFORMATION Buffer,
+    OUT PIO_STATUS_BLOCK IoStatus,
+    IN PDEVICE_OBJECT DeviceObject
+    );
+
+BOOLEAN
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdFastQueryStdInfo (
+    IN PFILE_OBJECT FileObject,
+    IN BOOLEAN Wait,
+    IN OUT PFILE_STANDARD_INFORMATION Buffer,
+    OUT PIO_STATUS_BLOCK IoStatus,
+    IN PDEVICE_OBJECT DeviceObject
+    );
+
+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
+    );
+
+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
+    );
+
+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
+    );
+
+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
+    );
+
+BOOLEAN
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdFastIoCheckIfPossible (
+    IN PFILE_OBJECT FileObject,
+    IN PLARGE_INTEGER FileOffset,
+    IN ULONG Length,
+    IN BOOLEAN Wait,
+    IN ULONG LockKey,
+    IN BOOLEAN CheckForReadOperation,
+    OUT PIO_STATUS_BLOCK IoStatus,
+    IN PDEVICE_OBJECT DeviceObject
+    );
+
+BOOLEAN
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdFastQueryNetworkInfo (
+    IN PFILE_OBJECT FileObject,
+    IN BOOLEAN Wait,
+    OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
+    OUT PIO_STATUS_BLOCK IoStatus,
+    IN PDEVICE_OBJECT DeviceObject
+    );
+
+//
+//  Following are the routines to handle the top level thread logic.
+//
+
+VOID
+CdSetThreadContext (
+    IN PIRP_CONTEXT IrpContext,
+    IN PTHREAD_CONTEXT ThreadContext
+    );
+
+
+//
+//  VOID
+//  CdRestoreThreadContext (
+//      IN PIRP_CONTEXT IrpContext
+//      );
+//
+
+#define CdRestoreThreadContext(IC)                              \
+    (IC)->ThreadContext->Cdfs = 0;                              \
+    IoSetTopLevelIrp( (IC)->ThreadContext->SavedTopLevelIrp );  \
+    (IC)->ThreadContext = NULL
+
+ULONG
+CdSerial32 (
+    IN PCHAR Buffer,
+    IN ULONG ByteCount
+    );
+
+//
+//  The following macro is used to determine if an FSD thread can block
+//  for I/O or wait for a resource.  It returns TRUE if the thread can
+//  block and FALSE otherwise.  This attribute can then be used to call
+//  the FSD & FSP common work routine with the proper wait value.
+//
+
+#define CanFsdWait(I)   IoIsOperationSynchronous(I)
+
+//
+//  The following macro is used to set the fast i/o possible bits in the
+//  FsRtl header.
+//
+//      FastIoIsNotPossible - If the Fcb is bad or there are oplocks on the file.
+//
+//      FastIoIsQuestionable - If there are file locks.
+//
+//      FastIoIsPossible - In all other cases.
+//
+//
+
+#define CdIsFastIoPossible(F) ((BOOLEAN)                                            \
+    ((((F)->Vcb->VcbCondition != VcbMounted ) ||                                    \
+      !FsRtlOplockIsFastIoPossible( &(F)->Oplock )) ?                               \
+                                                                                    \
+     FastIoIsNotPossible :                                                          \
+                                                                                    \
+     ((((F)->FileLock != NULL) && FsRtlAreThereCurrentFileLocks( (F)->FileLock )) ? \
+                                                                                    \
+        FastIoIsQuestionable :                                                      \
+                                                                                    \
+        FastIoIsPossible))                                                          \
+)
+
+\f
+//
+//  The FSP level dispatch/main routine.  This is the routine that takes
+//  IRP's off of the work queue and calls the appropriate FSP level
+//  work routine.
+//
+
+VOID
+CdFspDispatch (                             //  implemented in FspDisp.c
+    IN PIRP_CONTEXT IrpContext
+    );
+
+VOID
+CdFspClose (                                //  implemented in Close.c
+    IN PVCB Vcb OPTIONAL
+    );
+
+//
+//  The following routines are the entry points for the different operations
+//  based on the IrpSp major functions.
+//
+
+NTSTATUS
+CdCommonCreate (                            //  Implemented in Create.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonClose (                             //  Implemented in Close.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonRead (                              //  Implemented in Read.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonQueryInfo (                         //  Implemented in FileInfo.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonSetInfo (                           //  Implemented in FileInfo.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonQueryVolInfo (                      //  Implemented in VolInfo.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonDirControl (                        //  Implemented in DirCtrl.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonFsControl (                         //  Implemented in FsCtrl.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonDevControl (                        //  Implemented in DevCtrl.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonLockControl (                       //  Implemented in LockCtrl.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonCleanup (                           //  Implemented in Cleanup.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdCommonPnp (                               //  Implemented in Pnp.c
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+\f
+//
+//  The following macros are used to establish the semantics needed
+//  to do a return from within a try-finally clause.  As a rule every
+//  try clause must end with a label call try_exit.  For example,
+//
+//      try {
+//              :
+//              :
+//
+//      try_exit: NOTHING;
+//      } finally {
+//
+//              :
+//              :
+//      }
+//
+//  Every return statement executed inside of a try clause should use the
+//  try_return macro.  If the compiler fully supports the try-finally construct
+//  then the macro should be
+//
+//      #define try_return(S)  { return(S); }
+//
+//  If the compiler does not support the try-finally construct then the macro
+//  should be
+//
+//      #define try_return(S)  { S; goto try_exit; }
+//
+/* ReactOS Change: Remove SEH */
+#define try
+#define leave goto exitLabel;
+#define finally  if (0) goto exitLabel; exitLabel:
+#define except(x) while (0)
+#define GetExceptionCode() 0
+#define AbnormalTermination() 0
+
+#define try_return(S) { goto try_exit; }
+#define try_leave(S) { leave; }
+
+
+//
+//  Encapsulate safe pool freeing
+//
+/* ReactOS Change: GCC "passing argument 1 of CdFreePool from incompatible pointer type" */
+#define CdFreePool(x) _CdFreePool((PVOID*)(x))
+
+/* ReactOS Change: "LD multiple definition of `_CdOperationIsDasdOpen'" */
+static inline void _CdFreePool(
+    IN PVOID *Pool
+    )
+{
+    if (*Pool != NULL) {
+
+        ExFreePool(*Pool);
+        *Pool = NULL;
+    }
+}
+
+#endif // _CDPROCS_
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/cdstruc.h b/reactos/drivers/filesystems/cdfs_new/cdstruc.h
new file mode 100755 (executable)
index 0000000..d3ffcfd
--- /dev/null
@@ -0,0 +1,1763 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    CdStruc.h
+
+Abstract:
+
+    This module defines the data structures that make up the major internal
+    part of the Cdfs file system.
+
+    In-Memory structures:
+
+        The global data structures with the CdDataRecord.  It contains a pointer
+        to a File System Device object and a queue of Vcb's.  There is a Vcb for
+        every currently or previously mounted volumes.  We may be in the process
+        of tearing down the Vcb's which have been dismounted.  The Vcb's are
+        allocated as an extension to a volume device object.
+
+            +--------+
+            | CdData |     +--------+
+            |        | --> |FilSysDo|
+            |        |     |        |
+            |        | <+  +--------+
+            +--------+  |
+                        |
+                        |  +--------+     +--------+
+                        |  |VolDo   |     |VolDo   |
+                        |  |        |     |        |
+                        |  +--------+     +--------+
+                        +> |Vcb     | <-> |Vcb     | <-> ...
+                           |        |     |        |
+                           +--------+     +--------+
+
+
+        Each Vcb contains a table of all the Fcbs for the volume indexed by
+        their FileId.  Each Vcb contains a pointer to the root directory of
+        the volume.  Each directory Fcb contains a queue of child Fcb's for
+        its children.  There can also be detached subtrees due to open operations
+        by Id where the Fcb's are not connected to the root.
+
+        The following diagram shows the root structure.
+
+            +--------+     +--------+
+            |  Vcb   |---->| Fcb    |-----------------------------------------------+
+            |        |     |  Table |--------------------------------------------+  |                                   |
+            |        |--+  |        |-----------------------------------------+  |  |                                   |
+            +--------+  |  +--------+                                         |  |  |
+                        |    |  |  |                                          |  |  |
+                        |    |  |  +--------------------+                     |  |  |
+                        |    V  +---------+             |                     |  |  |
+                        |  +--------+     |             |                     |  |  |
+                        |  |RootFcb |     V             V                     |  |  |
+                        +->|        |   +--------+    +--------+              |  |  |
+                           |        |-->|Child   |    |Child   |              |  |  |
+                           +--------+   | Fcb    |<-->| Fcb    |<--> ...      |  |  |
+                                        |        |    |        |              |  |  |
+                                        +--------+    +--------+              |  |  |
+                                                                              |  |  |
+                          (Freestanding sub-tree)                             |  |  |
+                          +--------+                                          |  |  |
+                          |OpenById|<-----------------------------------------+  |  |
+                          | Dir    |    +--------+                               |  |
+                          |        |--->|OpenById|<------------------------------+  |
+                          +--------+    | Child  |    +--------+                    |
+                                        |  Dir   |--->|OpenById|<-------------------+
+                                        +--------+    | Child  |
+                                                      |  File  |
+                                                      +--------+
+\f
+        Attached to each Directory Fcb is a prefix table containing the names
+        of children of this directory for which there is an Fcb.  Not all Fcb's
+        will necessarily have an entry in this table.
+
+            +--------+      +--------+
+            |  Dir   |      | Prefix |
+            |   Fcb  |----->|  Table |--------------------+
+            |        |      |        |-------+            |
+            +--------+      +--------+       |            |
+                |              |             |            |
+                |              |             |            |
+                |              V             V            V
+                |           +--------+    +--------+    +--------+    +--------+
+                |           |  Fcb   |    |  Fcb   |    |  Fcb   |    |  Fcb   |
+                +---------->|        |<-->|        |<-->|        |<-->|        |
+                            |        |    |        |    |        |    |        |
+                            +--------+    +--------+    +--------+    +--------+
+
+
+        Each file object open on a CDROM volume contains two context pointers.  The
+        first will point back to the Fcb for the file object.  The second, if present,
+        points to a Ccb (ContextControlBlock) which contains the per-handle information.
+        This includes the state of any directory enumeration.
+
+          +--------+       +--------+    +--------+
+          |  Fcb   |<------| File   |    |  Ccb   |
+          |        |       |  Object|--->|        |
+          |        |       |        |    |        |
+          +--------+       +--------+    +--------+
+            ^    ^
+            |    |         +--------+    +--------+
+            |    |         | File   |    |  Ccb   |
+            |    +---------|  Object|--->|        |
+            |              |        |    |        |
+            |              +--------+    +--------+
+            |
+            |              +--------+
+            |              |Stream  |
+            +--------------| File   |
+                           |  Object|
+                           +--------+
+
+\f
+    Synchronization:
+
+        1. A resource in the CdData synchronizes access to the Vcb queue.  This
+            is used during mount/verify/dismount operations.
+
+        2. A resource in the Vcb is used to synchronize access to Vcb for
+            open/close operations.  Typically acquired shared, it
+            is acquired exclusively to lock out these operations.
+
+        3. A second resource in the Vcb is used to synchronize all file operations.
+            Typically acquired shared, it is acquired exclusively to lock
+            out all file operations.  Acquiring both Vcb resources will lock
+            the entire volume.
+
+        4. A resource in the nonpaged Fcb will synchronize open/close operations
+            on an Fcb.
+
+        5. A fast mutex in the Vcb will protect access to the Fcb table and
+            the open counts in the Vcb.  It is also used to modify the reference
+            counts in all Fcbs.  This mutex cannot be acquired
+            exclusely and is an end resource.
+
+        6. A fast mutex in the Fcb will synchronize access to all Fcb fields
+            which aren't synchronized in some other way.  A thread may acquire
+            mutexes for multiple Fcb's as long as it works it way toward the
+            root of the tree.  This mutex can also be acquired recursively.
+
+        7. Normal locking order is CdData/Vcb/Fcb starting at any point in this
+            chain.  The Vcb is required prior to acquiring resources for multiple
+            files.  Shared ownership of the Vcb is sufficient in this case.
+
+        8. Normal locking order when acquiring multiple Fcb's is from some
+            starting Fcb and walking towards the root of tree.  Create typically
+            walks down the tree.  In this case we will attempt to acquire the
+            next node optimistically and if that fails we will reference
+            the current node in the tree, release it and acquire the next node.
+            At that point it will be safe to reacquire the parent node.
+
+        9. Locking order for the Fcb (via the fast mutex) will be from leaf of
+            tree back towards the root.  No other resource may be acquired
+            after locking the Vcb (other than in-page reads).
+
+       10. Cleanup operations only lock the Vcb and Fcb long enough to change the
+            critical counts and share access fields.  No reason to synchronize
+            otherwise.  None of the structures can go away from beneath us
+            in this case.
+
+
+--*/
+
+#ifndef _CDSTRUC_
+#define _CDSTRUC_
+
+typedef PVOID PBCB;     //**** Bcb's are now part of the cache module
+
+#define BYTE_COUNT_EMBEDDED_NAME        (32)
+
+\f
+//
+//  The CD_MCB is used to store the mapping of logical file offset to
+//  logical disk offset.  NOTE - This package only deals with the
+//  logical 2048 sectors.  Translating to 'raw' sectors happens in
+//  software.  We will embed a single MCB_ENTRY in the Fcb since this
+//  will be the typical case.
+//
+
+typedef struct _CD_MCB {
+
+    //
+    //  Size and current count of the Mcb entries.
+    //
+
+    ULONG MaximumEntryCount;
+    ULONG CurrentEntryCount;
+
+    //
+    //  Pointer to the start of the Mcb entries.
+    //
+
+    struct _CD_MCB_ENTRY *McbArray;
+
+} CD_MCB;
+typedef CD_MCB *PCD_MCB;
+
+typedef struct _CD_MCB_ENTRY {
+
+    //
+    //  Starting offset and number of bytes described by this entry.
+    //  The Byte count is rounded to a logical block boundary if this is
+    //  the last block.
+    //
+
+    LONGLONG DiskOffset;
+    LONGLONG ByteCount;
+
+    //
+    //  Starting offset in the file of mapping described by this dirent.
+    //
+
+    LONGLONG FileOffset;
+
+    //
+    //  Data length and block length.  Data length is the length of each
+    //  data block.  Total length is the length of each data block and
+    //  the skip size.
+    //
+
+    LONGLONG DataBlockByteCount;
+    LONGLONG TotalBlockByteCount;
+
+} CD_MCB_ENTRY;
+typedef CD_MCB_ENTRY *PCD_MCB_ENTRY;
+
+\f
+//
+//  Cd name structure.  The following structure is used to represent the
+//  full Cdrom name.  This name can be stored in either Unicode or ANSI
+//  format.
+//
+
+typedef struct _CD_NAME {
+
+    //
+    //  String containing name without the version number.
+    //  The maximum length field for filename indicates the
+    //  size of the buffer allocated for the two parts of the name.
+    //
+
+    UNICODE_STRING FileName;
+
+    //
+    //  String containging the version number.
+    //
+
+    UNICODE_STRING VersionString;
+
+} CD_NAME;
+typedef CD_NAME *PCD_NAME;
+
+//
+//  Following is the splay link structure for the prefix lookup.
+//  The names can be in either Unicode string or Ansi string format.
+//
+
+typedef struct _NAME_LINK {
+
+    RTL_SPLAY_LINKS Links;
+    UNICODE_STRING FileName;
+
+} NAME_LINK;
+typedef NAME_LINK *PNAME_LINK;
+
+\f
+//
+//  Prefix entry.  There is one of these for each name in the prefix table.
+//  An Fcb will have one of these embedded for the long name and an optional
+//  pointer to the short name entry.
+//
+
+typedef struct _PREFIX_ENTRY {
+
+    //
+    //  Pointer to the Fcb for this entry.
+    //
+
+    struct _FCB *Fcb;
+
+    //
+    //  Flags field.  Used to indicate if the name is in the prefix table.
+    //
+
+    ULONG PrefixFlags;
+
+    //
+    //  Exact case name match.
+    //
+
+    NAME_LINK ExactCaseName;
+
+    //
+    //  Case-insensitive name link.
+    //
+
+    NAME_LINK IgnoreCaseName;
+
+    WCHAR FileNameBuffer[ BYTE_COUNT_EMBEDDED_NAME ];
+
+} PREFIX_ENTRY;
+typedef PREFIX_ENTRY *PPREFIX_ENTRY;
+
+#define PREFIX_FLAG_EXACT_CASE_IN_TREE              (0x00000001)
+#define PREFIX_FLAG_IGNORE_CASE_IN_TREE             (0x00000002)
+
+\f
+//
+//  The CD_DATA record is the top record in the CDROM file system in-memory
+//  data structure.  This structure must be allocated from non-paged pool.
+//
+
+typedef struct _CD_DATA {
+
+    //
+    //  The type and size of this record (must be CDFS_NTC_DATA_HEADER)
+    //
+
+    NODE_TYPE_CODE NodeTypeCode;
+    NODE_BYTE_SIZE NodeByteSize;
+
+    //
+    //  A pointer to the Driver object we were initialized with
+    //
+
+    PDRIVER_OBJECT DriverObject;
+
+    //
+    //  Vcb queue.
+    //
+
+    LIST_ENTRY VcbQueue;
+
+    //
+    //  The following fields are used to allocate IRP context structures
+    //  using a lookaside list, and other fixed sized structures from a
+    //  small cache.  We use the CdData mutex to protext these structures.
+    //
+
+    ULONG IrpContextDepth;
+    ULONG IrpContextMaxDepth;
+    SINGLE_LIST_ENTRY IrpContextList;
+
+    //
+    //  Filesystem device object for CDFS.
+    //
+
+    PDEVICE_OBJECT FileSystemDeviceObject;
+
+    //
+    //  Following are used to manage the async and delayed close queue.
+    //
+    //  FspCloseActive - Indicates whether there is a thread processing the
+    //      two close queues.
+    //  ReduceDelayedClose - Indicates that we have hit the upper threshold
+    //      for the delayed close queue and need to reduce it to lower threshold.
+    //
+    //  AsyncCloseQueue - Queue of IrpContext waiting for async close operation.
+    //  AsyncCloseCount - Number of entries on the async close queue.
+    //
+    //  DelayedCloseQueue - Queue of IrpContextLite waiting for delayed close
+    //      operation.
+    //  MaxDelayedCloseCount - Trigger delay close work at this threshold.
+    //  MinDelayedCloseCount - Turn off delay close work at this threshold.
+    //  DelayedCloseCount - Number of entries on the delayted close queue.
+    //
+    //  CloseItem - Workqueue item used to start FspClose thread.
+    //
+
+    LIST_ENTRY AsyncCloseQueue;
+    ULONG AsyncCloseCount;
+    BOOLEAN FspCloseActive;
+    BOOLEAN ReduceDelayedClose;
+    USHORT PadUshort;
+
+    //
+    //  The following fields describe the deferred close file objects.
+    //
+
+    LIST_ENTRY DelayedCloseQueue;
+    ULONG DelayedCloseCount;
+    ULONG MaxDelayedCloseCount;
+    ULONG MinDelayedCloseCount;
+
+    //
+    //  Fast mutex used to lock the fields of this structure.
+    //
+
+    PVOID CdDataLockThread;
+    FAST_MUTEX CdDataMutex;
+
+    //
+    //  A resource variable to control access to the global CDFS data record
+    //
+
+    ERESOURCE DataResource;
+
+    //
+    //  Cache manager call back structure, which must be passed on each call
+    //  to CcInitializeCacheMap.
+    //
+
+    CACHE_MANAGER_CALLBACKS CacheManagerCallbacks;
+    CACHE_MANAGER_CALLBACKS CacheManagerVolumeCallbacks;
+
+    //
+    //  This is the ExWorkerItem that does both kinds of deferred closes.
+    //
+
+    PIO_WORKITEM CloseItem;
+
+} CD_DATA;
+typedef CD_DATA *PCD_DATA;
+
+\f
+//
+//  The Vcb (Volume control block) record corresponds to every
+//  volume mounted by the file system.  They are ordered in a queue off
+//  of CdData.VcbQueue.
+//
+//  The Vcb will be in several conditions during its lifespan.
+//
+//      NotMounted - Disk is not currently mounted (i.e. removed
+//          from system) but cleanup and close operations are
+//          supported.
+//
+//      MountInProgress - State of the Vcb from the time it is
+//          created until it is successfully mounted or the mount
+//          fails.
+//
+//      Mounted - Volume is currently in the mounted state.
+//
+//      Invalid - User has invalidated the volume.  Only legal operations
+//          are cleanup and close.
+//
+//      DismountInProgress - We have begun the process of tearing down the
+//          Vcb.  It can be deleted when all the references to it
+//          have gone away.
+//
+
+typedef enum _VCB_CONDITION {
+
+    VcbNotMounted = 0,
+    VcbMountInProgress,
+    VcbMounted,
+    VcbInvalid,
+    VcbDismountInProgress
+
+} VCB_CONDITION;
+
+typedef struct _VCB {
+
+    //
+    //  The type and size of this record (must be CDFS_NTC_VCB)
+    //
+
+    NODE_TYPE_CODE NodeTypeCode;
+    NODE_BYTE_SIZE NodeByteSize;
+
+    //
+    //  Vpb for this volume.
+    //
+
+    PVPB Vpb;
+
+    //
+    //  Device object for the driver below us.
+    //
+
+    PDEVICE_OBJECT TargetDeviceObject;
+
+    //
+    //  File object used to lock the volume.
+    //
+
+    PFILE_OBJECT VolumeLockFileObject;
+
+    //
+    //  Link into queue of Vcb's in the CdData structure.  We will create a union with
+    //  a LONGLONG to force the Vcb to be quad-aligned.
+    //
+
+    union {
+
+        LIST_ENTRY VcbLinks;
+        LONGLONG Alignment;
+    };
+
+    //
+    //  State flags and condition for the Vcb.
+    //
+
+    ULONG VcbState;
+    VCB_CONDITION VcbCondition;
+
+    //
+    //  Various counts for this Vcb.
+    //
+    //      VcbCleanup - Open handles left on this system.
+    //      VcbReference - Number of reasons this Vcb is still present.
+    //      VcbUserReference - Number of user file objects still present.
+    //
+
+    ULONG VcbCleanup;
+    LONG VcbReference; /* ReactOS Change: GCC 'pointer targets in passing argument 1 of 'InterlockedXxx' differ in signedness */
+    LONG VcbUserReference; /* ReactOS Change: GCC 'pointer targets in passing argument 1 of 'InterlockedXxx' differ in signedness */
+
+    //
+    //  Fcb for the Volume Dasd file, root directory and the Path Table.
+    //
+
+    struct _FCB *VolumeDasdFcb;
+    struct _FCB *RootIndexFcb;
+    struct _FCB *PathTableFcb;
+
+    //
+    //  Location of current session and offset of volume descriptors.
+    //
+
+    ULONG BaseSector;
+    ULONG VdSectorOffset;
+    ULONG PrimaryVdSectorOffset;
+
+    //
+    //  Following is a sector from the last non-cached read of an XA file.
+    //  Also the cooked offset on the disk.
+    //
+
+    PVOID XASector;
+    LONGLONG XADiskOffset;
+
+    //
+    //  Vcb resource.  This is used to synchronize open/cleanup/close operations.
+    //
+
+    ERESOURCE VcbResource;
+
+    //
+    //  File resource.  This is used to synchronize all file operations except
+    //  open/cleanup/close.
+    //
+
+    ERESOURCE FileResource;
+
+    //
+    //  Vcb fast mutex.  This is used to synchronize the fields in the Vcb
+    //  when modified when the Vcb is not held exclusively.  Included here
+    //  are the count fields and Fcb table.
+    //
+    //  We also use this to synchronize changes to the Fcb reference field.
+    //
+
+    FAST_MUTEX VcbMutex;
+    PVOID VcbLockThread;
+
+    //
+    //  The following is used to synchronize the dir notify package.
+    //
+
+    PNOTIFY_SYNC NotifySync;
+
+    //
+    //  The following is the head of a list of notify Irps.
+    //
+
+    LIST_ENTRY DirNotifyList;
+
+    //
+    //  Logical block size for this volume as well constant values
+    //  associated with the block size.
+    //
+
+    ULONG BlockSize;
+    ULONG BlockToSectorShift;
+    ULONG BlockToByteShift;
+    ULONG BlocksPerSector;
+    ULONG BlockMask;
+    ULONG BlockInverseMask;
+
+    //
+    //  Fcb table.  Synchronized with the Vcb fast mutex.
+    //
+
+    RTL_GENERIC_TABLE FcbTable;
+
+    //
+    //  Volume TOC.  Cache this information for quick lookup.
+    //
+
+    PCDROM_TOC CdromToc;
+    ULONG TocLength;
+    ULONG TrackCount;
+    ULONG DiskFlags;
+
+    //
+    //  Block factor to determine last session information.
+    //
+
+    ULONG BlockFactor;
+
+    //
+    //  Media change count from device driver for bulletproof detection
+    //  of media movement
+    //
+
+    ULONG MediaChangeCount;
+
+    //
+    //  For raw reads, CDFS must obey the port maximum transfer restrictions.
+    //
+
+    ULONG MaximumTransferRawSectors;
+    ULONG MaximumPhysicalPages;
+
+    //
+    //  Preallocated VPB for swapout, so we are not forced to consider
+    //  must succeed pool.
+    //
+
+    PVPB SwapVpb;
+
+} VCB;
+typedef VCB *PVCB;
+
+#define VCB_STATE_HSG                               (0x00000001)
+#define VCB_STATE_ISO                               (0x00000002)
+#define VCB_STATE_JOLIET                            (0x00000004)
+#define VCB_STATE_LOCKED                            (0x00000010)
+#define VCB_STATE_REMOVABLE_MEDIA                   (0x00000020)
+#define VCB_STATE_CDXA                              (0x00000040)
+#define VCB_STATE_AUDIO_DISK                        (0x00000080)
+#define VCB_STATE_NOTIFY_REMOUNT                    (0x00000100)
+#define VCB_STATE_VPB_NOT_ON_DEVICE                 (0x00000200)
+
+\f
+//
+//  The Volume Device Object is an I/O system device object with a
+//  workqueue and an VCB record appended to the end.  There are multiple
+//  of these records, one for every mounted volume, and are created during
+//  a volume mount operation.  The work queue is for handling an overload
+//  of work requests to the volume.
+//
+
+typedef struct _VOLUME_DEVICE_OBJECT {
+
+    DEVICE_OBJECT DeviceObject;
+
+    //
+    //  The following field tells how many requests for this volume have
+    //  either been enqueued to ExWorker threads or are currently being
+    //  serviced by ExWorker threads.  If the number goes above
+    //  a certain threshold, put the request on the overflow queue to be
+    //  executed later.
+    //
+
+    LONG PostedRequestCount; /* ReactOS Change: GCC "pointer targets in passing argument 1 of 'InterlockedDecrement' differ in signedness" */
+
+    //
+    //  The following field indicates the number of IRP's waiting
+    //  to be serviced in the overflow queue.
+    //
+
+    ULONG OverflowQueueCount;
+
+    //
+    //  The following field contains the queue header of the overflow queue.
+    //  The Overflow queue is a list of IRP's linked via the IRP's ListEntry
+    //  field.
+    //
+
+    LIST_ENTRY OverflowQueue;
+
+    //
+    //  The following spinlock protects access to all the above fields.
+    //
+
+    KSPIN_LOCK OverflowQueueSpinLock;
+
+    //
+    //  This is the file system specific volume control block.
+    //
+
+    VCB Vcb;
+
+} VOLUME_DEVICE_OBJECT;
+typedef VOLUME_DEVICE_OBJECT *PVOLUME_DEVICE_OBJECT;
+
+\f
+//
+//  The following two structures are the separate union structures for
+//  data and index Fcb's.  The path table is actually the same structure
+//  as the index Fcb since it uses the first few fields.
+//
+
+typedef enum _FCB_CONDITION {
+    FcbGood = 1,
+    FcbBad,
+    FcbNeedsToBeVerified
+} FCB_CONDITION;
+
+typedef struct _FCB_DATA {
+
+    //
+    //  The following field is used by the oplock module
+    //  to maintain current oplock information.
+    //
+
+    OPLOCK Oplock;
+
+    //
+    //  The following field is used by the filelock module
+    //  to maintain current byte range locking information.
+    //  A file lock is allocated as needed.
+    //
+
+    PFILE_LOCK FileLock;
+
+} FCB_DATA;
+typedef FCB_DATA *PFCB_DATA;
+
+typedef struct _FCB_INDEX {
+
+    //
+    //  Internal stream file.
+    //
+
+    PFILE_OBJECT FileObject;
+
+    //
+    //  Offset of first entry in stream.  This is for case where directory
+    //  or path table does not begin on a sector boundary.  This value is
+    //  added to all offset values to determine the real offset.
+    //
+
+    ULONG StreamOffset;
+
+    //
+    //  List of child fcbs.
+    //
+
+    LIST_ENTRY FcbQueue;
+
+    //
+    //  Ordinal number for this directory.  Combine this with the path table offset
+    //  in the FileId and you have a starting point in the path table.
+    //
+
+    ULONG Ordinal;
+
+    //
+    //  Children path table start.  This is the offset in the path table
+    //  for the first child of the directory.  A value of zero indicates
+    //  that we haven't found the first child yet.  If there are no child
+    //  directories we will position at a point in the path table so that
+    //  subsequent searches will fail quickly.
+    //
+
+    ULONG ChildPathTableOffset;
+    ULONG ChildOrdinal;
+
+    //
+    //  Root of splay trees for exact and ignore case prefix trees.
+    //
+
+    PRTL_SPLAY_LINKS ExactCaseRoot;
+    PRTL_SPLAY_LINKS IgnoreCaseRoot;
+
+} FCB_INDEX;
+typedef FCB_INDEX *PFCB_INDEX;
+
+typedef struct _FCB_NONPAGED {
+
+    //
+    //  Type and size of this record must be CDFS_NTC_FCB_NONPAGED
+    //
+
+    NODE_TYPE_CODE NodeTypeCode;
+    NODE_BYTE_SIZE NodeByteSize;
+
+    //
+    //  The following field contains a record of special pointers used by
+    //  MM and Cache to manipluate section objects.  Note that the values
+    //  are set outside of the file system.  However the file system on an
+    //  open/create will set the file object's SectionObject field to
+    //  point to this field
+    //
+
+    SECTION_OBJECT_POINTERS SegmentObject;
+
+    //
+    //  This is the resource structure for this Fcb.
+    //
+
+    ERESOURCE FcbResource;
+
+    //
+    //  This is the FastMutex for this Fcb.
+    //
+
+    FAST_MUTEX FcbMutex;
+
+    //
+    //  This is the mutex that is inserted into the FCB_ADVANCED_HEADER
+    //  FastMutex field
+    //
+
+    FAST_MUTEX AdvancedFcbHeaderMutex;
+
+} FCB_NONPAGED;
+typedef FCB_NONPAGED *PFCB_NONPAGED;
+
+//
+//  The Fcb/Dcb record corresponds to every open file and directory, and to
+//  every directory on an opened path.
+//
+
+typedef struct _FCB {
+
+    //
+    //  The following field is used for fast I/O.  It contains the node
+    //  type code and size, indicates if fast I/O is possible, contains
+    //  allocation, file, and valid data size, a resource, and call back
+    //  pointers for FastIoRead and FastMdlRead.
+    //
+    //
+    //  Node type codes for the Fcb must be one of the following.
+    //
+    //      CDFS_NTC_FCB_PATH_TABLE
+    //      CDFS_NTC_FCB_INDEX
+    //      CDFS_NTC_FCB_DATA
+    //
+
+    //
+    //  Common Fsrtl Header.  The named header is for the fieldoff.c output.  We
+    //  use the unnamed header internally.
+    //
+
+    union{
+
+        FSRTL_ADVANCED_FCB_HEADER Header;
+        FSRTL_ADVANCED_FCB_HEADER;
+    };
+
+    //
+    //  Vcb for this Fcb.
+    //
+
+    PVCB Vcb;
+
+    //
+    //  Parent Fcb for this Fcb.  This may be NULL if this file was opened
+    //  by ID, also for the root Fcb.
+    //
+
+    struct _FCB *ParentFcb;
+
+    //
+    //  Links to the queue of Fcb's in the parent.
+    //
+
+    LIST_ENTRY FcbLinks;
+
+    //
+    //  FileId for this file.
+    //
+
+    FILE_ID FileId;
+
+    //
+    //  Counts on this Fcb.  Cleanup count represents the number of open handles
+    //  on this Fcb.  Reference count represents the number of reasons this Fcb
+    //  is still present.  It includes file objects, children Fcb and anyone
+    //  who wants to prevent this Fcb from going away.  Cleanup count is synchronized
+    //  with the FcbResource.  The reference count is synchronized with the
+    //  VcbMutex.
+    //
+
+    ULONG FcbCleanup;
+    LONG FcbReference; /* ReactOS Change: GCC 'pointer targets in passing argument 1 of 'InterlockedXxx' differ in signedness */
+    ULONG FcbUserReference;
+
+    //
+    //  State flags for this Fcb.
+    //
+
+    ULONG FcbState;
+
+    //
+    //  NT style attributes for the Fcb.
+    //
+
+    ULONG FileAttributes;
+
+    //
+    //  CDXA attributes for this file.
+    //
+
+    USHORT XAAttributes;
+
+    //
+    //  File number from the system use area.
+    //
+
+    UCHAR XAFileNumber;
+
+    //
+    //  This is the thread and count for the thread which has locked this
+    //  Fcb.
+    //
+
+    PVOID FcbLockThread;
+    ULONG FcbLockCount;
+
+    //
+    //  Pointer to the Fcb non-paged structures.
+    //
+
+    PFCB_NONPAGED FcbNonpaged;
+
+    //
+    //  Share access structure.
+    //
+
+    SHARE_ACCESS ShareAccess;
+
+    //
+    //  Mcb for the on disk mapping and a single map entry.
+    //
+
+    CD_MCB_ENTRY McbEntry;
+    CD_MCB Mcb;
+
+    //
+    //  Embed the prefix entry for the longname.  Store an optional pointer
+    //  to a prefix structure for the short name.
+    //
+
+    PPREFIX_ENTRY ShortNamePrefix;
+    PREFIX_ENTRY FileNamePrefix;
+
+    //
+    //  Time stamp for this file.
+    //
+
+    LONGLONG CreationTime;
+
+    union{
+
+        ULONG FcbType;
+        FCB_DATA;
+        FCB_INDEX;
+    };
+
+} FCB;
+typedef FCB *PFCB;
+
+#define FCB_STATE_INITIALIZED                   (0x00000001)
+#define FCB_STATE_IN_FCB_TABLE                  (0x00000002)
+#define FCB_STATE_MODE2FORM2_FILE               (0x00000004)
+#define FCB_STATE_MODE2_FILE                    (0x00000008)
+#define FCB_STATE_DA_FILE                       (0x00000010)
+
+//
+//  These file types are read as raw 2352 byte sectors
+//
+
+#define FCB_STATE_RAWSECTOR_MASK                ( FCB_STATE_MODE2FORM2_FILE | \
+                                                  FCB_STATE_MODE2_FILE      | \
+                                                  FCB_STATE_DA_FILE )
+
+#define SIZEOF_FCB_DATA     \
+    (FIELD_OFFSET( FCB, FcbType ) + sizeof( FCB_DATA ))
+
+#define SIZEOF_FCB_INDEX    \
+    (FIELD_OFFSET( FCB, FcbType ) + sizeof( FCB_INDEX ))
+
+\f
+//
+//  The Ccb record is allocated for every file object
+//
+
+typedef struct _CCB {
+
+    //
+    //  Type and size of this record (must be CDFS_NTC_CCB)
+    //
+
+    NODE_TYPE_CODE NodeTypeCode;
+    NODE_BYTE_SIZE NodeByteSize;
+
+    //
+    //  Flags.  Indicates flags to apply for the current open.
+    //
+
+    ULONG Flags;
+
+    //
+    //  Fcb for the file being opened.
+    //
+
+    PFCB Fcb;
+
+    //
+    //  We store state information in the Ccb for a directory
+    //  enumeration on this handle.
+    //
+
+    //
+    //  Offset in the directory stream to base the next enumeration.
+    //
+
+    ULONG CurrentDirentOffset;
+    CD_NAME SearchExpression;
+
+} CCB;
+typedef CCB *PCCB;
+
+#define CCB_FLAG_OPEN_BY_ID                     (0x00000001)
+#define CCB_FLAG_OPEN_RELATIVE_BY_ID            (0x00000002)
+#define CCB_FLAG_IGNORE_CASE                    (0x00000004)
+#define CCB_FLAG_OPEN_WITH_VERSION              (0x00000008)
+#define CCB_FLAG_DISMOUNT_ON_CLOSE              (0x00000010)
+
+//
+//  Following flags refer to index enumeration.
+//
+
+#define CCB_FLAG_ENUM_NAME_EXP_HAS_WILD         (0x00010000)
+#define CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD      (0x00020000)
+#define CCB_FLAG_ENUM_MATCH_ALL                 (0x00040000)
+#define CCB_FLAG_ENUM_VERSION_MATCH_ALL         (0x00080000)
+#define CCB_FLAG_ENUM_RETURN_NEXT               (0x00100000)
+#define CCB_FLAG_ENUM_INITIALIZED               (0x00200000)
+#define CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY    (0x00400000)
+
+\f
+//
+//  The Irp Context record is allocated for every orginating Irp.  It is
+//  created by the Fsd dispatch routines, and deallocated by the CdComplete
+//  request routine
+//
+
+typedef struct _IRP_CONTEXT {
+
+    //
+    //  Type and size of this record (must be CDFS_NTC_IRP_CONTEXT)
+    //
+
+    NODE_TYPE_CODE NodeTypeCode;
+    NODE_BYTE_SIZE NodeByteSize;
+
+    //
+    //  Originating Irp for the request.
+    //
+
+    PIRP Irp;
+
+    //
+    //  Vcb for this operation.  When this is NULL it means we were called
+    //  with our filesystem device object instead of a volume device object.
+    //  (Mount will fill this in once the Vcb is created)
+    //
+
+    PVCB Vcb;
+
+    //
+    //  Exception encountered during the request.  Any error raised explicitly by
+    //  the file system will be stored here.  Any other error raised by the system
+    //  is stored here after normalizing it.
+    //
+
+    NTSTATUS ExceptionStatus;
+    ULONG RaisedAtLineFile;
+
+    //
+    //  Flags for this request.
+    //
+
+    ULONG Flags;
+
+    //
+    //  Real device object.  This represents the physical device closest to the media.
+    //
+
+    PDEVICE_OBJECT RealDevice;
+
+    //
+    //  Io context for a read request.
+    //  Address of Fcb for teardown oplock in create case.
+    //
+
+    union {
+
+        struct _CD_IO_CONTEXT *IoContext;
+        PFCB *TeardownFcb;
+    };
+
+    //
+    //  Top level irp context for this thread.
+    //
+
+    struct _IRP_CONTEXT *TopLevel;
+
+    //
+    //  Major and minor function codes.
+    //
+
+    UCHAR MajorFunction;
+    UCHAR MinorFunction;
+
+    //
+    //  Pointer to the top-level context if this IrpContext is responsible
+    //  for cleaning it up.
+    //
+
+    struct _THREAD_CONTEXT *ThreadContext;
+
+    //
+    //  This structure is used for posting to the Ex worker threads.
+    //
+
+    WORK_QUEUE_ITEM WorkQueueItem;
+
+} IRP_CONTEXT;
+typedef IRP_CONTEXT *PIRP_CONTEXT;
+
+#define IRP_CONTEXT_FLAG_ON_STACK               (0x00000001)
+#define IRP_CONTEXT_FLAG_MORE_PROCESSING        (0x00000002)
+#define IRP_CONTEXT_FLAG_WAIT                   (0x00000004)
+#define IRP_CONTEXT_FLAG_FORCE_POST             (0x00000008)
+#define IRP_CONTEXT_FLAG_TOP_LEVEL              (0x00000010)
+#define IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS         (0x00000020)
+#define IRP_CONTEXT_FLAG_IN_FSP                 (0x00000040)
+#define IRP_CONTEXT_FLAG_IN_TEARDOWN            (0x00000080)
+#define IRP_CONTEXT_FLAG_ALLOC_IO               (0x00000100)
+#define IRP_CONTEXT_FLAG_DISABLE_POPUPS         (0x00000200)
+#define IRP_CONTEXT_FLAG_FORCE_VERIFY           (0x00000400)
+
+//
+//  Flags used for create.
+//
+
+#define IRP_CONTEXT_FLAG_FULL_NAME              (0x10000000)
+#define IRP_CONTEXT_FLAG_TRAIL_BACKSLASH        (0x20000000)
+
+//
+//  The following flags need to be cleared when a request is posted.
+//
+
+#define IRP_CONTEXT_FLAGS_CLEAR_ON_POST (   \
+    IRP_CONTEXT_FLAG_MORE_PROCESSING    |   \
+    IRP_CONTEXT_FLAG_WAIT               |   \
+    IRP_CONTEXT_FLAG_FORCE_POST         |   \
+    IRP_CONTEXT_FLAG_TOP_LEVEL          |   \
+    IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS     |   \
+    IRP_CONTEXT_FLAG_IN_FSP             |   \
+    IRP_CONTEXT_FLAG_IN_TEARDOWN        |   \
+    IRP_CONTEXT_FLAG_DISABLE_POPUPS         \
+)
+
+//
+//  The following flags need to be cleared when a request is retried.
+//
+
+#define IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY (  \
+    IRP_CONTEXT_FLAG_MORE_PROCESSING    |   \
+    IRP_CONTEXT_FLAG_IN_TEARDOWN        |   \
+    IRP_CONTEXT_FLAG_DISABLE_POPUPS         \
+)
+
+//
+//  The following flags are set each time through the Fsp loop.
+//
+
+#define IRP_CONTEXT_FSP_FLAGS (             \
+    IRP_CONTEXT_FLAG_WAIT               |   \
+    IRP_CONTEXT_FLAG_TOP_LEVEL          |   \
+    IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS     |   \
+    IRP_CONTEXT_FLAG_IN_FSP                 \
+)
+
+\f
+//
+//  Following structure is used to queue a request to the delayed close queue.
+//  This structure should be the minimum block allocation size.
+//
+
+typedef struct _IRP_CONTEXT_LITE {
+
+    //
+    //  Type and size of this record (must be CDFS_NTC_IRP_CONTEXT_LITE)
+    //
+
+    NODE_TYPE_CODE NodeTypeCode;
+    NODE_BYTE_SIZE NodeByteSize;
+
+    //
+    //  Fcb for the file object being closed.
+    //
+
+    PFCB Fcb;
+
+    //
+    //  List entry to attach to delayed close queue.
+    //
+
+    LIST_ENTRY DelayedCloseLinks;
+
+    //
+    //  User reference count for the file object being closed.
+    //
+
+    ULONG UserReference;
+
+    //
+    //  Real device object.  This represents the physical device closest to the media.
+    //
+
+    PDEVICE_OBJECT RealDevice;
+
+} IRP_CONTEXT_LITE;
+typedef IRP_CONTEXT_LITE *PIRP_CONTEXT_LITE;
+
+\f
+//
+//  Context structure for asynchronous I/O calls.  Most of these fields
+//  are actually only required for the ReadMultiple routines, but
+//  the caller must allocate one as a local variable anyway before knowing
+//  whether there are multiple requests are not.  Therefore, a single
+//  structure is used for simplicity.
+//
+
+typedef struct _CD_IO_CONTEXT {
+
+    //
+    //  These two fields are used for multiple run Io
+    //
+
+    LONG IrpCount;
+    PIRP MasterIrp;
+    NTSTATUS Status;
+    BOOLEAN AllocatedContext;
+
+    union {
+
+        //
+        //  This element handles the asynchronous non-cached Io
+        //
+
+        struct {
+
+            PERESOURCE Resource;
+            ERESOURCE_THREAD ResourceThreadId;
+            ULONG RequestedByteCount;
+        };
+
+        //
+        //  and this element handles the synchronous non-cached Io.
+        //
+
+        KEVENT SyncEvent;
+    };
+
+} CD_IO_CONTEXT;
+typedef CD_IO_CONTEXT *PCD_IO_CONTEXT;
+
+\f
+//
+//  Following structure is used to track the top level request.  Each Cdfs
+//  Fsd and Fsp entry point will examine the top level irp location in the
+//  thread local storage to determine if this request is top level and/or
+//  top level Cdfs.  The top level Cdfs request will remember the previous
+//  value and update that location with a stack location.  This location
+//  can be accessed by recursive Cdfs entry points.
+//
+
+typedef struct _THREAD_CONTEXT {
+
+    //
+    //  CDFS signature.  Used to confirm structure on stack is valid.
+    //
+
+    ULONG Cdfs;
+
+    //
+    //  Previous value in top-level thread location.  We restore this
+    //  when done.
+    //
+
+    PIRP SavedTopLevelIrp;
+
+    //
+    //  Top level Cdfs IrpContext.  Initial Cdfs entry point on stack
+    //  will store the IrpContext for the request in this stack location.
+    //
+
+    PIRP_CONTEXT TopLevelIrpContext;
+
+} THREAD_CONTEXT;
+typedef THREAD_CONTEXT *PTHREAD_CONTEXT;
+
+\f
+//
+//  The following structure is used for enumerating the entries in the
+//  path table.  We will always map this two sectors at a time so we don't
+//  have to worry about entries which span sectors.  We move through
+//  one sector at a time though.  We will unpin and remap after
+//  crossing a sector boundary.
+//
+//  The only special case is where we span a cache view.  In that case
+//  we will allocate a buffer and read both pieces into it.
+//
+//  This strategy takes advantage of the CC enhancement which allows
+//  overlapping ranges.
+//
+
+typedef struct _PATH_ENUM_CONTEXT {
+
+    //
+    //  Pointer to the current sector and the offset of this sector to
+    //  the beginning of the path table.  The Data pointer may be
+    //  a pool block in the case where we cross a cache view
+    //  boundary.  Also the length of the data for this block.
+    //
+
+    PVOID Data;
+    ULONG BaseOffset;
+    ULONG DataLength;
+
+    //
+    //  Bcb for the sector.  (We may actually have pinned two sectors)
+    //  This will be NULL for the case where we needed to allocate a
+    //  buffer in the case where we span a cache view.
+    //
+
+    PBCB Bcb;
+
+    //
+    //  Offset to current entry within the current data block.
+    //
+
+    ULONG DataOffset;
+
+    //
+    //  Did we allocate the buffer for the entry.
+    //
+
+    BOOLEAN AllocatedData;
+
+    //
+    //  End of Path Table.  This tells us whether the current data
+    //  block includes the end of the path table.  This is the
+    //  only block where we need to do a careful check about whether
+    //  the path table entry fits into the buffer.
+    //
+    //  Also once we have reached the end of the path table we don't
+    //  need to remap the data as we move into the final sector.
+    //  We always look at the last two sectors together.
+    //
+
+    BOOLEAN LastDataBlock;
+
+} PATH_ENUM_CONTEXT;
+typedef PATH_ENUM_CONTEXT *PPATH_ENUM_CONTEXT;
+
+#define VACB_MAPPING_MASK               (VACB_MAPPING_GRANULARITY - 1)
+#define LAST_VACB_SECTOR_OFFSET         (VACB_MAPPING_GRANULARITY - SECTOR_SIZE)
+
+\f
+//
+//  Path Entry.  This is our representation of the on disk data.
+//
+
+typedef struct _PATH_ENTRY {
+
+    //
+    //  Directory number and offset.  This is the ordinal and the offset from
+    //  the beginning of the path table stream for this entry.
+    //
+    //
+
+    ULONG Ordinal;
+    ULONG PathTableOffset;
+
+    //
+    //  Logical block Offset on the disk for this entry.  We already bias
+    //  this by any Xar blocks.
+    //
+
+    ULONG DiskOffset;
+
+    //
+    //  Length of on-disk path table entry.
+    //
+
+    ULONG PathEntryLength;
+
+    //
+    //  Parent number.
+    //
+
+    ULONG ParentOrdinal;
+
+    //
+    //  DirName length and Id.  Typically the pointer here points to the raw on-disk
+    //  bytes.  We will point to a fixed self entry if this is the root directory.
+    //
+
+    ULONG DirNameLen;
+    PCHAR DirName;
+
+    //
+    //  Following are the flags used to cleanup this structure.
+    //
+
+    ULONG Flags;
+
+    //
+    //  The following is the filename string and version number strings.  We embed a buffer
+    //  large enough to hold two 8.3 names.  One for exact case and one for case insensitive.
+    //
+
+    CD_NAME CdDirName;
+    CD_NAME CdCaseDirName;
+
+    WCHAR NameBuffer[BYTE_COUNT_EMBEDDED_NAME / sizeof( WCHAR ) * 2];
+
+} PATH_ENTRY;
+typedef PATH_ENTRY *PPATH_ENTRY;
+
+#define PATH_ENTRY_FLAG_ALLOC_BUFFER            (0x00000001)
+
+\f
+//
+//  Compound path entry.  This structure combines the on-disk entries
+//  with the in-memory structures.
+//
+
+typedef struct _COMPOUND_PATH_ENTRY {
+
+    PATH_ENUM_CONTEXT PathContext;
+    PATH_ENTRY PathEntry;
+
+} COMPOUND_PATH_ENTRY;
+typedef COMPOUND_PATH_ENTRY *PCOMPOUND_PATH_ENTRY;
+
+\f
+//
+//  The following is used for enumerating through a directory via the
+//  dirents.
+//
+
+typedef struct _DIRENT_ENUM_CONTEXT {
+
+    //
+    //  Pointer the current sector and the offset of this sector within
+    //  the directory file.  Also the data length of this pinned block.
+    //
+
+    PVOID Sector;
+    ULONG BaseOffset;
+    ULONG DataLength;
+
+    //
+    //  Bcb for the sector.
+    //
+
+    PBCB Bcb;
+
+    //
+    //  Offset to the current dirent within this sector.
+    //
+
+    ULONG SectorOffset;
+
+    //
+    //  Length to next dirent.  A zero indicates to move to the next sector.
+    //
+
+    ULONG NextDirentOffset;
+
+} DIRENT_ENUM_CONTEXT;
+typedef DIRENT_ENUM_CONTEXT *PDIRENT_ENUM_CONTEXT;
+
+\f
+//
+//  Following structure is used to smooth out the differences in the HSG, ISO
+//  and Joliett directory entries.
+//
+
+typedef struct _DIRENT {
+
+    //
+    //  Offset in the Directory of this entry.  Note this includes
+    //  any bytes added to the beginning of the directory to pad
+    //  down to a sector boundary.
+    //
+
+    ULONG DirentOffset;
+
+    ULONG DirentLength;
+
+    //
+    //  Starting offset on the disk including any Xar blocks.
+    //
+
+    ULONG StartingOffset;
+
+    //
+    //  DataLength of the data.  If not the last block then this should
+    //  be an integral number of logical blocks.
+    //
+
+    ULONG DataLength;
+
+    //
+    //  The following field is the time stamp out of the directory entry.
+    //  Use a pointer into the dirent for this.
+    //
+
+    PCHAR CdTime;
+
+    //
+    //  The following field is the dirent file flags field.
+    //
+
+    UCHAR DirentFlags;
+
+    //
+    //  Following field is a Cdfs flag field used to clean up this structure.
+    //
+
+    UCHAR Flags;
+
+    //
+    //  The following fields indicate the file unit size and interleave gap
+    //  for interleaved files.  Each of these are in logical blocks.
+    //
+
+    ULONG FileUnitSize;
+    ULONG InterleaveGapSize;
+
+    //
+    //  System use offset.  Zero value indicates no system use area.
+    //
+
+    ULONG SystemUseOffset;
+
+    //
+    //  CDXA attributes and file number for this file.
+    //
+
+    USHORT XAAttributes;
+    UCHAR XAFileNumber;
+
+    //
+    //  Filename length and ID.  We copy the length (in bytes) and keep
+    //  a pointer to the start of the name.
+    //
+
+    ULONG FileNameLen;
+    PCHAR FileName;
+
+    //
+    //  The following are the filenames stored by name and version numbers.
+    //  The fixed buffer here can hold two Unicode 8.3 names.  This allows
+    //  us to upcase the name into a fixed buffer.
+    //
+
+    CD_NAME CdFileName;
+    CD_NAME CdCaseFileName;
+
+    //
+    //  Data stream type.  Indicates if this is audio, XA mode2 form2 or cooked sectors.
+    //
+
+    XA_EXTENT_TYPE ExtentType;
+
+    WCHAR NameBuffer[BYTE_COUNT_EMBEDDED_NAME / sizeof( WCHAR ) * 2];
+
+} DIRENT;
+typedef DIRENT *PDIRENT;
+
+#define DIRENT_FLAG_ALLOC_BUFFER                (0x01)
+#define DIRENT_FLAG_CONSTANT_ENTRY              (0x02)
+
+#define DIRENT_FLAG_NOT_PERSISTENT              (0)
+
+\f
+//
+//  Following structure combines the on-disk information with the normalized
+//  structure.
+//
+
+typedef struct _COMPOUND_DIRENT {
+
+    DIRENT_ENUM_CONTEXT DirContext;
+    DIRENT Dirent;
+
+} COMPOUND_DIRENT;
+typedef COMPOUND_DIRENT *PCOMPOUND_DIRENT;
+
+\f
+//
+//  The following structure is used to enumerate the files in a directory.
+//  It contains three DirContext/Dirent pairs and then self pointers to
+//  know which of these is begin used how.
+//
+
+typedef struct _FILE_ENUM_CONTEXT {
+
+    //
+    //  Pointers to the current compound dirents below.
+    //
+    //      PriorDirent - Initial dirent for the last file encountered.
+    //      InitialDirent - Initial dirent for the current file.
+    //      CurrentDirent - Second or later dirent for the current file.
+    //
+
+    PCOMPOUND_DIRENT PriorDirent;
+    PCOMPOUND_DIRENT InitialDirent;
+    PCOMPOUND_DIRENT CurrentDirent;
+
+    //
+    //  Flags indicating the state of the search.
+    //
+
+    ULONG Flags;
+
+    //
+    //  This is an accumulation of the file sizes of the different extents
+    //  of a single file.
+    //
+
+    LONGLONG FileSize;
+
+    //
+    //  Short name for this file.
+    //
+
+    CD_NAME ShortName;
+    WCHAR ShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof( WCHAR ) ];
+
+    //
+    //  Array of compound dirents.
+    //
+
+    COMPOUND_DIRENT Dirents[3];
+
+} FILE_ENUM_CONTEXT;
+typedef FILE_ENUM_CONTEXT *PFILE_ENUM_CONTEXT;
+
+#define FILE_CONTEXT_MULTIPLE_DIRENTS       (0x00000001)
+
+\f
+//
+//  RIFF header.  Prepended to the data of a file containing XA sectors.
+//  This is a hard-coded structure except that we bias the 'ChunkSize' and
+//  'RawSectors' fields with the file size.  We also copy the attributes flag
+//  from the system use area in the dirent.  We always initialize this
+//  structure by copying the XAFileHeader.
+//
+
+typedef struct _RIFF_HEADER {
+
+    ULONG ChunkId;
+    LONG ChunkSize;
+    ULONG SignatureCDXA;
+    ULONG SignatureFMT;
+    ULONG XAChunkSize;
+    ULONG OwnerId;
+    USHORT Attributes;
+    USHORT SignatureXA;
+    UCHAR FileNumber;
+    UCHAR Reserved[7];
+    ULONG SignatureData;
+    ULONG RawSectors;
+
+} RIFF_HEADER;
+typedef RIFF_HEADER *PRIFF_HEADER;
+
+//
+//  Audio play header for CDDA tracks.
+//
+
+typedef struct _AUDIO_PLAY_HEADER {
+
+    ULONG Chunk;
+    ULONG ChunkSize;
+    ULONG SignatureCDDA;
+    ULONG SignatureFMT;
+    ULONG FMTChunkSize;
+    USHORT FormatTag;
+    USHORT TrackNumber;
+    ULONG DiskID;
+    ULONG StartingSector;
+    ULONG SectorCount;
+    UCHAR TrackAddress[4];
+    UCHAR TrackLength[4];
+
+} AUDIO_PLAY_HEADER;
+typedef AUDIO_PLAY_HEADER *PAUDIO_PLAY_HEADER;
+
+\f
+//
+//  Some macros for supporting the use of a Generic Table
+//  containing all the FCB/DCBs and indexed by their FileId.
+//
+//  For directories:
+//
+//      The HighPart contains the path table offset of this directory in the
+//      path table.
+//
+//      The LowPart contains zero except for the upper bit which is
+//      set to indicate that this is a directory.
+//
+//  For files:
+//
+//      The HighPart contains the path table offset of the parent directory
+//      in the path table.
+//
+//      The LowPart contains the byte offset of the dirent in the parent
+//      directory file.
+//
+//  A directory is always entered into the Fcb Table as if it's
+//  dirent offset was zero.  This enables any child to look in the FcbTable
+//  for it's parent by searching with the same HighPart but with zero
+//  as the value for LowPart.
+//
+//  The Id field is a LARGE_INTEGER where the High and Low parts can be
+//  accessed separately.
+//
+//  The following macros are used to access the Fid fields.
+//
+//      CdQueryFidDirentOffset      - Accesses the Dirent offset field
+//      CdQueryFidPathTableNumber   - Accesses the PathTable offset field
+//      CdSetFidDirentOffset        - Sets the Dirent offset field
+//      CdSetFidPathTableNumber     - Sets the PathTable ordinal field
+//      CdFidIsDirectory            - Queries if directory bit is set
+//      CdFidSetDirectory           - Sets directory bit
+//
+
+#define FID_DIR_MASK  0x80000000            // high order bit means directory.
+
+#define CdQueryFidDirentOffset(I)           ((I).LowPart & ~FID_DIR_MASK)
+#define CdQueryFidPathTableOffset(I)        ((I).HighPart)
+#define CdSetFidDirentOffset(I,D)           ((I).LowPart = D)
+#define CdSetFidPathTableOffset(I,P)        ((I).HighPart = P)
+#define CdFidIsDirectory(I)                 FlagOn( (I).LowPart, FID_DIR_MASK )
+#define CdFidSetDirectory(I)                SetFlag( (I).LowPart, FID_DIR_MASK )
+
+#define CdSetFidFromParentAndDirent(I,F,D)  {                                           \
+        CdSetFidPathTableOffset( (I), CdQueryFidPathTableOffset( (F)->FileId ));        \
+        CdSetFidDirentOffset( (I), (D)->DirentOffset );                                 \
+        if (FlagOn( (D)->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {                       \
+            CdFidSetDirectory((I));                                                     \
+        }                                                                               \
+}
+
+#endif // _CDSTRUC_
+
diff --git a/reactos/drivers/filesystems/cdfs_new/cleanup.c b/reactos/drivers/filesystems/cdfs_new/cleanup.c
new file mode 100755 (executable)
index 0000000..70faad7
--- /dev/null
@@ -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;
+}
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/close.c b/reactos/drivers/filesystems/cdfs_new/close.c
new file mode 100755 (executable)
index 0000000..913c0fd
--- /dev/null
@@ -0,0 +1,1028 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    Close.c
+
+Abstract:
+
+    This module implements the File Close routine for Cdfs called by the
+    Fsd/Fsp dispatch routines.
+
+    The close operation interacts with both the async and delayed close queues
+    in the CdData structure.  Since close may be called recursively we may
+    violate the locking order in acquiring the Vcb or Fcb.  In this case
+    we may move the request to the async close queue.  If this is the last
+    reference on the Fcb and there is a chance the user may reopen this
+    file again soon we would like to defer the close.  In this case we
+    may move the request to the async close queue.
+
+    Once we are past the decode file operation there is no need for the
+    file object.  If we are moving the request to either of the work
+    queues then we remember all of the information from the file object and
+    complete the request with STATUS_SUCCESS.  The Io system can then
+    reuse the file object and we can complete the request when convenient.
+
+    The async close queue consists of requests which we would like to
+    complete as soon as possible.  They are queued using the original
+    IrpContext where some of the fields have been overwritten with
+    information from the file object.  We will extract this information,
+    cleanup the IrpContext and then call the close worker routine.
+
+    The delayed close queue consists of requests which we would like to
+    defer the close for.  We keep size of this list within a range
+    determined by the size of the system.  We let it grow to some maximum
+    value and then shrink to some minimum value.  We allocate a small
+    structure which contains the key information from the file object
+    and use this information along with an IrpContext on the stack
+    to complete the request.
+
+
+--*/
+
+#include "CdProcs.h"
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (CDFS_BUG_CHECK_CLOSE)
+
+//
+//  Local support routines
+//
+
+BOOLEAN
+CdCommonClosePrivate (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PFCB Fcb,
+    IN ULONG UserReference,
+    IN BOOLEAN FromFsd
+    );
+
+VOID
+CdQueueClose (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN ULONG UserReference,
+    IN BOOLEAN DelayedClose
+    );
+
+PIRP_CONTEXT
+CdRemoveClose (
+    IN PVCB Vcb OPTIONAL
+    );
+
+VOID
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdCloseWorker (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PVOID Context
+    );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdCommonClose)
+#pragma alloc_text(PAGE, CdCommonClosePrivate)
+#pragma alloc_text(PAGE, CdQueueClose)
+#pragma alloc_text(PAGE, CdRemoveClose)
+#pragma alloc_text(PAGE, CdCloseWorker)
+#endif
+
+
+VOID
+CdFspClose (
+    IN PVCB Vcb OPTIONAL
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to process the close queues in the CdData.  If the
+    Vcb is passed then we want to remove all of the closes for this Vcb.
+    Otherwise we will do as many of the delayed closes as we need to do.
+
+Arguments:
+
+    Vcb - If specified then we are looking for all of the closes for the
+        given Vcb.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PIRP_CONTEXT IrpContext;
+    IRP_CONTEXT StackIrpContext;
+
+    THREAD_CONTEXT ThreadContext;
+
+    PFCB Fcb;
+    ULONG UserReference;
+
+    ULONG VcbHoldCount = 0;
+    PVCB CurrentVcb = NULL;
+
+    BOOLEAN PotentialVcbTeardown = FALSE;
+
+    PAGED_CODE();
+
+    FsRtlEnterFileSystem();
+
+    //
+    //  Continue processing until there are no more closes to process.
+    //
+    /* ReactOS Change: "GCC suggest parentheses around assignment used as truth value" */
+    while ((IrpContext = CdRemoveClose( Vcb ))) {
+
+        //
+        //  If we don't have an IrpContext then use the one on the stack.
+        //  Initialize it for this request.
+        //
+
+        if (SafeNodeType( IrpContext ) != CDFS_NTC_IRP_CONTEXT ) {
+
+            //
+            //  Update the local values from the IrpContextLite.
+            //
+
+            Fcb = ((PIRP_CONTEXT_LITE) IrpContext)->Fcb;
+            UserReference = ((PIRP_CONTEXT_LITE) IrpContext)->UserReference;
+
+            //
+            //  Update the stack irp context with the values from the
+            //  IrpContextLite.
+            //
+
+            CdInitializeStackIrpContext( &StackIrpContext,
+                                         (PIRP_CONTEXT_LITE) IrpContext );
+
+            //
+            //  Free the IrpContextLite.
+            //
+
+            CdFreeIrpContextLite( IrpContext ); /* ReactOS Change: GCC "error: invalid lvalue in unary '&'" */
+
+            //
+            //  Remember we have the IrpContext from the stack.
+            //
+
+            IrpContext = &StackIrpContext;
+
+        //
+        //  Otherwise cleanup the existing IrpContext.
+        //
+
+        } else {
+
+            //
+            //  Remember the Fcb and user reference count.
+            //
+
+            Fcb = (PFCB) IrpContext->Irp;
+            IrpContext->Irp = NULL;
+
+            UserReference = (ULONG) IrpContext->ExceptionStatus;
+            IrpContext->ExceptionStatus = STATUS_SUCCESS;
+        }
+
+        //
+        //  We have an IrpContext.  Now we need to set the top level thread
+        //  context.
+        //
+
+        SetFlag( IrpContext->Flags, IRP_CONTEXT_FSP_FLAGS );
+
+        //
+        //  If we were given a Vcb then there is a request on top of this.
+        //
+
+        if (ARGUMENT_PRESENT( Vcb )) {
+
+            ClearFlag( IrpContext->Flags,
+                       IRP_CONTEXT_FLAG_TOP_LEVEL | IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS );
+        }
+
+        CdSetThreadContext( IrpContext, &ThreadContext );
+
+        //
+        //  If we have hit the maximum number of requests to process without
+        //  releasing the Vcb then release the Vcb now.  If we are holding
+        //  a different Vcb to this one then release the previous Vcb.
+        //
+        //  In either case acquire the current Vcb.
+        //
+        //  We use the MinDelayedCloseCount from the CdData since it is
+        //  a convenient value based on the system size.  Only thing we are trying
+        //  to do here is prevent this routine starving other threads which
+        //  may need this Vcb exclusively.
+        //
+        //  Note that the check for potential teardown below is unsafe.  We'll 
+        //  repeat later within the cddata lock.
+        //
+
+        PotentialVcbTeardown = !ARGUMENT_PRESENT( Vcb ) &&
+                               (Fcb->Vcb->VcbCondition != VcbMounted) &&
+                               (Fcb->Vcb->VcbCondition != VcbMountInProgress) &&
+                               (Fcb->Vcb->VcbCleanup == 0);
+
+        if (PotentialVcbTeardown ||
+            (VcbHoldCount > CdData.MinDelayedCloseCount) ||
+            (Fcb->Vcb != CurrentVcb)) {
+
+            if (CurrentVcb != NULL) {
+
+                CdReleaseVcb( IrpContext, CurrentVcb );
+            }
+
+            if (PotentialVcbTeardown) {
+
+                CdAcquireCdData( IrpContext );
+
+                //
+                //  Repeat the checks with global lock held.  The volume could have
+                //  been remounted while we didn't hold the lock.
+                //
+
+                PotentialVcbTeardown = !ARGUMENT_PRESENT( Vcb ) &&
+                                       (Fcb->Vcb->VcbCondition != VcbMounted) &&
+                                       (Fcb->Vcb->VcbCondition != VcbMountInProgress) &&
+                                       (Fcb->Vcb->VcbCleanup == 0);
+                                
+                if (!PotentialVcbTeardown)  {
+
+                    CdReleaseCdData( IrpContext);
+                }
+            }
+
+            CurrentVcb = Fcb->Vcb;
+            CdAcquireVcbShared( IrpContext, CurrentVcb, FALSE );
+
+            VcbHoldCount = 0;
+
+        } else {
+
+            VcbHoldCount += 1;
+        }
+
+        //
+        //  Call our worker routine to perform the close operation.
+        //
+
+        CdCommonClosePrivate( IrpContext, CurrentVcb, Fcb, UserReference, FALSE );
+
+        //
+        //  If the reference count on this Vcb is below our residual reference
+        //  then check if we should dismount the volume.
+        //
+
+        if (PotentialVcbTeardown) {
+
+            CdReleaseVcb( IrpContext, CurrentVcb );
+            CdCheckForDismount( IrpContext, CurrentVcb, FALSE );
+
+            CurrentVcb = NULL;
+
+            CdReleaseCdData( IrpContext );
+            PotentialVcbTeardown = FALSE;
+        }
+
+        //
+        //  Complete the current request to cleanup the IrpContext.
+        //
+
+        CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
+    }
+
+    //
+    //  Release any Vcb we may still hold.
+    //
+
+    if (CurrentVcb != NULL) {
+
+        CdReleaseVcb( IrpContext, CurrentVcb );
+
+    }
+
+    FsRtlExitFileSystem();
+}
+
+
+NTSTATUS
+CdCommonClose (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is the Fsd entry for the close operation.  We decode the file
+    object to find the CDFS structures and type of open.  We call our internal
+    worker routine to perform the actual work.  If the work wasn't completed
+    then we post to one of our worker queues.  The Ccb isn't needed after this
+    point so we delete the Ccb and return STATUS_SUCCESS to our caller in all
+    cases.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+Return Value:
+
+    STATUS_SUCCESS
+
+--*/
+
+{
+    TYPE_OF_OPEN TypeOfOpen;
+
+    PVCB Vcb;
+    PFCB Fcb;
+    PCCB Ccb;
+    ULONG UserReference = 0;
+
+    BOOLEAN PotentialVcbTeardown = FALSE;
+    BOOLEAN ForceDismount = FALSE;
+
+    PAGED_CODE();
+
+    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;
+    }
+
+    //
+    //  Decode the file object to get the type of open and Fcb/Ccb.
+    //
+
+    TypeOfOpen = CdDecodeFileObject( IrpContext,
+                                     IoGetCurrentIrpStackLocation( Irp )->FileObject,
+                                     &Fcb,
+                                     &Ccb );
+
+    //
+    //  No work to do for unopened file objects.
+    //
+
+    if (TypeOfOpen == UnopenedFileObject) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
+
+        return STATUS_SUCCESS;
+    }
+
+    Vcb = Fcb->Vcb;
+
+    //
+    //  Clean up any CCB associated with this open.
+    //
+    
+    if (Ccb != NULL) {
+
+        UserReference = 1;
+
+        //
+        //  Was a FSCTL_DISMOUNT issued on this handle?  If so,  we need to
+        //  force a dismount of the volume now.
+        //
+        
+        ForceDismount = BooleanFlagOn( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE);
+
+        //
+        //  We can always deallocate the Ccb if present.
+        //
+
+        CdDeleteCcb( IrpContext, Ccb );
+    }
+
+    //
+    //  If this is the last reference to a user file or directory on a 
+    //  currently mounted volume, then post it to the delayed close queue.  Note
+    //  that the VcbCondition check is unsafe,  but it doesn't really matter -
+    //  we just might delay the volume teardown a little by posting this close.
+    //
+
+    if ((Vcb->VcbCondition == VcbMounted) &&
+        (Fcb->FcbReference == 1) &&
+        ((TypeOfOpen == UserFileOpen) ||
+         (TypeOfOpen == UserDirectoryOpen))) {
+
+        CdQueueClose( IrpContext, Fcb, UserReference, TRUE );
+        IrpContext = NULL;
+
+    //
+    //  Otherwise try to process this close.  Post to the async close queue
+    //  if we can't acquire all of the resources.
+    //
+
+    } else {
+
+        //
+        //  If we may be dismounting this volume then acquire the CdData
+        //  resource.
+        //
+        //  Since we now must make volumes go away as soon as reasonable after
+        //  the last user handles closes, key off of the cleanup count.  It is
+        //  OK to do this more than neccesary.  Since this Fcb could be holding
+        //  a number of other Fcbs (and thus their references), a simple check
+        //  on reference count is not appropriate.
+        //
+        //  Do an unsafe check first to avoid taking the (global) cddata lock in the 
+        //  common case.
+        //
+
+        if (((Vcb->VcbCleanup == 0) || ForceDismount) &&
+            (Vcb->VcbCondition != VcbMounted))  {
+
+            //
+            //  Possible.  Acquire CdData to synchronise with the remount path,  and
+            //  then repeat the tests.
+            //
+            //  Note that we must send the notification outside of any locks,  since 
+            //  the worker that processes the notify could also be calling into our 
+            //  pnp path which wants both CdData and VcbResource.  For a force dismount
+            //  the volume will be marked invalid (no going back),  so we will definitely
+            //  go ahead and dismount below.
+            //
+
+            if (ForceDismount)  {
+            
+                //
+                //  Send notification.
+                //
+                
+                FsRtlNotifyVolumeEvent( IoGetCurrentIrpStackLocation( Irp )->FileObject, 
+                                        FSRTL_VOLUME_DISMOUNT );
+            }
+            
+            CdAcquireCdData( IrpContext );
+
+            if (((Vcb->VcbCleanup == 0) || ForceDismount) &&
+                (Vcb->VcbCondition != VcbMounted) &&
+                (Vcb->VcbCondition != VcbMountInProgress) &&
+                FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS ))  {
+
+                PotentialVcbTeardown = TRUE;
+            }
+            else {
+
+                //
+                //  We can't dismount this volume now,  there are other references or
+                //  it's just been remounted.
+                //
+
+                CdReleaseCdData( IrpContext);
+            }
+        }
+
+        if (ForceDismount)  {
+        
+            //
+            //  Physically disconnect this Vcb from the device so a new mount can
+            //  occur.  Vcb deletion cannot happen at this time since there is
+            //  a handle on it associated with this very request,  but we'll call
+            //  check for dismount again later anyway.
+            //
+
+            CdCheckForDismount( IrpContext, Vcb, TRUE );
+        }
+        
+        //
+        //  Call the worker routine to perform the actual work.  This routine
+        //  should never raise except for a fatal error.
+        //
+
+        if (!CdCommonClosePrivate( IrpContext, Vcb, Fcb, UserReference, TRUE )) {
+
+            //
+            //  If we didn't complete the request then post the request as needed.
+            //
+
+            CdQueueClose( IrpContext, Fcb, UserReference, FALSE );
+            IrpContext = NULL;
+
+        //
+        //  Check whether we should be dismounting the volume and then complete
+        //  the request.
+        //
+
+        } else if (PotentialVcbTeardown) {
+
+            CdCheckForDismount( IrpContext, Vcb, FALSE );
+        }
+    }
+
+    //
+    //  Always complete this request with STATUS_SUCCESS.
+    //
+
+    CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
+
+    if (PotentialVcbTeardown) {
+
+        CdReleaseCdData( IrpContext );
+    }
+
+    //
+    //  Always return STATUS_SUCCESS for closes.
+    //
+
+    return STATUS_SUCCESS;
+}
+
+\f
+//
+//  Local support routine
+//
+
+BOOLEAN
+CdCommonClosePrivate (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PFCB Fcb,
+    IN ULONG UserReference,
+    IN BOOLEAN FromFsd
+    )
+
+/*++
+
+Routine Description:
+
+    This is the worker routine for the close operation.  We can be called in
+    an Fsd thread or from a worker Fsp thread.  If called from the Fsd thread
+    then we acquire the resources without waiting.  Otherwise we know it is
+    safe to wait.
+
+    We check to see whether we should post this request to the delayed close
+    queue.  If we are to process the close here then we acquire the Vcb and
+    Fcb.  We will adjust the counts and call our teardown routine to see
+    if any of the structures should go away.
+
+Arguments:
+
+    Vcb - Vcb for this volume.
+
+    Fcb - Fcb for this request.
+
+    UserReference - Number of user references for this file object.  This is
+        zero for an internal stream.
+
+    FromFsd - This request was called from an Fsd thread.  Indicates whether
+        we should wait to acquire resources.
+
+    DelayedClose - Address to store whether we should try to put this on
+        the delayed close queue.  Ignored if this routine can process this
+        close.
+
+Return Value:
+
+    BOOLEAN - TRUE if this thread processed the close, FALSE otherwise.
+
+--*/
+
+{
+    BOOLEAN RemovedFcb;
+
+    PAGED_CODE();
+
+    ASSERT_IRP_CONTEXT( IrpContext );
+    ASSERT_FCB( Fcb );
+
+    //
+    //  Try to acquire the Vcb and Fcb.  If we can't acquire them then return
+    //  and let our caller know he should post the request to the async
+    //  queue.
+    //
+
+    if (CdAcquireVcbShared( IrpContext, Vcb, FromFsd )) {
+
+        if (!CdAcquireFcbExclusive( IrpContext, Fcb, FromFsd )) {
+
+            //
+            //  We couldn't get the Fcb.  Release the Vcb and let our caller
+            //  know to post this request.
+            //
+
+            CdReleaseVcb( IrpContext, Vcb );
+            return FALSE;
+        }
+
+    //
+    //  We didn't get the Vcb.  Let our caller know to post this request.
+    //
+
+    } else {
+
+        return FALSE;
+    }
+
+    //
+    //  Lock the Vcb and decrement the reference counts.
+    //
+
+    CdLockVcb( IrpContext, Vcb );
+    CdDecrementReferenceCounts( IrpContext, Fcb, 1, UserReference );
+    CdUnlockVcb( IrpContext, Vcb );
+
+    //
+    //  Call our teardown routine to see if this object can go away.
+    //  If we don't remove the Fcb then release it.
+    //
+
+    CdTeardownStructures( IrpContext, Fcb, &RemovedFcb );
+
+    if (!RemovedFcb) {
+
+        CdReleaseFcb( IrpContext, Fcb );
+    }
+
+    //
+    //  Release the Vcb and return to our caller.  Let him know we completed
+    //  this request.
+    //
+
+    CdReleaseVcb( IrpContext, Vcb );
+
+    return TRUE;
+}
+
+VOID
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdCloseWorker (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PVOID Context
+    )
+/*++
+
+Routine Description:
+
+    Worker routine to call CsFspClose.
+
+Arguments:
+
+    DeviceObject - Filesystem registration device object
+
+    Context - Callers context
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    CdFspClose (NULL);
+}
+
+\f
+VOID
+CdQueueClose (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN ULONG UserReference,
+    IN BOOLEAN DelayedClose
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to queue a request to either the async or delayed
+    close queue.  For the delayed queue we need to allocate a smaller
+    structure to contain the information about the file object.  We do
+    that so we don't put the larger IrpContext structures into this long
+    lived queue.  If we can allocate this structure then we put this
+    on the async queue instead.
+
+Arguments:
+
+    Fcb - Fcb for this file object.
+
+    UserReference - Number of user references for this file object.  This is
+        zero for an internal stream.
+
+    DelayedClose - Indicates whether this should go on the async or delayed
+        close queue.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PIRP_CONTEXT_LITE IrpContextLite = NULL;
+    BOOLEAN StartWorker = FALSE;
+
+    PAGED_CODE();
+
+    ASSERT_IRP_CONTEXT( IrpContext );
+    ASSERT_FCB( Fcb );
+
+    //
+    //  Start with the delayed queue request.  We can move this to the async
+    //  queue if there is an allocation failure.
+    //
+
+    if (DelayedClose) {
+
+        //
+        //  Try to allocate non-paged pool for the IRP_CONTEXT_LITE.
+        //
+
+        IrpContextLite = CdCreateIrpContextLite( IrpContext );
+    }
+
+    //
+    //  We want to clear the top level context in this thread if
+    //  necessary.  Call our cleanup routine to do the work.
+    //
+
+    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
+    CdCleanupIrpContext( IrpContext, TRUE );
+
+    //
+    //  Synchronize with the CdData lock.
+    //
+
+    CdLockCdData();
+
+    //
+    //  If we have an IrpContext then put the request on the delayed close queue.
+    //
+
+    if (IrpContextLite != NULL) {
+
+        //
+        //  Initialize the IrpContextLite.
+        //
+
+        IrpContextLite->NodeTypeCode = CDFS_NTC_IRP_CONTEXT_LITE;
+        IrpContextLite->NodeByteSize = sizeof( IRP_CONTEXT_LITE );
+        IrpContextLite->Fcb = Fcb;
+        IrpContextLite->UserReference = UserReference;
+        IrpContextLite->RealDevice = IrpContext->RealDevice;
+
+        //
+        //  Add this to the delayed close list and increment
+        //  the count.
+        //
+
+        InsertTailList( &CdData.DelayedCloseQueue,
+                        &IrpContextLite->DelayedCloseLinks );
+
+        CdData.DelayedCloseCount += 1;
+
+        //
+        //  If we are above our threshold then start the delayed
+        //  close operation.
+        //
+
+        if (CdData.DelayedCloseCount > CdData.MaxDelayedCloseCount) {
+
+            CdData.ReduceDelayedClose = TRUE;
+
+            if (!CdData.FspCloseActive) {
+
+                CdData.FspCloseActive = TRUE;
+                StartWorker = TRUE;
+            }
+        }
+
+        //
+        //  Unlock the CdData.
+        //
+
+        CdUnlockCdData();
+
+        //
+        //  Cleanup the IrpContext.
+        //
+
+        CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
+
+    //
+    //  Otherwise drop into the async case below.
+    //
+
+    } else {
+
+        //
+        //  Store the information about the file object into the IrpContext.
+        //
+
+        IrpContext->Irp = (PIRP) Fcb;
+        IrpContext->ExceptionStatus = (NTSTATUS) UserReference;
+
+        //
+        //  Add this to the async close list and increment the count.
+        //
+
+        InsertTailList( &CdData.AsyncCloseQueue,
+                        &IrpContext->WorkQueueItem.List );
+
+        CdData.AsyncCloseCount += 1;
+
+        //
+        //  Remember to start the Fsp close thread if not currently started.
+        //
+
+        if (!CdData.FspCloseActive) {
+
+            CdData.FspCloseActive = TRUE;
+
+            StartWorker = TRUE;
+        }
+
+        //
+        //  Unlock the CdData.
+        //
+
+        CdUnlockCdData();
+    }
+
+    //
+    //  Start the FspClose thread if we need to.
+    //
+
+    if (StartWorker) {
+
+        IoQueueWorkItem( CdData.CloseItem, CdCloseWorker, CriticalWorkQueue, NULL );
+    }
+
+    //
+    //  Return to our caller.
+    //
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+PIRP_CONTEXT
+CdRemoveClose (
+    IN PVCB Vcb OPTIONAL
+    )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+    This routine is called to scan the async and delayed close queues looking
+    for a suitable entry.  If the Vcb is specified then we scan both queues
+    looking for an entry with the same Vcb.  Otherwise we will look in the
+    async queue first for any close item.  If none found there then we look
+    in the delayed close queue provided that we have triggered the delayed
+    close operation.
+
+Return Value:
+
+    PIRP_CONTEXT - NULL if no work item found.  Otherwise it is the pointer to
+        either the IrpContext or IrpContextLite for this request.
+
+--*/
+
+{
+    PIRP_CONTEXT IrpContext = NULL;
+    PIRP_CONTEXT NextIrpContext;
+    PIRP_CONTEXT_LITE NextIrpContextLite;
+
+    PLIST_ENTRY Entry;
+
+    PAGED_CODE();
+
+    ASSERT_OPTIONAL_VCB( Vcb );
+
+    //
+    //  Lock the CdData to perform the scan.
+    //
+
+    CdLockCdData();
+
+    //
+    //  First check the list of async closes.
+    //
+
+    Entry = CdData.AsyncCloseQueue.Flink;
+
+    while (Entry != &CdData.AsyncCloseQueue) {
+
+        //
+        //  Extract the IrpContext.
+        //
+
+        NextIrpContext = CONTAINING_RECORD( Entry,
+                                            IRP_CONTEXT,
+                                            WorkQueueItem.List );
+
+        //
+        //  If no Vcb was specified or this Vcb is for our volume
+        //  then perform the close.
+        //
+
+        if (!ARGUMENT_PRESENT( Vcb ) || (NextIrpContext->Vcb == Vcb)) {
+
+            RemoveEntryList( Entry );
+            CdData.AsyncCloseCount -= 1;
+
+            IrpContext = NextIrpContext;
+            break;
+        }
+
+        //
+        //  Move to the next entry.
+        //
+
+        Entry = Entry->Flink;
+    }
+
+    //
+    //  If we didn't find anything look through the delayed close
+    //  queue.
+    //
+    //  We will only check the delayed close queue if we were given
+    //  a Vcb or the delayed close operation is active.
+    //
+
+    if ((IrpContext == NULL) &&
+        (ARGUMENT_PRESENT( Vcb ) ||
+         (CdData.ReduceDelayedClose &&
+          (CdData.DelayedCloseCount > CdData.MinDelayedCloseCount)))) {
+
+        Entry = CdData.DelayedCloseQueue.Flink;
+
+        while (Entry != &CdData.DelayedCloseQueue) {
+
+            //
+            //  Extract the IrpContext.
+            //
+
+            NextIrpContextLite = CONTAINING_RECORD( Entry,
+                                                    IRP_CONTEXT_LITE,
+                                                    DelayedCloseLinks );
+
+            //
+            //  If no Vcb was specified or this Vcb is for our volume
+            //  then perform the close.
+            //
+
+            if (!ARGUMENT_PRESENT( Vcb ) || (NextIrpContextLite->Fcb->Vcb == Vcb)) {
+
+                RemoveEntryList( Entry );
+                CdData.DelayedCloseCount -= 1;
+
+                IrpContext = (PIRP_CONTEXT) NextIrpContextLite;
+                break;
+            }
+
+            //
+            //  Move to the next entry.
+            //
+
+            Entry = Entry->Flink;
+        }
+    }
+
+    //
+    //  If the Vcb wasn't specified and we couldn't find an entry
+    //  then turn off the Fsp thread.
+    //
+
+    if (!ARGUMENT_PRESENT( Vcb ) && (IrpContext == NULL)) {
+
+        CdData.FspCloseActive = FALSE;
+        CdData.ReduceDelayedClose = FALSE;
+    }
+
+    //
+    //  Unlock the CdData.
+    //
+
+    CdUnlockCdData();
+
+    return IrpContext;
+}
+
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/create.c b/reactos/drivers/filesystems/cdfs_new/create.c
new file mode 100755 (executable)
index 0000000..1458ea2
--- /dev/null
@@ -0,0 +1,2916 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    Create.c
+
+Abstract:
+
+    This module implements the File Create routine for Cdfs called by the
+    Fsd/Fsp dispatch routines.
+
+
+--*/
+
+#include "CdProcs.h"
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (CDFS_BUG_CHECK_CREATE)
+
+//
+//  Local support routines
+//
+
+NTSTATUS
+CdNormalizeFileNames (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN BOOLEAN OpenByFileId,
+    IN BOOLEAN IgnoreCase,
+    IN TYPE_OF_OPEN RelatedTypeOfOpen,
+    IN PCCB RelatedCcb OPTIONAL,
+    IN PUNICODE_STRING RelatedFileName OPTIONAL,
+    IN OUT PUNICODE_STRING FileName,
+    IN OUT PCD_NAME RemainingName
+    );
+
+NTSTATUS
+CdOpenByFileId (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PVCB Vcb,
+    IN OUT PFCB *CurrentFcb
+    );
+
+NTSTATUS
+CdOpenExistingFcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN OUT PFCB *CurrentFcb,
+    IN TYPE_OF_OPEN TypeOfOpen,
+    IN BOOLEAN IgnoreCase,
+    IN PCCB RelatedCcb OPTIONAL
+    );
+
+NTSTATUS
+CdOpenDirectoryFromPathEntry (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PVCB Vcb,
+    IN OUT PFCB *CurrentFcb,
+    IN PCD_NAME DirName,
+    IN BOOLEAN IgnoreCase,
+    IN BOOLEAN ShortNameMatch,
+    IN PPATH_ENTRY PathEntry,
+    IN BOOLEAN PerformUserOpen,
+    IN PCCB RelatedCcb OPTIONAL
+    );
+
+NTSTATUS
+CdOpenFileFromFileContext (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PVCB Vcb,
+    IN OUT PFCB *CurrentFcb,
+    IN PCD_NAME FileName,
+    IN BOOLEAN IgnoreCase,
+    IN BOOLEAN ShortNameMatch,
+    IN PFILE_ENUM_CONTEXT FileContext,
+    IN PCCB RelatedCcb OPTIONAL
+    );
+
+NTSTATUS
+CdCompleteFcbOpen (
+    IN PIRP_CONTEXT IrpContext,
+    PIO_STACK_LOCATION IrpSp,
+    IN PVCB Vcb,
+    IN OUT PFCB *CurrentFcb,
+    IN TYPE_OF_OPEN TypeOfOpen,
+    IN ULONG UserCcbFlags,
+    IN ACCESS_MASK DesiredAccess
+    );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdCommonCreate)
+#pragma alloc_text(PAGE, CdCompleteFcbOpen)
+#pragma alloc_text(PAGE, CdNormalizeFileNames)
+#pragma alloc_text(PAGE, CdOpenByFileId)
+#pragma alloc_text(PAGE, CdOpenDirectoryFromPathEntry)
+#pragma alloc_text(PAGE, CdOpenExistingFcb)
+#pragma alloc_text(PAGE, CdOpenFileFromFileContext)
+#endif
+
+\f
+NTSTATUS
+CdCommonCreate (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This is the common routine for opening a file called by both the
+    Fsp and Fsd threads.
+
+    The file can be opened either by name or by file Id either with or without
+    a relative name.  The file name field in the file object passed to this routine
+    contains either a unicode string or a 64 bit value which is the file Id.
+    If this is not a Joliet disk then we will convert the unicode name to
+    an Oem string in this routine.  If there is a related file object with
+    a name then we will already have converted that name to Oem.
+
+    We will store the full name for the file in the file object on a successful
+    open.  We will allocate a larger buffer if necessary and combine the
+    related and file object names.  The only exception is the relative open
+    when the related file object is for an OpenByFileId file.  If we need to
+    allocate a buffer for a case insensitive name then we allocate it at
+    the tail of the buffer we will store into the file object.  The upcased
+    portion will begin immediately after the name defined by the FileName
+    in the file object.
+
+    Once we have the full name in the file object we don't want to split the
+    name in the event of a retry.  We use a flag in the IrpContext to indicate
+    that the name has been split.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+Return Value:
+
+    NTSTATUS - This is the status from this open operation.
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PFILE_OBJECT FileObject;
+
+    COMPOUND_PATH_ENTRY CompoundPathEntry;
+    BOOLEAN CleanupCompoundPathEntry = FALSE;
+
+    FILE_ENUM_CONTEXT FileContext;
+    BOOLEAN CleanupFileContext = FALSE;
+    BOOLEAN FoundEntry;
+
+    PVCB Vcb;
+
+    BOOLEAN OpenByFileId;
+    BOOLEAN IgnoreCase;
+    ULONG CreateDisposition;
+
+    BOOLEAN ShortNameMatch;
+    ULONG ShortNameDirentOffset;
+
+    BOOLEAN VolumeOpen = FALSE;
+
+    //
+    //  We will be acquiring and releasing file Fcb's as we move down the
+    //  directory tree during opens.  At any time we need to know the deepest
+    //  point we have traversed down in the tree in case we need to cleanup
+    //  any structures created here.
+    //
+    //  CurrentFcb - represents this point.  If non-null it means we have
+    //      acquired it and need to release it in finally clause.
+    //
+    //  NextFcb - represents the NextFcb to walk to but haven't acquired yet.
+    //
+
+    TYPE_OF_OPEN RelatedTypeOfOpen = UnopenedFileObject;
+    PFILE_OBJECT RelatedFileObject;
+    PCCB RelatedCcb = NULL;
+
+    PFCB NextFcb;
+    PFCB CurrentFcb = NULL;
+
+    //
+    //  During the open we need to combine the related file object name
+    //  with the remaining name.  We also may need to upcase the file name
+    //  in order to do a case-insensitive name comparison.  We also need
+    //  to restore the name in the file object in the event that we retry
+    //  the request.  We use the following string variables to manage the
+    //  name.  We will can put these strings into either Unicode or Ansi
+    //  form.
+    //
+    //  FileName - Pointer to name as currently stored in the file
+    //      object.  We store the full name into the file object early in
+    //      the open operation.
+    //
+    //  RelatedFileName - Pointer to the name in the related file object.
+    //
+    //  RemainingName - String containing remaining name to parse.
+    //
+    //  MatchingName - Address of name structure in FileContext which matched.
+    //      We need this to know whether we matched the long or short name.
+    //
+
+    PUNICODE_STRING FileName;
+    PUNICODE_STRING RelatedFileName = NULL;
+
+    CD_NAME RemainingName;
+    CD_NAME FinalName;
+    PCD_NAME MatchingName;
+
+    PAGED_CODE();
+
+    //
+    //  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 create parameters from the Irp.
+    //
+
+    OpenByFileId = BooleanFlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID );
+    IgnoreCase = !BooleanFlagOn( IrpSp->Flags, SL_CASE_SENSITIVE );
+    CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff;
+
+    //
+    //  Do some preliminary checks to make sure the operation is supported.
+    //  We fail in the following cases immediately.
+    //
+    //      - Open a paging file.
+    //      - Open a target directory.
+    //      - Open a file with Eas.
+    //      - Create a file.
+    //
+
+    if (FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE | SL_OPEN_TARGET_DIRECTORY) ||
+        (IrpSp->Parameters.Create.EaLength != 0) ||
+        (CreateDisposition == FILE_CREATE)) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
+        return STATUS_ACCESS_DENIED;
+    }
+
+    //
+    //  Copy the Vcb to a local.  Assume the starting directory is the root.
+    //
+
+    Vcb = IrpContext->Vcb;
+    NextFcb = Vcb->RootIndexFcb;
+
+    //
+    //  Reference our input parameters to make things easier
+    //
+
+    FileObject = IrpSp->FileObject;
+    RelatedFileObject = NULL;
+
+    FileName = &FileObject->FileName;
+
+    //
+    //  Set up the file object's Vpb pointer in case anything happens.
+    //  This will allow us to get a reasonable pop-up.
+    //
+
+    if ((FileObject->RelatedFileObject != NULL) && !OpenByFileId) {
+
+        RelatedFileObject = FileObject->RelatedFileObject;
+        FileObject->Vpb = RelatedFileObject->Vpb;
+
+        RelatedTypeOfOpen = CdDecodeFileObject( IrpContext, RelatedFileObject, &NextFcb, &RelatedCcb );
+
+        //
+        //  Fail the request if this is not a user file object.
+        //
+
+        if (RelatedTypeOfOpen < UserVolumeOpen) {
+
+            CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+            return STATUS_INVALID_PARAMETER;
+        }
+
+        //
+        //  Remember the name in the related file object.
+        //
+
+        RelatedFileName = &RelatedFileObject->FileName;
+    }
+
+    //
+    //  If we haven't initialized the names then make sure the strings are valid.
+    //  If this an OpenByFileId then verify the file id buffer.
+    //
+    //  After this routine returns we know that the full name is in the
+    //  FileName buffer and the buffer will hold the upcased portion
+    //  of the name yet to parse immediately after the full name in the
+    //  buffer.  Any trailing backslash has been removed and the flag
+    //  in the IrpContext will indicate whether we removed the
+    //  backslash.
+    //
+
+    Status = CdNormalizeFileNames( IrpContext,
+                                   Vcb,
+                                   OpenByFileId,
+                                   IgnoreCase,
+                                   RelatedTypeOfOpen,
+                                   RelatedCcb,
+                                   RelatedFileName,
+                                   FileName,
+                                   &RemainingName );
+
+    //
+    //  Return the error code if not successful.
+    //
+
+    if (!NT_SUCCESS( Status )) {
+
+        CdCompleteRequest( IrpContext, Irp, Status );
+        return Status;
+    }
+
+    //
+    //  We want to acquire the Vcb.  Exclusively for a volume open, shared otherwise.
+    //  The file name is empty for a volume open.
+    //
+
+    if ((FileName->Length == 0) &&
+        (RelatedTypeOfOpen <= UserVolumeOpen) &&
+        !OpenByFileId) {
+
+        VolumeOpen = TRUE;
+        CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
+
+    } else {
+
+        CdAcquireVcbShared( IrpContext, Vcb, FALSE );
+    }
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Verify that the Vcb is not in an unusable condition.  This routine
+        //  will raise if not usable.
+        //
+
+        CdVerifyVcb( IrpContext, Vcb );
+
+        //
+        //  If the Vcb is locked then we cannot open another file
+        //
+
+        if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) {
+
+            try_return( Status = STATUS_ACCESS_DENIED );
+        }
+
+        //
+        //  If we are opening this file by FileId then process this immediately
+        //  and exit.
+        //
+
+        if (OpenByFileId) {
+
+            //
+            //  We only allow Dasd opens of audio disks.  Fail this request at
+            //  this point.
+            //
+
+            if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
+
+                try_return( Status = STATUS_INVALID_DEVICE_REQUEST );
+            }
+
+            //
+            //  The only create disposition we allow is OPEN.
+            //
+
+            if ((CreateDisposition != FILE_OPEN) &&
+                (CreateDisposition != FILE_OPEN_IF)) {
+
+                try_return( Status = STATUS_ACCESS_DENIED );
+            }
+
+            //
+            //  Make sure we can wait for this request.
+            //
+
+            if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
+
+                CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
+            }
+
+            try_return( Status = CdOpenByFileId( IrpContext,
+                                                 IrpSp,
+                                                 Vcb,
+                                                 &CurrentFcb ));
+        }
+
+        //
+        //  If we are opening this volume Dasd then process this immediately
+        //  and exit.
+        //
+
+        if (VolumeOpen) {
+
+            //
+            //  The only create disposition we allow is OPEN.
+            //
+
+            if ((CreateDisposition != FILE_OPEN) &&
+                (CreateDisposition != FILE_OPEN_IF)) {
+
+                try_return( Status = STATUS_ACCESS_DENIED );
+            }
+
+            //
+            //  If they wanted to open a directory, surprise.
+            //
+
+            if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
+
+                try_return( Status = STATUS_NOT_A_DIRECTORY );
+            }
+
+            //
+            //  Acquire the Fcb first.
+            //
+
+            CurrentFcb = Vcb->VolumeDasdFcb;
+            CdAcquireFcbExclusive( IrpContext, CurrentFcb, FALSE );
+
+            try_return( Status = CdOpenExistingFcb( IrpContext,
+                                                    IrpSp,
+                                                    &CurrentFcb,
+                                                    UserVolumeOpen,
+                                                    FALSE,
+                                                    NULL ));
+        }
+
+        //
+        //  At this point CurrentFcb points to the deepest Fcb for this open
+        //  in the tree.  Let's acquire this Fcb to keep it from being deleted
+        //  beneath us.
+        //
+
+        CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
+        CurrentFcb = NextFcb;
+
+        //
+        //  Do a prefix search if there is more of the name to parse.
+        //
+
+        if (RemainingName.FileName.Length != 0) {
+
+            //
+            //  Do the prefix search to find the longest matching name.
+            //
+
+            CdFindPrefix( IrpContext,
+                          &CurrentFcb,
+                          &RemainingName.FileName,
+                          IgnoreCase );
+        }
+
+        //
+        //  If the remaining name length is zero then we have found our
+        //  target.
+        //
+
+        if (RemainingName.FileName.Length == 0) {
+
+            //
+            //  If this is a file so verify the user didn't want to open
+            //  a directory.
+            //
+
+            if (SafeNodeType( CurrentFcb ) == CDFS_NTC_FCB_DATA) {
+
+                if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH ) ||
+                    FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
+
+                    try_return( Status = STATUS_NOT_A_DIRECTORY );
+                }
+
+                //
+                //  The only create disposition we allow is OPEN.
+                //
+
+                if ((CreateDisposition != FILE_OPEN) &&
+                    (CreateDisposition != FILE_OPEN_IF)) {
+
+                    try_return( Status = STATUS_ACCESS_DENIED );
+                }
+
+                try_return( Status = CdOpenExistingFcb( IrpContext,
+                                                        IrpSp,
+                                                        &CurrentFcb,
+                                                        UserFileOpen,
+                                                        IgnoreCase,
+                                                        RelatedCcb ));
+
+            //
+            //  This is a directory.  Verify the user didn't want to open
+            //  as a file.
+            //
+
+            } else if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
+
+                try_return( Status = STATUS_FILE_IS_A_DIRECTORY );
+
+            //
+            //  Open the file as a directory.
+            //
+
+            } else {
+
+                //
+                //  The only create disposition we allow is OPEN.
+                //
+
+                if ((CreateDisposition != FILE_OPEN) &&
+                    (CreateDisposition != FILE_OPEN_IF)) {
+
+                    try_return( Status = STATUS_ACCESS_DENIED );
+                }
+
+                try_return( Status = CdOpenExistingFcb( IrpContext,
+                                                        IrpSp,
+                                                        &CurrentFcb,
+                                                        UserDirectoryOpen,
+                                                        IgnoreCase,
+                                                        RelatedCcb ));
+            }
+        }
+
+        //
+        //  We have more work to do.  We have a starting Fcb which we own shared.
+        //  We also have the remaining name to parse.  Walk through the name
+        //  component by component looking for the full name.
+        //
+
+        //
+        //  Our starting Fcb better be a directory.
+        //
+
+        if (!FlagOn( CurrentFcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
+
+            try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
+        }
+
+        //
+        //  If we can't wait then post this request.
+        //
+
+        if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
+
+            CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
+        }
+
+        //
+        //  Make sure the final name has no version string.
+        //
+
+        FinalName.VersionString.Length = 0;
+
+        while (TRUE) {
+
+            ShortNameMatch = FALSE;
+
+            //
+            //  Split off the next component from the name.
+            //
+
+            CdDissectName( IrpContext,
+                           &RemainingName.FileName,
+                           &FinalName.FileName );
+
+            //
+            //  Go ahead and look this entry up in the path table.
+            //
+
+            CdInitializeCompoundPathEntry( IrpContext, &CompoundPathEntry );
+            CleanupCompoundPathEntry = TRUE;
+
+            FoundEntry = CdFindPathEntry( IrpContext,
+                                          CurrentFcb,
+                                          &FinalName,
+                                          IgnoreCase,
+                                          &CompoundPathEntry );
+
+            //
+            //  If we didn't find the entry then check if the current name
+            //  is a possible short name.
+            //
+
+            if (!FoundEntry) {
+
+                ShortNameDirentOffset = CdShortNameDirentOffset( IrpContext, &FinalName.FileName );
+
+                //
+                //  If there is an embedded short name offset then look for the
+                //  matching long name in the directory.
+                //
+
+                if (ShortNameDirentOffset != MAXULONG) {
+
+                    if (CleanupFileContext) {
+
+                        CdCleanupFileContext( IrpContext, &FileContext );
+                    }
+
+                    CdInitializeFileContext( IrpContext, &FileContext );
+                    CleanupFileContext = TRUE;
+
+                    FoundEntry = CdFindFileByShortName( IrpContext,
+                                                        CurrentFcb,
+                                                        &FinalName,
+                                                        IgnoreCase,
+                                                        ShortNameDirentOffset,
+                                                        &FileContext );
+
+                    //
+                    //  If we found an entry and it is a directory then look
+                    //  this up in the path table.
+                    //
+
+                    if (FoundEntry) {
+
+                        ShortNameMatch = TRUE;
+
+                        if (FlagOn( FileContext.InitialDirent->Dirent.DirentFlags,
+                                    CD_ATTRIBUTE_DIRECTORY )) {
+
+                            CdCleanupCompoundPathEntry( IrpContext, &CompoundPathEntry );
+                            CdInitializeCompoundPathEntry( IrpContext, &CompoundPathEntry );
+
+                            FoundEntry = CdFindPathEntry( IrpContext,
+                                                          CurrentFcb,
+                                                          &FileContext.InitialDirent->Dirent.CdCaseFileName,
+                                                          IgnoreCase,
+                                                          &CompoundPathEntry );
+
+                            //
+                            //  We better find this entry.
+                            //
+
+                            if (!FoundEntry) {
+
+                                CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+                            }
+
+                            //
+                            //  Upcase the name with the short name if case
+                            //  insensitive.
+                            //
+
+                            if (IgnoreCase) {
+
+                                CdUpcaseName( IrpContext, &FinalName, &FinalName );
+                            }
+
+                        //
+                        //  We found a matching file.  If we are at the last
+                        //  entry then break out of the loop and open the
+                        //  file below.  Otherwise we return an error.
+                        //
+
+                        } else if (RemainingName.FileName.Length == 0) {
+
+                            //
+                            //  Break out of the loop.  We will process the dirent
+                            //  below.
+                            //
+
+                            MatchingName = &FileContext.ShortName;
+                            break;
+
+                        } else {
+
+                            try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
+                        }
+                    }
+                }
+
+                //
+                //  We didn't find the name in either the path table or as
+                //  a short name in a directory.  If the remaining name
+                //  length is zero then break out of the loop to search
+                //  the directory.
+                //
+
+                if (!FoundEntry) {
+
+                    if (RemainingName.FileName.Length == 0) {
+
+                        break;
+
+                    //
+                    //  Otherwise this path could not be cracked.
+                    //
+
+                    } else {
+
+                        try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
+                    }
+                }
+            }
+
+            //
+            //  If this is an ignore case open then copy the exact case
+            //  in the file object name.  If it was a short name match then
+            //  the name must be upcase already.
+            //
+
+            if (IgnoreCase && !ShortNameMatch) {
+
+                RtlCopyMemory( FinalName.FileName.Buffer,
+                               CompoundPathEntry.PathEntry.CdDirName.FileName.Buffer,
+                               CompoundPathEntry.PathEntry.CdDirName.FileName.Length );
+            }
+
+            //
+            //  If we have found the last component then open this as a directory
+            //  and return to our caller.
+            //
+
+            if (RemainingName.FileName.Length == 0) {
+
+                if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
+
+                    try_return( Status = STATUS_FILE_IS_A_DIRECTORY );
+                }
+
+                //
+                //  The only create disposition we allow is OPEN.
+                //
+
+                if ((CreateDisposition != FILE_OPEN) &&
+                    (CreateDisposition != FILE_OPEN_IF)) {
+
+                    try_return( Status = STATUS_ACCESS_DENIED );
+                }
+
+                try_return( Status = CdOpenDirectoryFromPathEntry( IrpContext,
+                                                                   IrpSp,
+                                                                   Vcb,
+                                                                   &CurrentFcb,
+                                                                   &FinalName,
+                                                                   IgnoreCase,
+                                                                   ShortNameMatch,
+                                                                   &CompoundPathEntry.PathEntry,
+                                                                   TRUE,
+                                                                   RelatedCcb ));
+            }
+
+            //
+            //  Otherwise open an Fcb for this intermediate index Fcb.
+            //
+
+            CdOpenDirectoryFromPathEntry( IrpContext,
+                                          IrpSp,
+                                          Vcb,
+                                          &CurrentFcb,
+                                          &FinalName,
+                                          IgnoreCase,
+                                          ShortNameMatch,
+                                          &CompoundPathEntry.PathEntry,
+                                          FALSE,
+                                          NULL );
+
+            CdCleanupCompoundPathEntry( IrpContext, &CompoundPathEntry );
+            CleanupCompoundPathEntry = FALSE;
+        }
+
+        //
+        //  We need to scan the current directory for a matching file name
+        //  if we don't already have one.
+        //
+
+        if (!FoundEntry) {
+
+            if (CleanupFileContext) {
+
+                CdCleanupFileContext( IrpContext, &FileContext );
+            }
+
+            CdInitializeFileContext( IrpContext, &FileContext );
+            CleanupFileContext = TRUE;
+
+            //
+            //  Split our search name into separate components.
+            //
+
+            CdConvertNameToCdName( IrpContext, &FinalName );
+
+            FoundEntry = CdFindFile( IrpContext,
+                                     CurrentFcb,
+                                     &FinalName,
+                                     IgnoreCase,
+                                     &FileContext,
+                                     &MatchingName );
+        }
+
+        //
+        //  If we didn't find a match then check if the name is invalid to
+        //  determine which error code to return.
+        //
+
+        if (!FoundEntry) {
+
+            if ((CreateDisposition == FILE_OPEN) ||
+                (CreateDisposition == FILE_OVERWRITE)) {
+
+                try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND );
+            }
+
+            //
+            //  Any other operation return STATUS_ACCESS_DENIED.
+            //
+
+            try_return( Status = STATUS_ACCESS_DENIED );
+        }
+
+        //
+        //  If this is a directory then the disk is corrupt because it wasn't
+        //  in the Path Table.
+        //
+
+        if (FlagOn( FileContext.InitialDirent->Dirent.Flags, CD_ATTRIBUTE_DIRECTORY )) {
+
+            CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
+        }
+
+        //
+        //  Make sure our opener didn't want a directory.
+        //
+
+        if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH ) ||
+            FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
+
+            try_return( Status = STATUS_NOT_A_DIRECTORY );
+        }
+
+        //
+        //  The only create disposition we allow is OPEN.
+        //
+
+        if ((CreateDisposition != FILE_OPEN) &&
+            (CreateDisposition != FILE_OPEN_IF)) {
+
+            try_return( Status = STATUS_ACCESS_DENIED );
+        }
+
+        //
+        //  If this is an ignore case open then copy the exact case
+        //  in the file object name.  Any version portion should
+        //  already be upcased.
+        //
+
+        if (IgnoreCase) {
+
+            RtlCopyMemory( FinalName.FileName.Buffer,
+                           MatchingName->FileName.Buffer,
+                           MatchingName->FileName.Length );
+        }
+
+        //
+        //  Open the file using the file context.  We already have the
+        //  first and last dirents.
+        //
+
+        try_return( Status = CdOpenFileFromFileContext( IrpContext,
+                                                        IrpSp,
+                                                        Vcb,
+                                                        &CurrentFcb,
+                                                        &FinalName,
+                                                        IgnoreCase,
+                                                        (BOOLEAN) (MatchingName == &FileContext.ShortName),
+                                                        &FileContext,
+                                                        RelatedCcb ));
+
+    try_exit:  NOTHING;
+    } finally {
+
+        //
+        //  Cleanup the PathEntry if initialized.
+        //
+
+        if (CleanupCompoundPathEntry) {
+
+            CdCleanupCompoundPathEntry( IrpContext, &CompoundPathEntry );
+        }
+
+        //
+        //  Cleanup the FileContext if initialized.
+        //
+
+        if (CleanupFileContext) {
+
+            CdCleanupFileContext( IrpContext, &FileContext );
+        }
+
+        //
+        //  The result of this open could be success, pending or some error
+        //  condition.
+        //
+
+        if (AbnormalTermination()) {
+
+
+            //
+            //  In the error path we start by calling our teardown routine if we
+            //  have a CurrentFcb.
+            //
+
+            if (CurrentFcb != NULL) {
+
+                BOOLEAN RemovedFcb;
+
+                CdTeardownStructures( IrpContext, CurrentFcb, &RemovedFcb );
+
+                if (RemovedFcb) {
+
+                    CurrentFcb = NULL;
+                }
+            }
+
+            //
+            //  No need to complete the request.
+            //
+
+            IrpContext = NULL;
+            Irp = NULL;
+
+        //
+        //  If we posted this request through the oplock package we need
+        //  to show that there is no reason to complete the request.
+        //
+
+        } else if (Status == STATUS_PENDING) {
+
+            IrpContext = NULL;
+            Irp = NULL;
+        }
+
+        //
+        //  Release the Current Fcb if still acquired.
+        //
+
+        if (CurrentFcb != NULL) {
+
+            CdReleaseFcb( IrpContext, CurrentFcb );
+        }
+
+        //
+        //  Release the Vcb.
+        //
+
+        CdReleaseVcb( IrpContext, Vcb );
+
+        //
+        //  Call our completion routine.  It will handle the case where either
+        //  the Irp and/or IrpContext are gone.
+        //
+
+        CdCompleteRequest( IrpContext, Irp, Status );
+    }
+
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdNormalizeFileNames (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN BOOLEAN OpenByFileId,
+    IN BOOLEAN IgnoreCase,
+    IN TYPE_OF_OPEN RelatedTypeOfOpen,
+    IN PCCB RelatedCcb OPTIONAL,
+    IN PUNICODE_STRING RelatedFileName OPTIONAL,
+    IN OUT PUNICODE_STRING FileName,
+    IN OUT PCD_NAME RemainingName
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to store the full name and upcased name into the
+    filename buffer.  We only upcase the portion yet to parse.  We also
+    check for a trailing backslash and lead-in double backslashes.  This
+    routine also verifies the mode of the related open against the name
+    currently in the filename.
+
+Arguments:
+
+    Vcb - Vcb for this volume.
+
+    OpenByFileId - Indicates if the filename should be a 64 bit FileId.
+
+    IgnoreCase - Indicates if this open is a case-insensitive operation.
+
+    RelatedTypeOfOpen - Indicates the type of the related file object.
+
+    RelatedCcb - Ccb for the related open.  Ignored if no relative open.
+
+    RelatedFileName - FileName buffer for related open.  Ignored if no
+        relative open.
+
+    FileName - FileName to update in this routine.  The name should
+        either be a 64-bit FileId or a Unicode string.
+
+    RemainingName - Name with the remaining portion of the name.  This
+        will begin after the related name and any separator.  For a
+        non-relative open we also step over the initial separator.
+
+Return Value:
+
+    NTSTATUS - STATUS_SUCCESS if the names are OK, appropriate error code
+        otherwise.
+
+--*/
+
+{
+    ULONG RemainingNameLength;
+    ULONG RelatedNameLength = 0;
+    ULONG SeparatorLength = 0;
+
+    ULONG BufferLength;
+
+    UNICODE_STRING NewFileName;
+
+    PAGED_CODE();
+
+    //
+    //  If this is the first pass then we need to build the full name and
+    //  check for name compatibility.
+    //
+
+    if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_FULL_NAME )) {
+
+        //
+        //  Deal with the regular file name case first.
+        //
+
+        if (!OpenByFileId) {
+
+            //
+            //  This is here because the Win32 layer can't avoid sending me double
+            //  beginning backslashes.
+            //
+            
+            if ((FileName->Length > sizeof( WCHAR )) &&
+                (FileName->Buffer[1] == L'\\') &&
+                (FileName->Buffer[0] == L'\\')) {
+
+                //
+                //  If there are still two beginning backslashes, the name is bogus.
+                //
+
+                if ((FileName->Length > 2 * sizeof( WCHAR )) &&
+                    (FileName->Buffer[2] == L'\\')) {
+
+                    return STATUS_OBJECT_NAME_INVALID;
+                }
+
+                //
+                //  Slide the name down in the buffer.
+                //
+
+                FileName->Length -= sizeof( WCHAR );
+
+                RtlMoveMemory( FileName->Buffer,
+                               FileName->Buffer + 1,
+                               FileName->Length );
+            }
+
+            //
+            //  Check for a trailing backslash.  Don't strip off if only character
+            //  in the full name or for relative opens where this is illegal.
+            //
+
+            if (((FileName->Length > sizeof( WCHAR)) ||
+                 ((FileName->Length == sizeof( WCHAR )) && (RelatedTypeOfOpen == UserDirectoryOpen))) &&
+                (FileName->Buffer[ (FileName->Length/2) - 1 ] == L'\\')) {
+
+                SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH );
+                FileName->Length -= sizeof( WCHAR );
+            }
+
+            //
+            //  Remember the length we need for this portion of the name.
+            //
+
+            RemainingNameLength = FileName->Length;
+
+            //
+            //  If this is a related file object then we verify the compatibility
+            //  of the name in the file object with the relative file object.
+            //
+
+            if (RelatedTypeOfOpen != UnopenedFileObject) {
+
+                //
+                //  If the filename length was zero then it must be legal.
+                //  If there are characters then check with the related
+                //  type of open.
+                //
+
+                if (FileName->Length != 0) {
+
+                    //
+                    //  The name length must always be zero for a volume open.
+                    //
+
+                    if (RelatedTypeOfOpen <= UserVolumeOpen) {
+
+                        return STATUS_INVALID_PARAMETER;
+
+                    //
+                    //  The remaining name cannot begin with a backslash.
+                    //
+
+                    } else if (FileName->Buffer[0] == L'\\' ) {
+
+                        return STATUS_INVALID_PARAMETER;
+
+                    //
+                    //  If the related file is a user file then there
+                    //  is no file with this path.
+                    //
+
+                    } else if (RelatedTypeOfOpen == UserFileOpen) {
+
+                        return STATUS_OBJECT_PATH_NOT_FOUND;
+                    }
+                }
+
+                //
+                //  Remember the length of the related name when building
+                //  the full name.  We leave the RelatedNameLength and
+                //  SeparatorLength at zero if the relative file is opened
+                //  by Id.
+                //
+
+                if (!FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID )) {
+
+                    //
+                    //  Add a separator if the name length is non-zero
+                    //  unless the relative Fcb is at the root.
+                    //
+
+                    if ((FileName->Length != 0) &&
+                        (RelatedCcb->Fcb != Vcb->RootIndexFcb)) {
+
+                        SeparatorLength = sizeof( WCHAR );
+                    }
+
+                    RelatedNameLength = RelatedFileName->Length;
+                }
+
+            //
+            //  The full name is already in the filename.  It must either
+            //  be length 0 or begin with a backslash.
+            //
+
+            } else if (FileName->Length != 0) {
+
+                if (FileName->Buffer[0] != L'\\') {
+
+                    return STATUS_INVALID_PARAMETER;
+                }
+
+                //
+                //  We will want to trim the leading backslash from the
+                //  remaining name we return.
+                //
+
+                RemainingNameLength -= sizeof( WCHAR );
+                SeparatorLength = sizeof( WCHAR );
+            }
+
+            //
+            //  Now see if the buffer is large enough to hold the full name.
+            //
+
+            BufferLength = RelatedNameLength + SeparatorLength + RemainingNameLength;
+
+            //
+            //  Check for an overflow of the maximum filename size.
+            //
+            
+            if (BufferLength > MAXUSHORT) {
+
+                return STATUS_INVALID_PARAMETER;
+            }
+            
+            //
+            //  Now see if we need to allocate a new buffer.
+            //
+
+            if (FileName->MaximumLength < BufferLength) {
+
+                NewFileName.Buffer = FsRtlAllocatePoolWithTag( CdPagedPool,
+                                                               BufferLength,
+                                                               TAG_FILE_NAME );
+
+                NewFileName.MaximumLength = (USHORT) BufferLength;
+
+            } else {
+
+                NewFileName.Buffer = FileName->Buffer;
+                NewFileName.MaximumLength = FileName->MaximumLength;
+            }
+
+            //
+            //  If there is a related name then we need to slide the remaining bytes up and
+            //  insert the related name.  Otherwise the name is in the correct position
+            //  already.
+            //
+
+            if (RelatedNameLength != 0) {
+
+                //
+                //  Store the remaining name in its correct position.
+                //
+
+                if (RemainingNameLength != 0) {
+
+                    RtlMoveMemory( Add2Ptr( NewFileName.Buffer, RelatedNameLength + SeparatorLength, PVOID ),
+                                   FileName->Buffer,
+                                   RemainingNameLength );
+                }
+
+                RtlCopyMemory( NewFileName.Buffer,
+                               RelatedFileName->Buffer,
+                               RelatedNameLength );
+
+                //
+                //  Add the separator if needed.
+                //
+
+                if (SeparatorLength != 0) {
+
+                    *(Add2Ptr( NewFileName.Buffer, RelatedNameLength, PWCHAR )) = L'\\';
+                }
+
+                //
+                //  Update the filename value we got from the user.
+                //
+
+                if (NewFileName.Buffer != FileName->Buffer) {
+
+                    if (FileName->Buffer != NULL) {
+
+                        CdFreePool( &FileName->Buffer );
+                    }
+
+                    FileName->Buffer = NewFileName.Buffer;
+                    FileName->MaximumLength = NewFileName.MaximumLength;
+                }
+
+                //
+                //  Copy the name length to the user's filename.
+                //
+
+                FileName->Length = (USHORT) (RelatedNameLength + SeparatorLength + RemainingNameLength);
+            }
+
+            //
+            //  Now update the remaining name to parse.
+            //
+
+            RemainingName->FileName.MaximumLength =
+            RemainingName->FileName.Length = (USHORT) RemainingNameLength;
+            RemainingName->VersionString.Length = 0;
+
+            RemainingName->FileName.Buffer = Add2Ptr( FileName->Buffer,
+                                                      RelatedNameLength + SeparatorLength,
+                                                      PWCHAR );
+
+            //
+            //  Upcase the name if necessary.
+            //
+
+            if (IgnoreCase && (RemainingNameLength != 0)) {
+
+                CdUpcaseName( IrpContext,
+                              RemainingName,
+                              RemainingName );
+            }
+
+            //
+            //  Do a quick check to make sure there are no wildcards.
+            //
+
+            if (FsRtlDoesNameContainWildCards( &RemainingName->FileName )) {
+
+                return STATUS_OBJECT_NAME_INVALID;
+            }
+
+        //
+        //  For the open by file Id case we verify the name really contains
+        //  a 64 bit value.
+        //
+
+        } else {
+
+            //
+            //  Check for validity of the buffer.
+            //
+
+            if (FileName->Length != sizeof( FILE_ID )) {
+
+                return STATUS_INVALID_PARAMETER;
+            }
+        }
+
+        SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FULL_NAME );
+
+    //
+    //  If we are in the retry path then the full name is already in the
+    //  file object name.  If this is a case-sensitive operation then
+    //  we need to upcase the name from the end of any related file name already stored
+    //  there.
+    //
+
+    } else {
+
+        //
+        //  Assume there is no relative name.
+        //
+
+        RemainingName->FileName = *FileName;
+        RemainingName->VersionString.Length = 0;
+
+        //
+        //  Nothing to do if the name length is zero.
+        //
+
+        if (RemainingName->FileName.Length != 0) {
+
+            //
+            //  If there is a relative name then we need to walk past it.
+            //
+
+            if (RelatedTypeOfOpen != UnopenedFileObject) {
+
+                //
+                //  Nothing to walk past if the RelatedCcb is opened by FileId.
+                //
+
+
+                if (!FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID )) {
+
+                    //
+                    //  Related file name is a proper prefix of the full name.
+                    //  We step over the related name and if we are then
+                    //  pointing at a separator character we step over that.
+                    //
+
+                    RemainingName->FileName.Buffer = Add2Ptr( RemainingName->FileName.Buffer,
+                                                              RelatedFileName->Length,
+                                                              PWCHAR );
+
+                    RemainingName->FileName.Length -= RelatedFileName->Length;
+                }
+            }
+
+            //
+            //  If we are pointing at a separator character then step past that.
+            //
+
+            if (RemainingName->FileName.Length != 0) {
+
+                if (*(RemainingName->FileName.Buffer) == L'\\') {
+
+                    RemainingName->FileName.Buffer = Add2Ptr( RemainingName->FileName.Buffer,
+                                                              sizeof( WCHAR ),
+                                                              PWCHAR );
+
+                    RemainingName->FileName.Length -= sizeof( WCHAR );
+                }
+            }
+        }
+
+        //
+        //  Upcase the name if necessary.
+        //
+
+        if (IgnoreCase && (RemainingName->FileName.Length != 0)) {
+
+            CdUpcaseName( IrpContext,
+                          RemainingName,
+                          RemainingName );
+        }
+    }
+
+    return STATUS_SUCCESS;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdOpenByFileId (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PVCB Vcb,
+    IN OUT PFCB *CurrentFcb
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to open a file by the FileId.  The file Id is in
+    the FileObject name buffer and has been verified to be 64 bits.
+
+    We extract the Id number and then check to see whether we are opening a
+    file or directory and compare that with the create options.  If this
+    generates no error then optimistically look up the Fcb in the Fcb Table.
+
+    If we don't find the Fcb then we need to carefully verify there is a file
+    at this offset.  First check whether the Parent Fcb is in the table.  If
+    not then lookup the parent at the path table offset given by file ID.
+
+    If found then build the Fcb from this entry and store the new Fcb in the
+    tree.
+
+    We know have the parent Fcb.  Do a directory scan to find the dirent at
+    the given offset in this stream.  This must point to the first entry
+    of a valid file.
+
+    Finally we call our worker routine to complete the open on this Fcb.
+
+Arguments:
+
+    IrpSp - Stack location within the create Irp.
+
+    Vcb - Vcb for this volume.
+
+    CurrentFcb - Address to store the Fcb for this open.  We only store the
+        CurrentFcb here when we have acquired it so our caller knows to
+        free or deallocate it.
+
+Return Value:
+
+    NTSTATUS - Status indicating the result of the operation.
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_ACCESS_DENIED;
+
+    BOOLEAN UnlockVcb = FALSE;
+    BOOLEAN Found;
+
+    ULONG StreamOffset;
+
+    NODE_TYPE_CODE NodeTypeCode;
+    TYPE_OF_OPEN TypeOfOpen;
+
+    FILE_ENUM_CONTEXT FileContext;
+    BOOLEAN CleanupFileContext = FALSE;
+
+    COMPOUND_PATH_ENTRY CompoundPathEntry;
+    BOOLEAN CleanupCompoundPathEntry = FALSE;
+
+    FILE_ID FileId;
+    FILE_ID ParentFileId;
+
+    PFCB NextFcb;
+
+    PAGED_CODE();
+
+    //
+    //  Extract the FileId from the FileObject.
+    //
+
+    RtlCopyMemory( &FileId, IrpSp->FileObject->FileName.Buffer, sizeof( FILE_ID ));
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Go ahead and figure out the TypeOfOpen and NodeType.  We can
+        //  get these from the input FileId.
+        //
+
+        if (CdFidIsDirectory( FileId )) {
+
+            TypeOfOpen = UserDirectoryOpen;
+            NodeTypeCode = CDFS_NTC_FCB_INDEX;
+
+            //
+            //  If the offset isn't zero then the file Id is bad.
+            //
+
+            if (CdQueryFidDirentOffset( FileId ) != 0) {
+
+                try_return( Status = STATUS_INVALID_PARAMETER );
+            }
+
+        } else {
+
+            TypeOfOpen = UserFileOpen;
+            NodeTypeCode = CDFS_NTC_FCB_DATA;
+        }
+
+        //
+        //  Acquire the Vcb and check if there is already an Fcb.
+        //  If not we will need to carefully verify the Fcb.
+        //  We will post the request if we don't find the Fcb and this
+        //  request can't wait.
+        //
+
+        CdLockVcb( IrpContext, Vcb );
+        UnlockVcb = TRUE;
+
+        NextFcb = CdLookupFcbTable( IrpContext, Vcb, FileId );
+
+        if (NextFcb == NULL) {
+
+            //
+            //  Get the path table offset from the file id.
+            //
+
+            StreamOffset = CdQueryFidPathTableOffset( FileId );
+
+            //
+            //  Build the parent FileId for this and try looking it
+            //  up in the PathTable.
+            //
+
+            CdSetFidDirentOffset( ParentFileId, 0 );
+            CdSetFidPathTableOffset( ParentFileId, StreamOffset );
+            CdFidSetDirectory( ParentFileId );
+
+            NextFcb = CdLookupFcbTable( IrpContext, Vcb, ParentFileId );
+
+            //
+            //  If not present then walk through the PathTable to this point.
+            //
+
+            if (NextFcb == NULL) {
+
+                CdUnlockVcb( IrpContext, Vcb );
+                UnlockVcb = FALSE;
+
+                //
+                //  Check that the path table offset lies within the path
+                //  table.
+                //
+
+                if (StreamOffset > Vcb->PathTableFcb->FileSize.LowPart) {
+
+                    try_return( Status = STATUS_INVALID_PARAMETER );
+                }
+
+                CdInitializeCompoundPathEntry( IrpContext, &CompoundPathEntry );
+                CleanupCompoundPathEntry = TRUE;
+
+                //
+                //  Start at the first entry in the PathTable.
+                //
+
+                CdLookupPathEntry( IrpContext,
+                                   Vcb->PathTableFcb->StreamOffset,
+                                   1,
+                                   TRUE,
+                                   &CompoundPathEntry );
+
+                //
+                //  Continue looking until we have passed our target offset.
+                //
+
+                while (TRUE) {
+
+                    //
+                    //  Move to the next entry.
+                    //
+
+                    Found = CdLookupNextPathEntry( IrpContext,
+                                                   &CompoundPathEntry.PathContext,
+                                                   &CompoundPathEntry.PathEntry );
+
+                    //
+                    //  If we didn't find the entry or are beyond it then the
+                    //  input Id is invalid.
+                    //
+
+                    if (!Found ||
+                        (CompoundPathEntry.PathEntry.PathTableOffset > StreamOffset)) {
+
+                        try_return( Status = STATUS_INVALID_PARAMETER );
+                    }
+                }
+
+                //
+                //  If the FileId specified a directory then we have found
+                //  the entry.  Make sure our caller wanted to open a directory.
+                //
+
+                if ((TypeOfOpen == UserDirectoryOpen) &&
+                    FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
+
+                    try_return( Status = STATUS_FILE_IS_A_DIRECTORY );
+                }
+
+                //
+                //  Lock the Vcb and create the Fcb if necessary.
+                //
+
+                CdLockVcb( IrpContext, Vcb );
+                UnlockVcb = TRUE;
+
+                NextFcb = CdCreateFcb( IrpContext, ParentFileId, NodeTypeCode, &Found );
+
+                //
+                //  It's possible that someone got in here ahead of us.
+                //
+
+                if (!Found) {
+
+                    CdInitializeFcbFromPathEntry( IrpContext,
+                                                  NextFcb,
+                                                  NULL,
+                                                  &CompoundPathEntry.PathEntry );
+                }
+
+                //
+                //  If the user wanted to open a directory then we have found
+                //  it.  Store this Fcb into the CurrentFcb and skip the
+                //  directory scan.
+                //
+
+                if (TypeOfOpen == UserDirectoryOpen) {
+
+                    *CurrentFcb = NextFcb;
+                    NextFcb = NULL;
+                }
+            }
+
+            //
+            //  Perform the directory scan if we don't already have our target.
+            //
+
+            if (NextFcb != NULL) {
+
+                //
+                //  Acquire the parent.  We currently own the Vcb lock so
+                //  do this without waiting first.
+                //
+
+                if (!CdAcquireFcbExclusive( IrpContext,
+                                            NextFcb,
+                                            TRUE )) {
+
+                    NextFcb->FcbReference += 1;
+                    CdUnlockVcb( IrpContext, Vcb );
+
+                    CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
+
+                    CdLockVcb( IrpContext, Vcb );
+                    NextFcb->FcbReference -= 1;
+                    CdUnlockVcb( IrpContext, Vcb );
+
+                } else {
+
+                    CdUnlockVcb( IrpContext, Vcb );
+                }
+
+                UnlockVcb = FALSE;
+
+                //
+                //  Set up the CurrentFcb pointers.  We know there was
+                //  no previous parent in this case.
+                //
+
+                *CurrentFcb = NextFcb;
+
+                //
+                //  Calculate the offset in the stream.
+                //
+
+                StreamOffset = CdQueryFidDirentOffset( FileId );
+
+                //
+                //  Create the stream file if it doesn't exist.  This will update
+                //  the Fcb with the size from the self entry.
+                //
+
+                if (NextFcb->FileObject == NULL) {
+
+                    CdCreateInternalStream( IrpContext, Vcb, NextFcb );
+                }
+
+                //
+                //  If our offset is beyond the end of the directory then the
+                //  FileId is invalid.
+                //
+
+                if (StreamOffset > NextFcb->FileSize.LowPart) {
+
+                    try_return( Status = STATUS_INVALID_PARAMETER );
+                }
+
+                //
+                //  Otherwise position ourselves at the self entry and walk
+                //  through dirent by dirent until this location is found.
+                //
+
+                CdInitializeFileContext( IrpContext, &FileContext );
+                CdLookupInitialFileDirent( IrpContext,
+                                           NextFcb,
+                                           &FileContext,
+                                           NextFcb->StreamOffset );
+
+                CleanupFileContext = TRUE;
+
+                while (TRUE) {
+
+                    //
+                    //  Move to the first entry of the next file.
+                    //
+
+                    Found = CdLookupNextInitialFileDirent( IrpContext,
+                                                           NextFcb,
+                                                           &FileContext );
+
+                    //
+                    //  If we didn't find the entry or are beyond it then the
+                    //  input Id is invalid.
+                    //
+
+                    if (!Found ||
+                        (FileContext.InitialDirent->Dirent.DirentOffset > StreamOffset)) {
+
+                        try_return( Status = STATUS_INVALID_PARAMETER );
+                    }
+                }
+
+                //
+                //  This better not be a directory.  Directory FileIds must
+                //  refer to the self entry for directories.
+                //
+
+                if (FlagOn( FileContext.InitialDirent->Dirent.DirentFlags,
+                            CD_ATTRIBUTE_DIRECTORY )) {
+
+                    try_return( Status = STATUS_INVALID_PARAMETER );
+                }
+
+                //
+                //  Check that our caller wanted to open a file.
+                //
+
+                if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
+
+                    try_return( Status = STATUS_NOT_A_DIRECTORY );
+                }
+
+                //
+                //  Otherwise we want to collect all of the dirents for this file
+                //  and create an Fcb with this.
+                //
+
+                CdLookupLastFileDirent( IrpContext, NextFcb, &FileContext );
+
+                CdLockVcb( IrpContext, Vcb );
+                UnlockVcb = TRUE;
+
+                NextFcb = CdCreateFcb( IrpContext, FileId, NodeTypeCode, &Found );
+
+                //
+                //  It's possible that someone has since created this Fcb since we
+                //  first checked.  If so then can simply use this.  Otherwise
+                //  we need to initialize a new Fcb and attach it to our parent
+                //  and insert it into the Fcb Table.
+                //
+
+                if (!Found) {
+
+                    CdInitializeFcbFromFileContext( IrpContext,
+                                                    NextFcb,
+                                                    *CurrentFcb,
+                                                    &FileContext );
+                }
+            }
+
+        //
+        //  We have the Fcb.  Check that the type of the file is compatible with
+        //  the desired type of file to open.
+        //
+
+        } else {
+
+            if (FlagOn( NextFcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
+
+                if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
+
+                    try_return( Status = STATUS_FILE_IS_A_DIRECTORY );
+                }
+
+            } else if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
+
+                try_return( Status = STATUS_NOT_A_DIRECTORY );
+            }
+        }
+
+        //
+        //  If we have a the previous Fcb and have inserted the next Fcb into
+        //  the Fcb Table.  It is safe to release the current Fcb if present
+        //  since it is referenced through the child Fcb.
+        //
+
+        if (*CurrentFcb != NULL) {
+
+            CdReleaseFcb( IrpContext, *CurrentFcb );
+        }
+
+        //
+        //  We now know the Fcb and currently hold the Vcb lock.
+        //  Try to acquire this Fcb without waiting.  Otherwise we
+        //  need to reference it, drop the Vcb, acquire the Fcb and
+        //  then dereference the Fcb.
+        //
+
+        if (!CdAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
+
+            NextFcb->FcbReference += 1;
+
+            CdUnlockVcb( IrpContext, Vcb );
+
+            CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
+
+            CdLockVcb( IrpContext, Vcb );
+            NextFcb->FcbReference -= 1;
+            CdUnlockVcb( IrpContext, Vcb );
+
+        } else {
+
+            CdUnlockVcb( IrpContext, Vcb );
+        }
+
+        UnlockVcb = FALSE;
+
+        //
+        //  Move to this Fcb.
+        //
+
+        *CurrentFcb = NextFcb;
+
+        //
+        //  Check the requested access on this Fcb.
+        //
+
+        if (!CdIllegalFcbAccess( IrpContext,
+                                 TypeOfOpen,
+                                 IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
+
+            //
+            //  Call our worker routine to complete the open.
+            //
+
+            Status = CdCompleteFcbOpen( IrpContext,
+                                        IrpSp,
+                                        Vcb,
+                                        CurrentFcb,
+                                        TypeOfOpen,
+                                        CCB_FLAG_OPEN_BY_ID,
+                                        IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
+        }
+
+    try_exit:  NOTHING;
+    } finally {
+
+        if (UnlockVcb) {
+
+            CdUnlockVcb( IrpContext, Vcb );
+        }
+
+        if (CleanupFileContext) {
+
+            CdCleanupFileContext( IrpContext, &FileContext );
+        }
+
+        if (CleanupCompoundPathEntry) {
+
+            CdCleanupCompoundPathEntry( IrpContext, &CompoundPathEntry );
+        }
+    }
+
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdOpenExistingFcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN OUT PFCB *CurrentFcb,
+    IN TYPE_OF_OPEN TypeOfOpen,
+    IN BOOLEAN IgnoreCase,
+    IN PCCB RelatedCcb OPTIONAL
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to open an Fcb which is already in the Fcb table.
+    We will verify the access to the file and then call our worker routine
+    to perform the final operations.
+
+Arguments:
+
+    IrpSp - Pointer to the stack location for this open.
+
+    CurrentFcb - Address of Fcb to open.  We will clear this if the Fcb
+        is released here.
+
+    TypeOfOpen - Indicates whether we are opening a file, directory or volume.
+
+    IgnoreCase - Indicates if this open is case-insensitive.
+
+    RelatedCcb - Ccb for related file object if relative open.  We use
+        this when setting the Ccb flags for this open.  It will tell
+        us whether the name currently in the file object is relative or
+        absolute.
+
+Return Value:
+
+    NTSTATUS - Status indicating the result of the operation.
+
+--*/
+
+{
+    ULONG CcbFlags = 0;
+
+    NTSTATUS Status = STATUS_ACCESS_DENIED;
+
+    PAGED_CODE();
+
+    //
+    //  Check that the desired access is legal.
+    //
+
+    if (!CdIllegalFcbAccess( IrpContext,
+                             TypeOfOpen,
+                             IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
+
+        //
+        //  Set the Ignore case.
+        //
+
+        if (IgnoreCase) {
+
+            SetFlag( CcbFlags, CCB_FLAG_IGNORE_CASE );
+        }
+
+        //
+        //  Check the related Ccb to see if this was an OpenByFileId and
+        //  whether there was a version.
+        //
+
+        if (ARGUMENT_PRESENT( RelatedCcb )) {
+
+            SetFlag( CcbFlags, FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_WITH_VERSION ));
+
+
+            if (FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID | CCB_FLAG_OPEN_RELATIVE_BY_ID )) {
+
+                SetFlag( CcbFlags, CCB_FLAG_OPEN_RELATIVE_BY_ID );
+            }
+        }
+
+        //
+        //  Call our worker routine to complete the open.
+        //
+
+        Status = CdCompleteFcbOpen( IrpContext,
+                                    IrpSp,
+                                    (*CurrentFcb)->Vcb,
+                                    CurrentFcb,
+                                    TypeOfOpen,
+                                    CcbFlags,
+                                    IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
+    }
+
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdOpenDirectoryFromPathEntry (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PVCB Vcb,
+    IN OUT PFCB *CurrentFcb,
+    IN PCD_NAME DirName,
+    IN BOOLEAN IgnoreCase,
+    IN BOOLEAN ShortNameMatch,
+    IN PPATH_ENTRY PathEntry,
+    IN BOOLEAN PerformUserOpen,
+    IN PCCB RelatedCcb OPTIONAL
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to open a directory where the directory was found
+    in the path table.  This routine is called in the case where this is the
+    file to open for the user and where this is an intermediate node in the
+    full path to open.
+
+    We first check that the desired access is legal for a directory.  Then we
+    construct the FileId for this and do a check to see if it is the Fcb
+    Table.  It is always possible that either it was created since or simply
+    wasn't in the prefix table at the time of the prefix table search.
+    Initialize the Fcb and store into the FcbTable if not present.
+
+    Next we will add this to the prefix table of our parent if needed.
+
+    Once we know that the new Fcb has been initialized then we move our pointer
+    in the tree down to this position.
+
+    This routine does not own the Vcb lock on entry.  We must be sure to release
+    it on exit.
+
+Arguments:
+
+    IrpSp - Stack location for this request.
+
+    Vcb - Vcb for this volume.
+
+    CurrentFcb - On input this is the parent of the Fcb to open.  On output we
+        store the Fcb for the file being opened.
+
+    DirName - This is always the exact name used to reach this file.
+
+    IgnoreCase - Indicates the type of case match for the open.
+
+    ShortNameMatch - Indicates if we are opening via the short name.
+
+    PathEntry - Path entry for the entry found.
+
+    PerformUserOpen - TRUE if we are to open this for a user, FALSE otherwise.
+
+    RelatedCcb - RelatedCcb for relative file object used to make this open.
+
+Return Value:
+
+    NTSTATUS - Status indicating the result of the operation.
+
+--*/
+
+{
+    ULONG CcbFlags = 0;
+    FILE_ID FileId;
+
+    BOOLEAN UnlockVcb = FALSE;
+    BOOLEAN FcbExisted;
+
+    PFCB NextFcb;
+    PFCB ParentFcb = NULL;
+
+    NTSTATUS Status = STATUS_SUCCESS; /* ReactOS Change: GCC uninitialized variable */
+
+    PAGED_CODE();
+
+    //
+    //  Check for illegal access to this file.
+    //
+
+    if (PerformUserOpen &&
+        CdIllegalFcbAccess( IrpContext,
+                            UserDirectoryOpen,
+                            IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
+
+        return STATUS_ACCESS_DENIED;
+    }
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Check the related Ccb to see if this was an OpenByFileId.
+        //
+
+        if (ARGUMENT_PRESENT( RelatedCcb ) &&
+            FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID | CCB_FLAG_OPEN_RELATIVE_BY_ID )) {
+
+            CcbFlags = CCB_FLAG_OPEN_RELATIVE_BY_ID;
+        }
+
+        if (IgnoreCase) {
+
+            SetFlag( CcbFlags, CCB_FLAG_IGNORE_CASE );
+        }
+
+        //
+        //  Build the file Id for this file.
+        //
+
+        FileId.QuadPart = 0;
+        CdSetFidPathTableOffset( FileId, PathEntry->PathTableOffset );
+        CdFidSetDirectory( FileId );
+
+        //
+        //  Lock the Vcb so we can examine the Fcb Table.
+        //
+
+        CdLockVcb( IrpContext, Vcb );
+        UnlockVcb = TRUE;
+
+        //
+        //  Get the Fcb for this directory.
+        //
+
+        NextFcb = CdCreateFcb( IrpContext, FileId, CDFS_NTC_FCB_INDEX, &FcbExisted );
+
+        //
+        //  If the Fcb was created here then initialize from the values in the
+        //  path table entry.
+        //
+
+        if (!FcbExisted) {
+
+            CdInitializeFcbFromPathEntry( IrpContext, NextFcb, *CurrentFcb, PathEntry );
+        }
+
+        //
+        //  Now try to acquire the new Fcb without waiting.  We will reference
+        //  the Fcb and retry with wait if unsuccessful.
+        //
+
+        if (!CdAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
+
+            NextFcb->FcbReference += 1;
+
+            CdUnlockVcb( IrpContext, Vcb );
+
+            CdReleaseFcb( IrpContext, *CurrentFcb );
+            CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
+            CdAcquireFcbExclusive( IrpContext, *CurrentFcb, FALSE );
+
+            CdLockVcb( IrpContext, Vcb );
+            NextFcb->FcbReference -= 1;
+            CdUnlockVcb( IrpContext, Vcb );
+
+        } else {
+
+            //
+            //  Unlock the Vcb and move down to this new Fcb.  Remember that we still
+            //  own the parent however.
+            //
+
+            CdUnlockVcb( IrpContext, Vcb );
+        }
+
+        UnlockVcb = FALSE;
+
+        ParentFcb = *CurrentFcb;
+        *CurrentFcb = NextFcb;
+
+        //
+        //  Store this name into the prefix table for the parent.
+        //
+
+        if (ShortNameMatch) {
+
+            //
+            //  Make sure the exact case is always in the tree.
+            //
+
+            CdInsertPrefix( IrpContext,
+                            NextFcb,
+                            DirName,
+                            FALSE,
+                            TRUE,
+                            ParentFcb );
+
+            if (IgnoreCase) {
+
+                CdInsertPrefix( IrpContext,
+                                NextFcb,
+                                DirName,
+                                TRUE,
+                                TRUE,
+                                ParentFcb );
+            }
+
+        } else {
+
+            //
+            //  Make sure the exact case is always in the tree.
+            //
+
+            CdInsertPrefix( IrpContext,
+                            NextFcb,
+                            &PathEntry->CdDirName,
+                            FALSE,
+                            FALSE,
+                            ParentFcb );
+
+            if (IgnoreCase) {
+
+                CdInsertPrefix( IrpContext,
+                                NextFcb,
+                                &PathEntry->CdCaseDirName,
+                                TRUE,
+                                FALSE,
+                                ParentFcb );
+            }
+        }
+
+        //
+        //  Release the parent Fcb at this point.
+        //
+
+        CdReleaseFcb( IrpContext, ParentFcb );
+        ParentFcb = NULL;
+
+        //
+        //  Call our worker routine to complete the open.
+        //
+
+        if (PerformUserOpen) {
+
+            Status = CdCompleteFcbOpen( IrpContext,
+                                        IrpSp,
+                                        Vcb,
+                                        CurrentFcb,
+                                        UserDirectoryOpen,
+                                        CcbFlags,
+                                        IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
+        }
+
+    } finally {
+
+        //
+        //  Unlock the Vcb if held.
+        //
+
+        if (UnlockVcb) {
+
+            CdUnlockVcb( IrpContext, Vcb );
+        }
+
+        //
+        //  Release the parent if held.
+        //
+
+        if (ParentFcb != NULL) {
+
+            CdReleaseFcb( IrpContext, ParentFcb );
+        }
+    }
+
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdOpenFileFromFileContext (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PVCB Vcb,
+    IN OUT PFCB *CurrentFcb,
+    IN PCD_NAME FileName,
+    IN BOOLEAN IgnoreCase,
+    IN BOOLEAN ShortNameMatch,
+    IN PFILE_ENUM_CONTEXT FileContext,
+    IN PCCB RelatedCcb OPTIONAL
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to open a file where the file was found in a directory scan.
+    This should only be for a file in the case since we will find the directories in the
+    path table.
+
+    We first check that the desired access is legal for this file.  Then we
+    construct the FileId for this and do a check to see if it is the Fcb
+    Table.  It is always possible that either it was created since or simply
+    wasn't in the prefix table at the time of the prefix table search.
+    Initialize the Fcb and store into the FcbTable if not present.
+
+    Next we will add this to the prefix table of our parent if needed.
+
+    Once we know that the new Fcb has been initialized then we move our pointer
+    in the tree down to this position.
+
+    This routine does not own the Vcb lock on entry.  We must be sure to release
+    it on exit.
+
+Arguments:
+
+    IrpSp - Stack location for this request.
+
+    Vcb - Vcb for the current volume.
+
+    CurrentFcb - On input this is the parent of the Fcb to open.  On output we
+        store the Fcb for the file being opened.
+
+    FileName - This is always the exact name used to reach this file.
+
+    IgnoreCase - Indicates the type of case of CaseName above.
+
+    ShortNameMatch - Indicates if we are opening via the short name.
+
+    FileContext - This is the context used to find the file.
+
+    RelatedCcb - RelatedCcb for relative file object used to make this open.
+
+Return Value:
+
+    NTSTATUS - Status indicating the result of the operation.
+
+--*/
+
+{
+    ULONG CcbFlags = 0;
+    FILE_ID FileId;
+
+    BOOLEAN UnlockVcb = FALSE;
+    BOOLEAN FcbExisted;
+
+    PFCB NextFcb;
+    PFCB ParentFcb = NULL;
+
+    NTSTATUS Status;
+
+    PAGED_CODE();
+
+    //
+    //  Check for illegal access to this file.
+    //
+
+    if (CdIllegalFcbAccess( IrpContext,
+                            UserFileOpen,
+                            IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
+
+        return STATUS_ACCESS_DENIED;
+    }
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Check if a version number was used to open this file.
+        //
+
+        if (FileName->VersionString.Length != 0) {
+
+            SetFlag( CcbFlags, CCB_FLAG_OPEN_WITH_VERSION );
+        }
+
+        //
+        //  Check the related Ccb to see if this was an OpenByFileId.
+        //
+
+        if (ARGUMENT_PRESENT( RelatedCcb ) &&
+            FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID | CCB_FLAG_OPEN_RELATIVE_BY_ID )) {
+
+            SetFlag( CcbFlags, CCB_FLAG_OPEN_RELATIVE_BY_ID );
+        }
+
+        if (IgnoreCase) {
+
+            SetFlag( CcbFlags, CCB_FLAG_IGNORE_CASE );
+        }
+
+        //
+        //  Build the file Id for this file.  We can use the path table offset from the
+        //  parent and the directory offset from the dirent.
+        //
+
+        CdSetFidPathTableOffset( FileId, CdQueryFidPathTableOffset( (*CurrentFcb)->FileId ));
+        CdSetFidDirentOffset( FileId, FileContext->InitialDirent->Dirent.DirentOffset );
+
+        //
+        //  Lock the Vcb so we can examine the Fcb Table.
+        //
+
+        CdLockVcb( IrpContext, Vcb );
+        UnlockVcb = TRUE;
+
+        //
+        //  Get the Fcb for this file.
+        //
+
+        NextFcb = CdCreateFcb( IrpContext, FileId, CDFS_NTC_FCB_DATA, &FcbExisted );
+
+        //
+        //  If the Fcb was created here then initialize from the values in the
+        //  dirent.
+        //
+
+        if (!FcbExisted) {
+
+            CdInitializeFcbFromFileContext( IrpContext,
+                                            NextFcb,
+                                            *CurrentFcb,
+                                            FileContext );
+        }
+
+        //
+        //  Now try to acquire the new Fcb without waiting.  We will reference
+        //  the Fcb and retry with wait if unsuccessful.
+        //
+
+        if (!CdAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
+
+            NextFcb->FcbReference += 1;
+
+            CdUnlockVcb( IrpContext, Vcb );
+
+            CdReleaseFcb( IrpContext, *CurrentFcb );
+            CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
+            CdAcquireFcbExclusive( IrpContext, *CurrentFcb, FALSE );
+
+            CdLockVcb( IrpContext, Vcb );
+            NextFcb->FcbReference -= 1;
+            CdUnlockVcb( IrpContext, Vcb );
+
+        } else {
+
+            //
+            //  Unlock the Vcb and move down to this new Fcb.  Remember that we still
+            //  own the parent however.
+            //
+
+            CdUnlockVcb( IrpContext, Vcb );
+        }
+
+        UnlockVcb = FALSE;
+
+        ParentFcb = *CurrentFcb;
+        *CurrentFcb = NextFcb;
+
+        //
+        //  Store this name into the prefix table for the parent.
+        //
+
+
+        if (ShortNameMatch) {
+
+            //
+            //  Make sure the exact case is always in the tree.
+            //
+
+            CdInsertPrefix( IrpContext,
+                            NextFcb,
+                            FileName,
+                            FALSE,
+                            TRUE,
+                            ParentFcb );
+
+            if (IgnoreCase) {
+
+                CdInsertPrefix( IrpContext,
+                                NextFcb,
+                                FileName,
+                                TRUE,
+                                TRUE,
+                                ParentFcb );
+            }
+
+        //
+        //  Insert this into the prefix table if we found this without
+        //  using a version string.
+        //
+
+        } else if (FileName->VersionString.Length == 0) {
+
+            //
+            //  Make sure the exact case is always in the tree.
+            //
+
+            CdInsertPrefix( IrpContext,
+                            NextFcb,
+                            &FileContext->InitialDirent->Dirent.CdFileName,
+                            FALSE,
+                            FALSE,
+                            ParentFcb );
+
+            if (IgnoreCase) {
+
+                CdInsertPrefix( IrpContext,
+                                NextFcb,
+                                &FileContext->InitialDirent->Dirent.CdCaseFileName,
+                                TRUE,
+                                FALSE,
+                                ParentFcb );
+            }
+        }
+
+        //
+        //  Release the parent Fcb at this point.
+        //
+
+        CdReleaseFcb( IrpContext, ParentFcb );
+        ParentFcb = NULL;
+
+        //
+        //  Call our worker routine to complete the open.
+        //
+
+        Status = CdCompleteFcbOpen( IrpContext,
+                                    IrpSp,
+                                    Vcb,
+                                    CurrentFcb,
+                                    UserFileOpen,
+                                    CcbFlags,
+                                    IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
+
+    } finally {
+
+        //
+        //  Unlock the Vcb if held.
+        //
+
+        if (UnlockVcb) {
+
+            CdUnlockVcb( IrpContext, Vcb );
+        }
+
+        //
+        //  Release the parent if held.
+        //
+
+        if (ParentFcb != NULL) {
+
+            CdReleaseFcb( IrpContext, ParentFcb );
+        }
+    }
+
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdCompleteFcbOpen (
+    IN PIRP_CONTEXT IrpContext,
+    PIO_STACK_LOCATION IrpSp,
+    IN PVCB Vcb,
+    IN OUT PFCB *CurrentFcb,
+    IN TYPE_OF_OPEN TypeOfOpen,
+    IN ULONG UserCcbFlags,
+    IN ACCESS_MASK DesiredAccess
+    )
+
+/*++
+
+Routine Description:
+
+    This is the worker routine which takes an existing Fcb and completes
+    the open.  We will do any necessary oplock checks and sharing checks.
+    Finally we will create the Ccb and update the file object and any
+    file object flags.
+
+Arguments:
+
+    IrpSp - Stack location for the current request.
+
+    Vcb - Vcb for the current volume.
+
+    CurrentFcb - Address of pointer to Fcb to open.  We clear this field if
+        we release the resource for this file.
+
+    TypeOfOpen - Type of open for this request.
+
+    UserCcbFlags - Flags to OR into the Ccb flags.
+
+    DesiredAccess - Desired access for this open.
+
+Return Value:
+
+    NTSTATUS - STATUS_SUCCESS if we complete this request, STATUS_PENDING if
+        the oplock package takes the Irp or SHARING_VIOLATION if there is a
+        sharing check conflict.
+
+--*/
+
+{
+    NTSTATUS Status;
+    NTSTATUS OplockStatus  = STATUS_SUCCESS;
+    ULONG Information = FILE_OPENED;
+
+    BOOLEAN LockVolume = FALSE;
+
+    PFCB Fcb = *CurrentFcb;
+    PCCB Ccb;
+
+    PAGED_CODE();
+
+    //
+    //  Expand maximum allowed to something sensible for share access checking
+    //
+
+    if (MAXIMUM_ALLOWED == DesiredAccess)  {
+    
+        DesiredAccess = FILE_ALL_ACCESS & ~((TypeOfOpen != UserVolumeOpen ?
+                                             (FILE_WRITE_ATTRIBUTES           |
+                                              FILE_WRITE_DATA                 |
+                                              FILE_WRITE_EA                   |
+                                              FILE_ADD_FILE                   |                     
+                                              FILE_ADD_SUBDIRECTORY           |
+                                              FILE_APPEND_DATA) : 0)          |
+                                            FILE_DELETE_CHILD                 |
+                                            DELETE                            |
+                                            WRITE_DAC );
+    }
+
+    //
+    //  If this a volume open and the user wants to lock the volume then
+    //  purge and lock the volume.
+    //
+
+    if ((TypeOfOpen <= UserVolumeOpen) &&
+        !FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_READ )) {
+
+        //
+        //  If there are open handles then fail this immediately.
+        //
+
+        if (Vcb->VcbCleanup != 0) {
+
+            return STATUS_SHARING_VIOLATION;
+        }
+
+        //
+        //  If we can't wait then force this to be posted.
+        //
+
+        if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
+
+            CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
+        }
+
+        LockVolume = TRUE;
+
+        //
+        //  Purge the volume and make sure all of the user references
+        //  are gone.
+        //
+
+        Status = CdPurgeVolume( IrpContext, Vcb, FALSE );
+
+        if (Status != STATUS_SUCCESS) {
+
+            return Status;
+        }
+
+        //
+        //  Now force all of the delayed close operations to go away.
+        //
+
+        CdFspClose( Vcb );
+
+        if (Vcb->VcbUserReference > CDFS_RESIDUAL_USER_REFERENCE) {
+
+            return STATUS_SHARING_VIOLATION;
+        }
+    }
+    
+    //
+    //  If the Fcb already existed then we need to check the oplocks and
+    //  the share access.
+    //
+
+    if (Fcb->FcbCleanup != 0) {
+
+        //
+        //  If this is a user file open then check whether there are any
+        //  batch oplock.
+        //
+
+        if (TypeOfOpen == UserFileOpen) {
+
+            //
+            //  Store the address of the Fcb for a possible teardown into
+            //  the IrpContext.  We will release this in the call to
+            //  prepost the Irp.
+            //
+
+            IrpContext->TeardownFcb = CurrentFcb;
+
+            if (FsRtlCurrentBatchOplock( &Fcb->Oplock )) {
+
+                //
+                //  We remember if a batch oplock break is underway for the
+                //  case where the sharing check fails.
+                //
+
+                Information = FILE_OPBATCH_BREAK_UNDERWAY;
+
+                OplockStatus = FsRtlCheckOplock( &Fcb->Oplock,
+                                                 IrpContext->Irp,
+                                                 IrpContext,
+                                                 (PVOID)CdOplockComplete,   /* ReactOS Change: GCC "assignment from incompatible pointer type" */
+                                                 (PVOID)CdPrePostIrp );   /* ReactOS Change: GCC "assignment from incompatible pointer type" */
+
+                if (OplockStatus == STATUS_PENDING) {
+
+                    return STATUS_PENDING;
+                }
+            }
+
+            //
+            //  Check the share access before breaking any exclusive oplocks.
+            //
+
+            Status = IoCheckShareAccess( DesiredAccess,
+                                         IrpSp->Parameters.Create.ShareAccess,
+                                         IrpSp->FileObject,
+                                         &Fcb->ShareAccess,
+                                         FALSE );
+
+            if (!NT_SUCCESS( Status )) {
+
+                return Status;
+            }
+
+            //
+            //  Now check that we can continue based on the oplock state of the
+            //  file.
+            //
+
+            OplockStatus = FsRtlCheckOplock( &Fcb->Oplock,
+                                             IrpContext->Irp,
+                                             IrpContext,
+                                             (PVOID)CdOplockComplete,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
+                                             (PVOID)CdPrePostIrp );/* ReactOS Change: GCC "assignment from incompatible pointer type" */
+
+            if (OplockStatus == STATUS_PENDING) {
+
+                return STATUS_PENDING;
+            }
+
+            IrpContext->TeardownFcb = NULL;
+
+        //
+        //  Otherwise just do the sharing check.
+        //
+
+        } else {
+
+            Status = IoCheckShareAccess( DesiredAccess,
+                                         IrpSp->Parameters.Create.ShareAccess,
+                                         IrpSp->FileObject,
+                                         &Fcb->ShareAccess,
+                                         FALSE );
+
+            if (!NT_SUCCESS( Status )) {
+
+                return Status;
+            }
+        }
+    }
+
+    //
+    //  Create the Ccb now.
+    //
+
+    Ccb = CdCreateCcb( IrpContext, Fcb, UserCcbFlags );
+
+    //
+    //  Update the share access.
+    //
+
+    if (Fcb->FcbCleanup == 0) {
+
+        IoSetShareAccess( DesiredAccess,
+                          IrpSp->Parameters.Create.ShareAccess,
+                          IrpSp->FileObject,
+                          &Fcb->ShareAccess );
+
+    } else {
+
+        IoUpdateShareAccess( IrpSp->FileObject, &Fcb->ShareAccess );
+    }
+
+    //
+    //  Set the file object type.
+    //
+
+    CdSetFileObject( IrpContext, IrpSp->FileObject, TypeOfOpen, Fcb, Ccb );
+
+    //
+    //  Set the appropriate cache flags for a user file object.
+    //
+
+    if (TypeOfOpen == UserFileOpen) {
+
+        if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING )) {
+
+            SetFlag( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING );
+
+        } else {
+
+            SetFlag( IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED );
+        }
+    }
+    else if (TypeOfOpen == UserVolumeOpen)  {
+
+        SetFlag( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING );
+    }
+
+    //
+    //  Update the open and cleanup counts.  Check the fast io state here.
+    //
+
+    CdLockVcb( IrpContext, Vcb );
+
+    CdIncrementCleanupCounts( IrpContext, Fcb );
+    CdIncrementReferenceCounts( IrpContext, Fcb, 1, 1 );
+
+    if (LockVolume) {
+
+        Vcb->VolumeLockFileObject = IrpSp->FileObject;
+        SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
+    }
+
+    CdUnlockVcb( IrpContext, Vcb );
+
+    CdLockFcb( IrpContext, Fcb );
+
+    if (TypeOfOpen == UserFileOpen) {
+
+        Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
+
+    } else {
+
+        Fcb->IsFastIoPossible = FastIoIsNotPossible;
+    }
+
+    CdUnlockFcb( IrpContext, Fcb );
+
+    //
+    //  Show that we opened the file.
+    //
+
+    IrpContext->Irp->IoStatus.Information = Information;
+
+    //
+    //  Point to the section object pointer in the non-paged Fcb.
+    //
+
+    IrpSp->FileObject->SectionObjectPointer = &Fcb->FcbNonpaged->SegmentObject;
+    return OplockStatus;
+}
+
+
+
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/devctrl.c b/reactos/drivers/filesystems/cdfs_new/devctrl.c
new file mode 100755 (executable)
index 0000000..7efebef
--- /dev/null
@@ -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
+
+\f
+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;
+}
+
+\f
+//
+//  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 );
+}
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/deviosup.c b/reactos/drivers/filesystems/cdfs_new/deviosup.c
new file mode 100755 (executable)
index 0000000..bc737d5
--- /dev/null
@@ -0,0 +1,3612 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    DevIoSup.c
+
+Abstract:
+
+    This module implements the low lever disk read/write support for Cdfs.
+
+
+--*/
+
+#include "CdProcs.h"
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (CDFS_BUG_CHECK_DEVIOSUP)
+
+//
+//  Local structure definitions
+//
+
+//
+//  An array of these structures is passed to CdMultipleAsync describing
+//  a set of runs to execute in parallel.
+//
+
+typedef struct _IO_RUN {
+
+    //
+    //  Disk offset to read from and number of bytes to read.  These
+    //  must be a multiple of 2048 and the disk offset is also a
+    //  multiple of 2048.
+    //
+
+    LONGLONG DiskOffset;
+    ULONG DiskByteCount;
+
+    //
+    //  Current position in user buffer.  This is the final destination for
+    //  this portion of the Io transfer.
+    //
+
+    PVOID UserBuffer;
+
+    //
+    //  Buffer to perform the transfer to.  If this is the same as the
+    //  user buffer above then we are using the user's buffer.  Otherwise
+    //  we either allocated a temporary buffer or are using a different portion
+    //  of the user's buffer.
+    //
+    //  TransferBuffer - Read full sectors into this location.  This can
+    //      be a pointer into the user's buffer at the exact location the
+    //      data should go.  It can also be an earlier point in the user's
+    //      buffer if the complete I/O doesn't start on a sector boundary.
+    //      It may also be a pointer into an allocated buffer.
+    //
+    //  TransferByteCount - Count of bytes to transfer to user's buffer.  A
+    //      value of zero indicates that we did do the transfer into the
+    //      user's buffer directly.
+    //
+    //  TransferBufferOffset - Offset in this buffer to begin the transfer
+    //      to the user's buffer.
+    //
+
+    PVOID TransferBuffer;
+    ULONG TransferByteCount;
+    ULONG TransferBufferOffset;
+
+    //
+    //  This is the Mdl describing the locked pages in memory.  It may
+    //  be allocated to describe the allocated buffer.  Or it may be
+    //  the Mdl in the originating Irp.  The MdlOffset is the offset of
+    //  the current buffer from the beginning of the buffer described by
+    //  the Mdl below.  If the TransferMdl is not the same as the Mdl
+    //  in the user's Irp then we know we have allocated it.
+    //
+
+    PMDL TransferMdl;
+    PVOID TransferVirtualAddress;
+
+    //
+    //  Associated Irp used to perform the Io.
+    //
+
+    PIRP SavedIrp;
+
+} IO_RUN;
+typedef IO_RUN *PIO_RUN;
+
+#define MAX_PARALLEL_IOS            5
+
+//
+//  Local support routines
+//
+
+BOOLEAN
+CdPrepareBuffers (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp,
+    IN PFCB Fcb,
+    IN PVOID UserBuffer,
+    IN ULONG UserBufferOffset,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount,
+    IN PIO_RUN IoRuns,
+    IN PULONG RunCount,
+    IN PULONG ThisByteCount
+    );
+
+VOID
+CdPrepareXABuffers (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp,
+    IN PFCB Fcb,
+    IN PVOID UserBuffer,
+    IN ULONG UserBufferOffset,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount,
+    IN PIO_RUN IoRuns,
+    IN PULONG RunCount,
+    IN PULONG ThisByteCount
+    );
+
+BOOLEAN
+CdFinishBuffers (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_RUN IoRuns,
+    IN ULONG RunCount,
+    IN BOOLEAN FinalCleanup,
+    IN BOOLEAN SaveXABuffer
+    );
+
+VOID
+CdMultipleAsync (
+    IN PIRP_CONTEXT IrpContext,
+    IN ULONG RunCount,
+    IN PIO_RUN IoRuns
+    );
+
+VOID
+CdMultipleXAAsync (
+    IN PIRP_CONTEXT IrpContext,
+    IN ULONG RunCount,
+    IN PIO_RUN IoRuns,
+    IN PRAW_READ_INFO RawReads,
+    IN TRACK_MODE_TYPE TrackMode
+    );
+
+VOID
+CdSingleAsync (
+    IN PIRP_CONTEXT IrpContext,
+    IN LONGLONG ByteOffset,
+    IN ULONG ByteCount
+    );
+
+VOID
+CdWaitSync (
+    IN PIRP_CONTEXT IrpContext
+    );
+
+NTSTATUS
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdMultiSyncCompletionRoutine (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN PVOID Context
+    );
+
+NTSTATUS
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdMultiAsyncCompletionRoutine (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN PVOID Context
+    );
+
+NTSTATUS
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdSingleSyncCompletionRoutine (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN PVOID Context
+    );
+
+NTSTATUS
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdSingleAsyncCompletionRoutine (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN PVOID Context
+    );
+
+VOID
+CdReadAudioSystemFile (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount,
+    IN PVOID SystemBuffer
+    );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdCreateUserMdl)
+#pragma alloc_text(PAGE, CdMultipleAsync)
+#pragma alloc_text(PAGE, CdMultipleXAAsync)
+#pragma alloc_text(PAGE, CdNonCachedRead)
+#pragma alloc_text(PAGE, CdNonCachedXARead)
+#pragma alloc_text(PAGE, CdFinishBuffers)
+#pragma alloc_text(PAGE, CdPerformDevIoCtrl)
+#pragma alloc_text(PAGE, CdPrepareBuffers)
+#pragma alloc_text(PAGE, CdReadAudioSystemFile)
+#pragma alloc_text(PAGE, CdReadSectors)
+#pragma alloc_text(PAGE, CdSingleAsync)
+#pragma alloc_text(PAGE, CdWaitSync)
+#endif
+
+\f
+__inline
+TRACK_MODE_TYPE
+CdFileTrackMode (
+    IN PFCB Fcb
+    )
+
+/*++
+
+Routine Description:
+
+    This routine converts FCB XA file type flags to the track mode
+    used by the device drivers.
+
+Arguments:
+
+    Fcb - Fcb representing the file to read.
+
+Return Value:
+
+    TrackMode of the file represented by the Fcb.
+
+--*/
+{
+    ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE |
+                                   FCB_STATE_MODE2_FILE |
+                                   FCB_STATE_DA_FILE ));
+
+    if (FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE )) {
+
+        return XAForm2;
+
+    } else if (FlagOn( Fcb->FcbState, FCB_STATE_DA_FILE )) {
+
+        return CDDA;
+
+    }
+    
+    //
+    //  FCB_STATE_MODE2_FILE
+    //
+        
+    return YellowMode2;
+}
+
+\f
+NTSTATUS
+CdNonCachedRead (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the non-cached reads to 'cooked' sectors (2048 bytes
+    per sector).  This is done by performing the following in a loop.
+
+        Fill in the IoRuns array for the next block of Io.
+        Send the Io to the device.
+        Perform any cleanup on the Io runs array.
+
+    We will not do async Io to any request that generates non-aligned Io.
+    Also we will not perform async Io if it will exceed the size of our
+    IoRuns array.  These should be the unusual cases but we will raise
+    or return CANT_WAIT in this routine if we detect this case.
+
+Arguments:
+
+    Fcb - Fcb representing the file to read.
+
+    StartingOffset - Logical offset in the file to read from.
+
+    ByteCount - Number of bytes to read.
+
+Return Value:
+
+    NTSTATUS - Status indicating the result of the operation.
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    IO_RUN IoRuns[MAX_PARALLEL_IOS];
+    ULONG RunCount = 0;
+    ULONG CleanupRunCount = 0;
+
+    PVOID UserBuffer;
+    ULONG UserBufferOffset = 0;
+    LONGLONG CurrentOffset = StartingOffset;
+    ULONG RemainingByteCount = ByteCount;
+    ULONG ThisByteCount;
+
+    BOOLEAN Unaligned;
+    BOOLEAN FlushIoBuffers = FALSE;
+    BOOLEAN FirstPass = TRUE;
+
+    PAGED_CODE();
+
+    //
+    //  We want to make sure the user's buffer is locked in all cases.
+    //
+
+    if (IrpContext->Irp->MdlAddress == NULL) {
+
+        CdCreateUserMdl( IrpContext, ByteCount, TRUE );
+    }
+
+    CdMapUserBuffer( IrpContext, &UserBuffer);
+
+    //
+    //  Special case the root directory and path table for a music volume.
+    //
+
+    if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_AUDIO_DISK ) &&
+        ((SafeNodeType( Fcb ) == CDFS_NTC_FCB_INDEX) ||
+         (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE))) {
+
+        CdReadAudioSystemFile( IrpContext,
+                               Fcb,
+                               StartingOffset,
+                               ByteCount,
+                               UserBuffer );
+
+        return STATUS_SUCCESS;
+    }
+
+    //
+    //  Use a try-finally to perform the final cleanup.
+    //
+
+    try {
+
+        //
+        //  Loop while there are more bytes to transfer.
+        //
+
+        do {
+
+            //
+            //  Call prepare buffers to set up the next entries
+            //  in the IoRuns array.  Remember if there are any
+            //  unaligned entries.  This routine will raise CANT_WAIT 
+            //  if there are unaligned entries for an async request.
+            //
+
+            RtlZeroMemory( IoRuns, sizeof( IoRuns ));
+
+            Unaligned = CdPrepareBuffers( IrpContext,
+                                          IrpContext->Irp,
+                                          Fcb,
+                                          UserBuffer,
+                                          UserBufferOffset,
+                                          CurrentOffset,
+                                          RemainingByteCount,
+                                          IoRuns,
+                                          &CleanupRunCount,
+                                          &ThisByteCount );
+
+
+            RunCount = CleanupRunCount;
+
+            //
+            //  If this is an async request and there aren't enough entries
+            //  in the Io array then post the request.
+            //
+
+            if ((ThisByteCount < RemainingByteCount) &&
+                !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
+
+                CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
+            }
+
+            //
+            //  If the entire Io is contained in a single run then
+            //  we can pass the Io down to the driver.  Send the driver down
+            //  and wait on the result if this is synchronous.
+            //
+
+            if ((RunCount == 1) && !Unaligned && FirstPass) {
+
+                CdSingleAsync( IrpContext,
+                               IoRuns[0].DiskOffset,
+                               IoRuns[0].DiskByteCount );
+
+                //
+                //  No cleanup needed for the IoRuns array here.
+                //
+
+                CleanupRunCount = 0;
+
+                //
+                //  Wait if we are synchronous, otherwise return
+                //
+
+                if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
+
+                    CdWaitSync( IrpContext );
+
+                    Status = IrpContext->Irp->IoStatus.Status;
+
+                //
+                //  Our completion routine will free the Io context but
+                //  we do want to return STATUS_PENDING.
+                //
+
+                } else {
+
+                    ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
+                    Status = STATUS_PENDING;
+                }
+
+                try_return( NOTHING );
+            }
+
+            //
+            //  Otherwise we will perform multiple Io to read in the data.
+            //
+
+            CdMultipleAsync( IrpContext, RunCount, IoRuns );
+
+            //
+            //  If this is a synchronous request then perform any necessary
+            //  post-processing.
+            //
+
+            if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
+
+                //
+                //  Wait for the request to complete.
+                //
+
+                CdWaitSync( IrpContext );
+
+                Status = IrpContext->Irp->IoStatus.Status;
+
+                //
+                //  Exit this loop if there is an error.
+                //
+
+                if (!NT_SUCCESS( Status )) {
+
+                    try_return( NOTHING );
+                }
+
+                //
+                //  Perform post read operations on the IoRuns if
+                //  necessary.
+                //
+
+                if (Unaligned &&
+                    CdFinishBuffers( IrpContext, IoRuns, RunCount, FALSE, FALSE )) {
+
+                    FlushIoBuffers = TRUE;
+                }
+                
+                CleanupRunCount = 0;
+
+                //
+                //  Exit this loop if there are no more bytes to transfer
+                //  or we have any error.
+                //
+
+                RemainingByteCount -= ThisByteCount;
+                CurrentOffset += ThisByteCount;
+                UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
+                UserBufferOffset += ThisByteCount;
+
+            //
+            //  Otherwise this is an asynchronous request.  Always return
+            //  STATUS_PENDING.
+            //
+
+            } else {
+
+                ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
+                CleanupRunCount = 0;
+                try_return( Status = STATUS_PENDING );
+                break;
+            }
+
+            FirstPass = FALSE;
+        } while (RemainingByteCount != 0);
+
+        //
+        //  Flush the hardware cache if we performed any copy operations.
+        //
+
+        if (FlushIoBuffers) {
+
+            KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE );
+        }
+
+    try_exit:  NOTHING;
+    } finally {
+
+        //
+        //  Perform final cleanup on the IoRuns if necessary.
+        //
+
+        if (CleanupRunCount != 0) {
+
+            CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE );
+        }
+    }
+
+    return Status;
+}
+
+\f
+NTSTATUS
+CdNonCachedXARead (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the non-cached reads for 'raw' sectors (2352 bytes
+    per sector).  We also prepend a hard-coded RIFF header of 44 bytes to the file.
+    All of this is already reflected in the file size.
+
+    We start by checking whether to prepend any portion of the RIFF header.  Then we check
+    if the last raw sector read was from the beginning portion of this file, deallocating
+    that buffer if necessary.  Finally we do the following in a loop.
+
+        Fill the IoRuns array for the next block of Io.
+        Send the Io to the device driver.
+        Perform any cleanup necessary on the IoRuns array.
+
+    We will not do any async request in this path.  The request would have been
+    posted to a worker thread before getting to this point.
+
+Arguments:
+
+    Fcb - Fcb representing the file to read.
+
+    StartingOffset - Logical offset in the file to read from.
+
+    ByteCount - Number of bytes to read.
+
+Return Value:
+
+    NTSTATUS - Status indicating the result of the operation.
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RIFF_HEADER LocalRiffHeader;
+    PRIFF_HEADER RiffHeader;
+
+    RAW_READ_INFO RawReads[MAX_PARALLEL_IOS];
+    IO_RUN IoRuns[MAX_PARALLEL_IOS];
+    ULONG RunCount = 0;
+    ULONG CleanupRunCount = 0;
+
+    PVOID UserBuffer;
+    ULONG UserBufferOffset = 0;
+    LONGLONG CurrentOffset = StartingOffset;
+    ULONG RemainingByteCount = ByteCount;
+    ULONG ThisByteCount;
+
+    BOOLEAN TryingYellowbookMode2 = FALSE;
+
+    TRACK_MODE_TYPE TrackMode;
+
+    PAGED_CODE();
+
+    //
+    //  We want to make sure the user's buffer is locked in all cases.
+    //
+
+    if (IrpContext->Irp->MdlAddress == NULL) {
+
+        CdCreateUserMdl( IrpContext, ByteCount, TRUE );
+    }
+
+    //
+    //  The byte count was rounded up to a logical sector boundary.  It has
+    //  nothing to do with the raw sectors on disk.  Limit the remaining
+    //  byte count to file size.
+    //
+
+    if (CurrentOffset + RemainingByteCount > Fcb->FileSize.QuadPart) {
+
+        RemainingByteCount = (ULONG) (Fcb->FileSize.QuadPart - CurrentOffset);
+    }
+
+    CdMapUserBuffer( IrpContext, &UserBuffer);
+
+    //
+    //  Use a try-finally to perform the final cleanup.
+    //
+
+    try {
+
+        //
+        //  If the initial offset lies within the RIFF header then copy the
+        //  necessary bytes to the user's buffer.
+        //
+
+        if (CurrentOffset < sizeof( RIFF_HEADER )) {
+
+            //
+            //  Copy the appropriate RIFF header.
+            //
+
+            if (FlagOn( Fcb->FcbState, FCB_STATE_DA_FILE )) {
+
+                //
+                //  Create the pseudo entries for a music disk.
+                //
+
+                if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
+
+                    PAUDIO_PLAY_HEADER AudioPlayHeader;
+                    PTRACK_DATA TrackData;
+                    ULONG SectorCount;
+
+                    AudioPlayHeader = (PAUDIO_PLAY_HEADER) &LocalRiffHeader;
+                    TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber];
+
+                    //
+                    //  Copy the data header into our local buffer.
+                    //
+
+                    RtlCopyMemory( AudioPlayHeader,
+                                   CdAudioPlayHeader,
+                                   sizeof( AUDIO_PLAY_HEADER ));
+
+                    //
+                    //  Copy the serial number into the Id field.  Also
+                    //  the track number in the TOC.
+                    //
+
+                    AudioPlayHeader->DiskID = Fcb->Vcb->Vpb->SerialNumber;
+                    AudioPlayHeader->TrackNumber = TrackData->TrackNumber;
+
+                    //
+                    //  TOC contains MSF (Minute/Second/Frame) addresses.  This is very
+                    //  arcane, and we wind up having to bias around by the size of the
+                    //  leadins and other such silliness to find real live sector addrs.
+                    //
+                    //  One frame == One sector.
+                    //  One second == 75 frames (winds up being a 44.1khz sample)
+                    //
+
+                    //
+                    //  Fill in the address and length fields.
+                    //
+
+                    AudioPlayHeader->TrackAddress[2] = TrackData->Address[1];
+                    AudioPlayHeader->TrackAddress[1] = TrackData->Address[2];
+                    AudioPlayHeader->TrackAddress[0] = TrackData->Address[3];
+
+                    AudioPlayHeader->StartingSector = TrackData->Address[3];
+                    AudioPlayHeader->StartingSector += (TrackData->Address[2] * 75);
+                    AudioPlayHeader->StartingSector += (TrackData->Address[1] * 60 * 75);
+
+                    //
+                    //  Subtract 2 seconds for the block number.
+                    //
+
+                    AudioPlayHeader->StartingSector -= 150;
+
+                    //
+                    //  Go to the next track and find the starting point.
+                    //
+
+                    TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber + 1];
+
+                    AudioPlayHeader->SectorCount = TrackData->Address[3];
+                    AudioPlayHeader->SectorCount += (TrackData->Address[2] * 75);
+                    AudioPlayHeader->SectorCount += (TrackData->Address[1] * 60 * 75);
+
+                    //
+                    //  Bias the sector count by 2 seconds.
+                    //  Check that the offset is at least two seconds.
+                    //
+
+                    if (AudioPlayHeader->SectorCount < 150) {
+
+                        AudioPlayHeader->SectorCount = 0;
+
+                    } else {
+
+                        AudioPlayHeader->SectorCount -= 150;
+                    }
+
+                    //
+                    //  Now compute the difference.  If there is an error then use
+                    //  a length of zero.
+                    //
+
+                    if (AudioPlayHeader->SectorCount < AudioPlayHeader->StartingSector) {
+
+                        AudioPlayHeader->SectorCount = 0;
+
+                    } else {
+
+                        AudioPlayHeader->SectorCount -= AudioPlayHeader->StartingSector;
+                    }
+
+                    //
+                    //  Use the sector count to determine the MSF length.
+                    //
+
+                    SectorCount = AudioPlayHeader->SectorCount;
+
+                    AudioPlayHeader->TrackLength[0] = (UCHAR) (SectorCount % 75);
+                    SectorCount /= 75;
+
+                    AudioPlayHeader->TrackLength[1] = (UCHAR) (SectorCount % 60);
+                    SectorCount /= 60;
+
+                    AudioPlayHeader->TrackLength[2] = (UCHAR) (SectorCount % 60);
+
+                    ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
+
+                    RtlCopyMemory( UserBuffer,
+                                   Add2Ptr( AudioPlayHeader,
+                                            sizeof( RIFF_HEADER ) - ThisByteCount,
+                                            PCHAR ),
+                                   ThisByteCount );
+
+                //
+                //  CD-XA CDDA
+                //
+
+                } else {
+
+                    //
+                    //  The WAVE header format is actually much closer to an audio play
+                    //  header in format but we only need to modify the filesize fields.
+                    //
+
+                    RiffHeader = &LocalRiffHeader;
+
+                    //
+                    //  Copy the data header into our local buffer and add the file size to it.
+                    //
+
+                    RtlCopyMemory( RiffHeader,
+                                   CdXAAudioPhileHeader,
+                                   sizeof( RIFF_HEADER ));
+
+                    RiffHeader->ChunkSize += Fcb->FileSize.LowPart;
+                    RiffHeader->RawSectors += Fcb->FileSize.LowPart;
+
+                    ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
+                    RtlCopyMemory( UserBuffer,
+                                   Add2Ptr( RiffHeader,
+                                            sizeof( RIFF_HEADER ) - ThisByteCount,
+                                            PCHAR ),
+                                   ThisByteCount );
+                }
+
+            //
+            //  CD-XA non-audio
+            //
+            
+            } else { 
+    
+                ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2_FILE | FCB_STATE_MODE2FORM2_FILE ));
+
+                RiffHeader = &LocalRiffHeader;
+
+                //
+                //  Copy the data header into our local buffer and add the file size to it.
+                //
+
+                RtlCopyMemory( RiffHeader,
+                               CdXAFileHeader,
+                               sizeof( RIFF_HEADER ));
+
+                RiffHeader->ChunkSize += Fcb->FileSize.LowPart;
+                RiffHeader->RawSectors += Fcb->FileSize.LowPart;
+
+                RiffHeader->Attributes = (USHORT) Fcb->XAAttributes;
+                RiffHeader->FileNumber = (UCHAR) Fcb->XAFileNumber;
+
+                ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
+                RtlCopyMemory( UserBuffer,
+                               Add2Ptr( RiffHeader,
+                                        sizeof( RIFF_HEADER ) - ThisByteCount,
+                                        PCHAR ),
+                               ThisByteCount );
+            }
+
+            //
+            //  Adjust the starting offset and byte count to reflect that
+            //  we copied over the RIFF bytes.
+            //
+
+            UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
+            UserBufferOffset += ThisByteCount;
+            CurrentOffset += ThisByteCount;
+            RemainingByteCount -= ThisByteCount;
+        }
+
+        //
+        //  Set up the appropriate trackmode
+        //
+
+        TrackMode = CdFileTrackMode(Fcb);
+
+        //
+        //  Loop while there are more bytes to transfer.
+        //
+
+        while (RemainingByteCount != 0) {
+
+            //
+            //  Call prepare buffers to set up the next entries
+            //  in the IoRuns array.  Remember if there are any
+            //  unaligned entries.  If we're just retrying the previous
+            //  runs with a different track mode,  then don't do anything here.
+            //
+
+            if (!TryingYellowbookMode2)  {
+            
+                RtlZeroMemory( IoRuns, sizeof( IoRuns ));
+                RtlZeroMemory( RawReads, sizeof( RawReads ));
+
+                CdPrepareXABuffers( IrpContext,
+                                    IrpContext->Irp,
+                                    Fcb,
+                                    UserBuffer,
+                                    UserBufferOffset,
+                                    CurrentOffset,
+                                    RemainingByteCount,
+                                    IoRuns,
+                                    &CleanupRunCount,
+                                    &ThisByteCount );
+            }
+            
+            //
+            //  Perform multiple Io to read in the data.  Note that
+            //  there may be no Io to do if we were able to use an
+            //  existing buffer from the Vcb.
+            //
+
+            if (CleanupRunCount != 0) {
+
+                RunCount = CleanupRunCount;
+
+                CdMultipleXAAsync( IrpContext,
+                                   RunCount,
+                                   IoRuns,
+                                   RawReads,
+                                   TrackMode );
+                //
+                //  Wait for the request to complete.
+                //
+
+                CdWaitSync( IrpContext );
+
+                Status = IrpContext->Irp->IoStatus.Status;
+
+                //
+                //  Exit this loop if there is an error.
+                //
+
+                if (!NT_SUCCESS( Status )) {
+
+                    if (!TryingYellowbookMode2 && 
+                        FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE )) {
+
+                        //
+                        //  There are wacky cases where someone has mastered as CD-XA
+                        //  but the sectors they claim are Mode2Form2 are really, according
+                        //  to ATAPI devices, Yellowbook Mode2. We will try once more
+                        //  with these. Kodak PHOTO-CD has been observed to do this.
+                        //
+
+                        TryingYellowbookMode2 = TRUE;
+                        TrackMode = YellowMode2;
+                        
+                        //
+                        //  Clear our 'cumulative' error status value
+                        //
+                        
+                        IrpContext->IoContext->Status = STATUS_SUCCESS;
+
+                        continue;
+                    }
+
+                    try_return( NOTHING );
+                }
+                
+                CleanupRunCount = 0;
+                
+                if (TryingYellowbookMode2) {
+
+                    //
+                    //  We succesfully got data when we tried switching the trackmode,
+                    //  so change the state of the FCB to remember that.
+                    //
+
+                    SetFlag( Fcb->FcbState, FCB_STATE_MODE2_FILE );
+                    ClearFlag( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE );
+
+                    TryingYellowbookMode2 = FALSE;
+                }
+
+                //
+                //  Perform post read operations on the IoRuns if
+                //  necessary.
+                //
+
+                CdFinishBuffers( IrpContext, IoRuns, RunCount, FALSE, TRUE );
+            }
+
+            //
+            //  Adjust our loop variants.
+            //
+
+            RemainingByteCount -= ThisByteCount;
+            CurrentOffset += ThisByteCount;
+            UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
+            UserBufferOffset += ThisByteCount;
+        }
+
+        //
+        //  Always flush the hardware cache.
+        //
+
+        KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE );
+
+    try_exit:  NOTHING;
+    } finally {
+
+        //
+        //  Perform final cleanup on the IoRuns if necessary.
+        //
+
+        if (CleanupRunCount != 0) {
+
+            CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE );
+        }
+    }
+
+    return Status;
+}
+
+\f
+BOOLEAN
+CdReadSectors (
+    IN PIRP_CONTEXT IrpContext,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount,
+    IN BOOLEAN ReturnError,
+    IN OUT PVOID Buffer,
+    IN PDEVICE_OBJECT TargetDeviceObject
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to transfer sectors from the disk to a
+    specified buffer.  It is used for mount and volume verify operations.
+
+    This routine is synchronous, it will not return until the operation
+    is complete or until the operation fails.
+
+    The routine allocates an IRP and then passes this IRP to a lower
+    level driver.  Errors may occur in the allocation of this IRP or
+    in the operation of the lower driver.
+
+Arguments:
+
+    StartingOffset - Logical offset on the disk to start the read.  This
+        must be on a sector boundary, no check is made here.
+
+    ByteCount - Number of bytes to read.  This is an integral number of
+        2K sectors, no check is made here to confirm this.
+
+    ReturnError - Indicates whether we should return TRUE or FALSE
+        to indicate an error or raise an error condition.  This only applies
+        to the result of the IO.  Any other error may cause a raise.
+
+    Buffer - Buffer to transfer the disk data into.
+
+    TargetDeviceObject - The device object for the volume to be read.
+
+Return Value:
+
+    BOOLEAN - Depending on 'RaiseOnError' flag above.  TRUE if operation
+              succeeded, FALSE otherwise.
+
+--*/
+
+{
+    NTSTATUS Status;
+    KEVENT  Event;
+    PIRP Irp;
+
+    PAGED_CODE();
+
+    //
+    //  Initialize the event.
+    //
+
+    KeInitializeEvent( &Event, NotificationEvent, FALSE );
+
+    //
+    //  Attempt to allocate the IRP.  If unsuccessful, raise
+    //  STATUS_INSUFFICIENT_RESOURCES.
+    //
+
+    Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
+                                        TargetDeviceObject,
+                                        Buffer,
+                                        ByteCount,
+                                        (PLARGE_INTEGER) &StartingOffset,
+                                        &Event,
+                                        &IrpContext->Irp->IoStatus );
+
+    if (Irp == NULL) {
+
+        CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
+    }
+
+    //
+    //  Ignore the change line (verify) for mount and verify requests
+    //
+
+    SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
+
+    //
+    //  Send the request down to the driver.  If an error occurs return
+    //  it to the caller.
+    //
+
+    Status = IoCallDriver( TargetDeviceObject, Irp );
+
+    //
+    //  If the status was STATUS_PENDING then wait on the event.
+    //
+
+    if (Status == STATUS_PENDING) {
+
+        Status = KeWaitForSingleObject( &Event,
+                                        Executive,
+                                        KernelMode,
+                                        FALSE,
+                                        NULL );
+
+        //
+        //  On a successful wait pull the status out of the IoStatus block.
+        //
+
+        if (NT_SUCCESS( Status )) {
+
+            Status = IrpContext->Irp->IoStatus.Status;
+        }
+    }
+
+    //
+    //  Check whether we should raise in the error case.
+    //
+
+    if (!NT_SUCCESS( Status )) {
+
+        if (!ReturnError) {
+
+            CdNormalizeAndRaiseStatus( IrpContext, Status );
+        }
+
+        //
+        //  We don't raise, but return FALSE to indicate an error.
+        //
+
+        return FALSE;
+
+    //
+    //  The operation completed successfully.
+    //
+
+    } else {
+
+        return TRUE;
+    }
+}
+
+\f
+NTSTATUS
+CdCreateUserMdl (
+    IN PIRP_CONTEXT IrpContext,
+    IN ULONG BufferLength,
+    IN BOOLEAN RaiseOnError
+    )
+
+/*++
+
+Routine Description:
+
+    This routine locks the specified buffer for read access (we only write into
+    the buffer).  The file system requires this routine since it does not
+    ask the I/O system to lock its buffers for direct I/O.  This routine
+    may only be called from the Fsd while still in the user context.
+
+    This routine is only called if there is not already an Mdl.
+
+Arguments:
+
+    BufferLength - Length of user buffer.
+
+    RaiseOnError - Indicates if our caller wants this routine to raise on
+        an error condition.
+
+Return Value:
+
+    NTSTATUS - Status from this routine.  Error status only returned if
+        RaiseOnError is FALSE.
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
+    PMDL Mdl;
+
+    PAGED_CODE();
+
+    ASSERT_IRP_CONTEXT( IrpContext );
+    ASSERT_IRP( IrpContext->Irp );
+    ASSERT( IrpContext->Irp->MdlAddress == NULL );
+
+    //
+    // Allocate the Mdl, and Raise if we fail.
+    //
+
+    Mdl = IoAllocateMdl( IrpContext->Irp->UserBuffer,
+                         BufferLength,
+                         FALSE,
+                         FALSE,
+                         IrpContext->Irp );
+
+    if (Mdl != NULL) {
+
+        //
+        //  Now probe the buffer described by the Irp.  If we get an exception,
+        //  deallocate the Mdl and return the appropriate "expected" status.
+        //
+
+        try {
+
+            MmProbeAndLockPages( Mdl, IrpContext->Irp->RequestorMode, IoWriteAccess );
+
+            Status = STATUS_SUCCESS;
+
+        } except(EXCEPTION_EXECUTE_HANDLER) {
+
+            Status = GetExceptionCode();
+
+            IoFreeMdl( Mdl );
+            IrpContext->Irp->MdlAddress = NULL;
+
+            if (!FsRtlIsNtstatusExpected( Status )) {
+
+                Status = STATUS_INVALID_USER_BUFFER;
+            }
+        }
+    }
+
+    //
+    //  Check if we are to raise or return
+    //
+
+    if (Status != STATUS_SUCCESS) {
+
+        if (RaiseOnError) {
+
+            CdRaiseStatus( IrpContext, Status );
+        }
+    }
+
+    //
+    //  Return the status code.
+    //
+
+    return Status;
+}
+
+\f
+NTSTATUS
+CdPerformDevIoCtrl (
+    IN PIRP_CONTEXT IrpContext,
+    IN ULONG IoControlCode,
+    IN PDEVICE_OBJECT Device,
+    OUT PVOID OutputBuffer OPTIONAL,
+    IN ULONG OutputBufferLength,
+    IN BOOLEAN InternalDeviceIoControl,
+    IN BOOLEAN OverrideVerify,
+    OUT PIO_STATUS_BLOCK Iosb OPTIONAL
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to perform DevIoCtrl functions internally within
+    the filesystem.  We take the status from the driver and return it to our
+    caller.
+
+Arguments:
+
+    IoControlCode - Code to send to driver.
+
+    Device - This is the device to send the request to.
+
+    OutPutBuffer - Pointer to output buffer.
+
+    OutputBufferLength - Length of output buffer above.
+
+    InternalDeviceIoControl - Indicates if this is an internal or external
+        Io control code.
+
+    OverrideVerify - Indicates if we should tell the driver not to return
+        STATUS_VERIFY_REQUIRED for mount and verify.
+
+    Iosb - If specified, we return the results of the operation here.
+
+Return Value:
+
+    NTSTATUS - Status returned by next lower driver.
+
+--*/
+
+{
+    NTSTATUS Status;
+    PIRP Irp;
+    KEVENT Event;
+    IO_STATUS_BLOCK LocalIosb;
+    PIO_STATUS_BLOCK IosbToUse = &LocalIosb;
+
+    PAGED_CODE();
+
+    //
+    //  Check if the user gave us an Iosb.
+    //
+
+    if (ARGUMENT_PRESENT( Iosb )) {
+
+        IosbToUse = Iosb;
+    }
+
+    IosbToUse->Status = 0;
+    IosbToUse->Information = 0;
+
+    KeInitializeEvent( &Event, NotificationEvent, FALSE );
+
+    Irp = IoBuildDeviceIoControlRequest( IoControlCode,
+                                         Device,
+                                         NULL,
+                                         0,
+                                         OutputBuffer,
+                                         OutputBufferLength,
+                                         InternalDeviceIoControl,
+                                         &Event,
+                                         IosbToUse );
+
+    if (Irp == NULL) {
+
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (OverrideVerify) {
+
+        SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
+    }
+
+    Status = IoCallDriver( Device, Irp );
+
+    //
+    //  We check for device not ready by first checking Status
+    //  and then if status pending was returned, the Iosb status
+    //  value.
+    //
+
+    if (Status == STATUS_PENDING) {
+
+        (VOID) KeWaitForSingleObject( &Event,
+                                      Executive,
+                                      KernelMode,
+                                      FALSE,
+                                      (PLARGE_INTEGER)NULL );
+
+        Status = IosbToUse->Status;
+    }
+
+    ASSERT( !(OverrideVerify && (STATUS_VERIFY_REQUIRED == Status)));
+
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+BOOLEAN
+CdPrepareBuffers (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp,
+    IN PFCB Fcb,
+    IN PVOID UserBuffer,
+    IN ULONG UserBufferOffset,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount,
+    IN PIO_RUN IoRuns,
+    IN PULONG RunCount,
+    IN PULONG ThisByteCount
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is the worker routine which looks up each run of an IO
+    request and stores an entry for it in the IoRuns array.  If the run
+    begins on an unaligned disk boundary then we will allocate a buffer
+    and Mdl for the unaligned portion and put it in the IoRuns entry.
+
+    This routine will raise CANT_WAIT if an unaligned transfer is encountered
+    and this request can't wait.
+
+Arguments:
+
+    Irp - Originating Irp for this request.
+
+    Fcb - This is the Fcb for this data stream.  It may be a file, directory,
+        path table or the volume file.
+
+    UserBuffer - Current position in the user's buffer.
+
+    UserBufferOffset - Offset from the start of the original user buffer.
+
+    StartingOffset - Offset in the stream to begin the read.
+
+    ByteCount - Number of bytes to read.  We will fill the IoRuns array up
+        to this point.  We will stop early if we exceed the maximum number
+        of parallel Ios we support.
+
+    IoRuns - Pointer to the IoRuns array.  The entire array is zeroes when
+        this routine is called.
+
+    RunCount - Number of entries in the IoRuns array filled here.
+
+    ThisByteCount - Number of bytes described by the IoRun entries.  Will
+        not exceed the ByteCount passed in.
+
+Return Value:
+
+    BOOLEAN - TRUE if one of the entries in an unaligned buffer (provided
+        this is synchronous).  FALSE otherwise.
+
+--*/
+
+{
+    BOOLEAN FoundUnaligned = FALSE;
+    PIO_RUN ThisIoRun = IoRuns;
+
+    //
+    //  Following indicate where we are in the current transfer.  Current
+    //  position in the file and number of bytes yet to transfer from
+    //  this position.
+    //
+
+    ULONG RemainingByteCount = ByteCount;
+    LONGLONG CurrentFileOffset = StartingOffset;
+
+    //
+    //  Following indicate the state of the user's buffer.  We have
+    //  the destination of the next transfer and its offset in the
+    //  buffer.  We also have the next available position in the buffer
+    //  available for a scratch buffer.  We will align this up to a sector
+    //  boundary.
+    //
+
+    PVOID CurrentUserBuffer = UserBuffer;
+    ULONG CurrentUserBufferOffset = UserBufferOffset;
+
+    PVOID ScratchUserBuffer = UserBuffer;
+    ULONG ScratchUserBufferOffset = UserBufferOffset;
+
+    //
+    //  The following is the next contiguous bytes on the disk to
+    //  transfer.  Read from the allocation package.
+    //
+
+    LONGLONG DiskOffset;
+    ULONG CurrentByteCount;
+
+    PAGED_CODE();
+
+    //
+    //  Initialize the RunCount and ByteCount.
+    //
+
+    *RunCount = 0;
+    *ThisByteCount = 0;
+
+    //
+    //  Loop while there are more bytes to process or there are
+    //  available entries in the IoRun array.
+    //
+
+    while (TRUE) {
+
+        *RunCount += 1;
+
+        //
+        //  Initialize the current position in the IoRuns array.
+        //  Find the user's buffer for this portion of the transfer.
+        //
+
+        ThisIoRun->UserBuffer = CurrentUserBuffer;
+
+        //
+        //  Find the allocation information for the current offset in the
+        //  stream.
+        //
+
+        CdLookupAllocation( IrpContext,
+                            Fcb,
+                            CurrentFileOffset,
+                            &DiskOffset,
+                            &CurrentByteCount );
+
+        //
+        //  Limit ourselves to the data requested.
+        //
+
+        if (CurrentByteCount > RemainingByteCount) {
+
+            CurrentByteCount = RemainingByteCount;
+        }
+
+        //
+        //  Handle the case where this is an unaligned transfer.  The
+        //  following must all be true for this to be an aligned transfer.
+        //
+        //      Disk offset on a 2048 byte boundary (Start of transfer)
+        //
+        //      Byte count is a multiple of 2048 (Length of transfer)
+        //
+        //      Current buffer offset is also on a 2048 byte boundary.
+        //
+        //  If the ByteCount is at least one sector then do the
+        //  unaligned transfer only for the tail.  We can use the
+        //  user's buffer for the aligned portion.
+        //
+
+        if (FlagOn( (ULONG) DiskOffset, SECTOR_MASK ) ||
+            FlagOn( CurrentUserBufferOffset, SECTOR_MASK ) ||
+            (FlagOn( (ULONG) CurrentByteCount, SECTOR_MASK ) &&
+             (CurrentByteCount < SECTOR_SIZE))) {
+
+            //
+            //  If we can't wait then raise.
+            //
+
+            if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
+
+                CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
+            }
+
+            //
+            //  Remember the offset and the number of bytes out of
+            //  the transfer buffer to copy into the user's buffer.
+            //  We will truncate the current read to end on a sector
+            //  boundary.
+            //
+
+            ThisIoRun->TransferBufferOffset = SectorOffset( DiskOffset );
+
+            //
+            //  Make sure this transfer ends on a sector boundary.
+            //
+
+            ThisIoRun->DiskOffset = LlSectorTruncate( DiskOffset );
+
+            //
+            //  Check if we can use a free portion of the user's buffer.
+            //  If we can copy the bytes to an earlier portion of the
+            //  buffer then read into that location and slide the bytes
+            //  up.
+            //
+            //  We can use the user's buffer if:
+            //
+            //      The temporary location in the buffer is before the
+            //      final destination.
+            //
+            //      There is at least one sector of data to read.
+            //
+
+            if ((ScratchUserBufferOffset + ThisIoRun->TransferBufferOffset < CurrentUserBufferOffset) &&
+                (ThisIoRun->TransferBufferOffset + CurrentByteCount >= SECTOR_SIZE)) {
+
+                ThisIoRun->DiskByteCount = SectorTruncate( ThisIoRun->TransferBufferOffset + CurrentByteCount );
+                CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
+                ThisIoRun->TransferByteCount = CurrentByteCount;
+
+                //
+                //  Point to the user's buffer and Mdl for this transfer.
+                //
+
+                ThisIoRun->TransferBuffer = ScratchUserBuffer;
+                ThisIoRun->TransferMdl = Irp->MdlAddress;
+                ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
+                                                             ScratchUserBufferOffset,
+                                                             PVOID );
+
+                ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
+                                             ThisIoRun->DiskByteCount,
+                                             PVOID );
+
+                ScratchUserBufferOffset += ThisIoRun->DiskByteCount;
+
+            //
+            //  Otherwise we need to allocate an auxilary buffer for the next sector.
+            //
+
+            } else {
+
+                //
+                //  Read up to a page containing the partial data
+                //
+
+                ThisIoRun->DiskByteCount = SectorAlign( ThisIoRun->TransferBufferOffset + CurrentByteCount );
+
+                if (ThisIoRun->DiskByteCount > PAGE_SIZE) {
+
+                    ThisIoRun->DiskByteCount = PAGE_SIZE;
+                }
+
+                if (ThisIoRun->TransferBufferOffset + CurrentByteCount > ThisIoRun->DiskByteCount) {
+
+                    CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
+                }
+
+                ThisIoRun->TransferByteCount = CurrentByteCount;
+
+                //
+                //  Allocate a buffer for the non-aligned transfer.
+                //
+
+                ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
+
+                //
+                //  Allocate and build the Mdl to describe this buffer.
+                //
+
+                ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
+                                                        PAGE_SIZE,
+                                                        FALSE,
+                                                        FALSE,
+                                                        NULL );
+
+                ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
+
+                if (ThisIoRun->TransferMdl == NULL) {
+
+                    IrpContext->Irp->IoStatus.Information = 0;
+                    CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
+                }
+
+                MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
+            }
+
+            //
+            //  Remember we found an unaligned transfer.
+            //
+
+            FoundUnaligned = TRUE;
+
+        //
+        //  Otherwise we use the buffer and Mdl from the original request.
+        //
+
+        } else {
+
+            //
+            //  Truncate the read length to a sector-aligned value.  We know
+            //  the length must be at least one sector or we wouldn't be
+            //  here now.
+            //
+
+            CurrentByteCount = SectorTruncate( CurrentByteCount );
+
+            //
+            //  Read these sectors from the disk.
+            //
+
+            ThisIoRun->DiskOffset = DiskOffset;
+            ThisIoRun->DiskByteCount = CurrentByteCount;
+
+            //
+            //  Use the user's buffer and Mdl as our transfer buffer
+            //  and Mdl.
+            //
+
+            ThisIoRun->TransferBuffer = CurrentUserBuffer;
+            ThisIoRun->TransferMdl = Irp->MdlAddress;
+            ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
+                                                         CurrentUserBufferOffset,
+                                                         PVOID );
+
+            ScratchUserBuffer = Add2Ptr( CurrentUserBuffer,
+                                         CurrentByteCount,
+                                         PVOID );
+
+            ScratchUserBufferOffset += CurrentByteCount;
+        }
+
+        //
+        //  Update our position in the transfer and the RunCount and
+        //  ByteCount for the user.
+        //
+
+        RemainingByteCount -= CurrentByteCount;
+
+        //
+        //  Break out if no more positions in the IoRuns array or
+        //  we have all of the bytes accounted for.
+        //
+
+        *ThisByteCount += CurrentByteCount;
+
+        if ((RemainingByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
+
+            break;
+        }
+
+        //
+        //  Update our pointers for the user's buffer.
+        //
+
+        ThisIoRun += 1;
+        CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentByteCount, PVOID );
+        CurrentUserBufferOffset += CurrentByteCount;
+        CurrentFileOffset += CurrentByteCount;
+    }
+
+    return FoundUnaligned;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdPrepareXABuffers (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp,
+    IN PFCB Fcb,
+    IN PVOID UserBuffer,
+    IN ULONG UserBufferOffset,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount,
+    IN PIO_RUN IoRuns,
+    IN PULONG RunCount,
+    IN PULONG ThisByteCount
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is the worker routine which looks up the individual runs
+    of an IO request and stores an entry for it in the IoRuns array.  The
+    worker routine is for XA files where we need to convert the raw offset
+    in the file to logical cooked sectors.  We store one raw sector in
+    the Vcb.  If the current read is to that sector then we can simply copy
+    whatever bytes are needed from that sector.
+
+Arguments:
+
+    Irp - Originating Irp for this request.
+
+    Fcb - This is the Fcb for this data stream.  It must be a data stream.
+
+    UserBuffer - Current position in the user's buffer.
+
+    UserBufferOffset - Offset of this buffer from the beginning of the user's
+        buffer for the original request.
+
+    StartingOffset - Offset in the stream to begin the read.
+
+    ByteCount - Number of bytes to read.  We will fill the IoRuns array up
+        to this point.  We will stop early if we exceed the maximum number
+        of parallel Ios we support.
+
+    IoRuns - Pointer to the IoRuns array.  The entire array is zeroes when
+        this routine is called.
+
+    RunCount - Number of entries in the IoRuns array filled here.
+
+    ThisByteCount - Number of bytes described by the IoRun entries.  Will
+        not exceed the ByteCount passed in.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PIO_RUN ThisIoRun = IoRuns;
+    BOOLEAN PerformedCopy;
+
+    //
+    //  The following deal with where we are in the range of raw sectors.
+    //  Note that we will bias the input file offset by the RIFF header
+    //  to deal directly with the raw sectors.
+    //
+
+    ULONG RawSectorOffset;
+    ULONG RemainingRawByteCount = ByteCount;
+    LONGLONG CurrentRawOffset = StartingOffset - sizeof( RIFF_HEADER );
+
+    //
+    //  The following is the offset into the cooked sectors for the file.
+    //
+
+    LONGLONG CurrentCookedOffset;
+    ULONG RemainingCookedByteCount;
+
+    //
+    //  Following indicate the state of the user's buffer.  We have
+    //  the destination of the next transfer and its offset in the
+    //  buffer.  We also have the next available position in the buffer
+    //  available for a scratch buffer.
+    //
+
+    PVOID CurrentUserBuffer = UserBuffer;
+    ULONG CurrentUserBufferOffset = UserBufferOffset;
+
+    PVOID ScratchUserBuffer = UserBuffer;
+    ULONG ScratchUserBufferOffset = UserBufferOffset;
+    BOOLEAN RoundScratchBuffer = TRUE;
+
+    //
+    //  The following is the next contiguous bytes on the disk to
+    //  transfer.  These are represented by cooked byte offset and length.
+    //  We also compute the number of raw bytes in the current transfer.
+    //
+
+    LONGLONG DiskOffset;
+    ULONG CurrentCookedByteCount;
+    ULONG CurrentRawByteCount;
+
+    PAGED_CODE();
+
+    //
+    //  We need to maintain our position as we walk through the sectors on the disk.
+    //  We keep separate values for the cooked offset as well as the raw offset.
+    //  These are initialized on sector boundaries and we move through these
+    //  the file sector-by-sector.
+    //
+    //  Try to do 32-bit math.
+    //
+
+    if (((PLARGE_INTEGER) &CurrentRawOffset)->HighPart == 0) {
+
+        //
+        //  Prefix/fast: Note that the following are safe since we only
+        //               take this path for 32bit offsets.
+        //
+
+        CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset / RAW_SECTOR_SIZE);
+
+        CurrentCookedOffset = (LONGLONG) ((ULONG) CurrentRawOffset << SECTOR_SHIFT );
+
+        CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset * RAW_SECTOR_SIZE);
+
+    //
+    //  Otherwise we need to do 64-bit math (sigh).
+    //
+
+    } else {
+
+        CurrentRawOffset /= RAW_SECTOR_SIZE;
+
+        CurrentCookedOffset = CurrentRawOffset << SECTOR_SHIFT;
+
+        CurrentRawOffset *= RAW_SECTOR_SIZE;
+    }
+
+    //
+    //  Now compute the full number of sectors to be read.  Count all of the raw
+    //  sectors that need to be read and convert to cooked bytes.
+    //
+
+    RawSectorOffset = (ULONG) ( StartingOffset - CurrentRawOffset) - sizeof( RIFF_HEADER );
+    CurrentRawByteCount = (RawSectorOffset + RemainingRawByteCount + RAW_SECTOR_SIZE - 1) / RAW_SECTOR_SIZE;
+
+    RemainingCookedByteCount = CurrentRawByteCount << SECTOR_SHIFT;
+
+    //
+    //  Initialize the RunCount and ByteCount.
+    //
+
+    *RunCount = 0;
+    *ThisByteCount = 0;
+
+    //
+    //  Loop while there are more bytes to process or there are
+    //  available entries in the IoRun array.
+    //
+
+    while (TRUE) {
+
+        PerformedCopy = FALSE;
+        *RunCount += 1;
+
+        //
+        //  Round the scratch buffer up to a sector boundary for alignment.
+        //
+
+        if (RoundScratchBuffer) {
+
+            if (SectorOffset( ScratchUserBuffer ) != 0) {
+
+                CurrentRawByteCount = SECTOR_SIZE - SectorOffset( ScratchUserBuffer );
+
+                ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
+                                             CurrentRawByteCount,
+                                             PVOID );
+
+                ScratchUserBufferOffset += CurrentRawByteCount;
+            }
+
+            RoundScratchBuffer = FALSE;
+        }
+
+        //
+        //  Initialize the current position in the IoRuns array.  Find the 
+        //  eventual destination in the user's buffer for this portion of the transfer.
+        //
+
+        ThisIoRun->UserBuffer = CurrentUserBuffer;
+
+        //
+        //  Find the allocation information for the current offset in the
+        //  stream.
+        //
+
+        CdLookupAllocation( IrpContext,
+                            Fcb,
+                            CurrentCookedOffset,
+                            &DiskOffset,
+                            &CurrentCookedByteCount );
+        //
+        //  Maybe we got lucky and this is the same sector as in the
+        //  Vcb.
+        //
+
+        if (DiskOffset == Fcb->Vcb->XADiskOffset) {
+
+            //
+            //  We will perform safe synchronization.  Check again that
+            //  this is the correct sector.
+            //
+
+            CdLockVcb( IrpContext, Fcb->Vcb );
+
+            if ((DiskOffset == Fcb->Vcb->XADiskOffset) &&
+                (Fcb->Vcb->XASector != NULL)) {
+
+                //
+                //  Copy any bytes we can from the current sector.
+                //
+
+                CurrentRawByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
+
+                //
+                //  Check whether we don't go to the end of the sector.
+                //
+
+                if (CurrentRawByteCount > RemainingRawByteCount) {
+
+                    CurrentRawByteCount = RemainingRawByteCount;
+                }
+
+                RtlCopyMemory( CurrentUserBuffer,
+                               Add2Ptr( Fcb->Vcb->XASector, RawSectorOffset, PCHAR ),
+                               CurrentRawByteCount );
+
+                CdUnlockVcb( IrpContext, Fcb->Vcb );
+
+                //
+                //  Adjust the run count and pointer in the IoRuns array
+                //  to show that we didn't use a position.
+                //
+
+                *RunCount -= 1;
+                ThisIoRun -= 1;
+
+                //
+                //  Remember that we performed a copy operation and update
+                //  the next available position in the scratch buffer.
+                //
+
+                PerformedCopy = TRUE;
+
+                ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
+                                             CurrentRawByteCount,
+                                             PVOID );
+
+                ScratchUserBufferOffset += CurrentRawByteCount;
+
+                CurrentCookedByteCount = SECTOR_SIZE;
+
+                //
+                //  Set the flag indicating we want to round the scratch buffer
+                //  to a sector boundary.
+                //
+                
+                RoundScratchBuffer = TRUE;
+
+            } else {
+
+                //
+                //  The safe test showed no available buffer.  Drop down to common code to
+                //  perform the Io.
+                //
+
+                CdUnlockVcb( IrpContext, Fcb->Vcb );
+            }
+        }
+
+        //
+        //  No work in this pass if we did a copy operation.
+        //
+
+        if (!PerformedCopy) {
+
+            //
+            //  Limit ourselves by the number of remaining cooked bytes.
+            //
+
+            if (CurrentCookedByteCount > RemainingCookedByteCount) {
+
+                CurrentCookedByteCount = RemainingCookedByteCount;
+            }
+
+            ThisIoRun->DiskOffset = DiskOffset;
+            ThisIoRun->TransferBufferOffset = RawSectorOffset;
+
+            //
+            //  We will always need to perform copy operations for XA files.
+            //  We allocate an auxillary buffer to read the start of the
+            //  transfer.  Then we can use a range of the user's buffer to
+            //  perform the next range of the transfer.  Finally we may
+            //  need to allocate a buffer for the tail of the transfer.
+            //
+            //  We can use the user's buffer (at the current scratch buffer) if the
+            //  following are true:
+            //
+            //      If we are to store the beginning of the raw sector in the user's buffer.
+            //      The current scratch buffer precedes the destination in the user's buffer 
+            //          (and hence also lies within it)
+            //      There are enough bytes remaining in the buffer for at least one
+            //          raw sector.
+            //
+
+            if ((RawSectorOffset == 0) &&
+                (ScratchUserBufferOffset <= CurrentUserBufferOffset) &&
+                (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount >= RAW_SECTOR_SIZE)) {
+
+                //
+                //  We can use the scratch buffer.  We must ensure we don't send down reads
+                //  greater than the device can handle, since the driver is unable to split
+                //  raw requests.
+                //
+
+                if (CurrentCookedByteCount <= Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE) {
+
+                    CurrentRawByteCount = (SectorAlign( CurrentCookedByteCount) >> SECTOR_SHIFT) * RAW_SECTOR_SIZE;
+    
+                } else {
+
+                    CurrentCookedByteCount = Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE;
+                    CurrentRawByteCount = Fcb->Vcb->MaximumTransferRawSectors * RAW_SECTOR_SIZE;
+                }
+
+                //
+                //  Now make sure we are within the page transfer limit.
+                //
+
+                while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(ScratchUserBuffer, RawSectorAlign( CurrentRawByteCount)) > 
+                       Fcb->Vcb->MaximumPhysicalPages )  {
+
+                    CurrentRawByteCount -= RAW_SECTOR_SIZE;
+                    CurrentCookedByteCount -= SECTOR_SIZE;
+                }
+
+                //
+                //  Trim the number of bytes to read if it won't fit into the current buffer. Take
+                //  account of the fact that we must read in whole raw sector multiples.
+                //
+
+                while ( RawSectorAlign( CurrentRawByteCount) > 
+                        (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount) )  {
+
+                    CurrentRawByteCount -= RAW_SECTOR_SIZE;
+                    CurrentCookedByteCount -= SECTOR_SIZE;
+                }
+
+                //
+                //  Now trim the maximum number of raw bytes to the remaining bytes.
+                //
+
+                if (CurrentRawByteCount > RemainingRawByteCount) {
+
+                    CurrentRawByteCount = RemainingRawByteCount;
+                }
+                
+                //
+                //  Update the IO run array.  We point to the scratch buffer as
+                //  well as the buffer and Mdl in the original Irp.
+                //
+
+                ThisIoRun->DiskByteCount = SectorAlign( CurrentCookedByteCount);
+
+                //
+                //  Store the number of bytes which we actually care about from this transfer
+                //
+                
+                ThisIoRun->TransferByteCount = CurrentRawByteCount;
+
+                //
+                //  Point to the user's buffer and Mdl for this transfer.
+                //
+
+                ThisIoRun->TransferBuffer = ScratchUserBuffer;
+                ThisIoRun->TransferMdl = Irp->MdlAddress;
+                ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer, 
+                                                             ScratchUserBufferOffset,
+                                                             PVOID);
+                //
+                //  Update the scratch buffer pointer.  Note that since the underlying
+                //  driver stack will always transfer in multiples of raw sectors,
+                //  we must round up here rather than simply advancing by the length of the
+                //  of the data which we actually care about.
+                //
+
+                ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
+                                             RawSectorAlign( CurrentRawByteCount),
+                                             PVOID );
+                                             
+                ScratchUserBufferOffset += RawSectorAlign( CurrentRawByteCount);;
+
+                //
+                //  Set the flag indicating we want to round the scratch buffer
+                //  to a cooked sector boundary.
+                //
+
+                RoundScratchBuffer = TRUE;
+
+            } else {
+
+                //
+                //  We need to determine the number of bytes to transfer and the
+                //  offset into this page to begin the transfer.
+                //
+                //  We will transfer only one raw sector.
+                //
+
+                ThisIoRun->DiskByteCount = SECTOR_SIZE;
+
+                CurrentCookedByteCount = SECTOR_SIZE;
+
+                ThisIoRun->TransferByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
+                ThisIoRun->TransferBufferOffset = RawSectorOffset;
+
+                if (ThisIoRun->TransferByteCount > RemainingRawByteCount) {
+
+                    ThisIoRun->TransferByteCount = RemainingRawByteCount;
+                }
+
+                CurrentRawByteCount = ThisIoRun->TransferByteCount;
+
+                //
+                //  We need to allocate an auxillary buffer.  We will allocate
+                //  a single page.  Then we will build an Mdl to describe the buffer.
+                //
+
+                ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
+
+                //
+                //  Allocate and build the Mdl to describe this buffer.
+                //
+
+                ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
+                                                        PAGE_SIZE,
+                                                        FALSE,
+                                                        FALSE,
+                                                        NULL );
+
+                ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
+
+                if (ThisIoRun->TransferMdl == NULL) {
+
+                    IrpContext->Irp->IoStatus.Information = 0;
+                    CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
+                }
+
+                MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
+            }
+        }
+
+        //
+        //  Update the byte count for our caller.
+        //
+
+        RemainingRawByteCount -= CurrentRawByteCount;
+        *ThisByteCount += CurrentRawByteCount;
+
+        //
+        //  Break out if no more positions in the IoRuns array or
+        //  we have all of the bytes accounted for.
+        //
+
+        if ((RemainingRawByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
+
+            break;
+        }
+
+        //
+        //  Update our local pointers to allow for the current range of bytes.
+        //
+
+        ThisIoRun += 1;
+
+        CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentRawByteCount, PVOID );
+        CurrentUserBufferOffset += CurrentRawByteCount;
+
+        RawSectorOffset = 0;
+
+        CurrentCookedOffset += CurrentCookedByteCount;
+        RemainingCookedByteCount -= CurrentCookedByteCount;
+    }
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+BOOLEAN
+CdFinishBuffers (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_RUN IoRuns,
+    IN ULONG RunCount,
+    IN BOOLEAN FinalCleanup,
+    IN BOOLEAN SaveXABuffer
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to perform any data transferred required for
+    unaligned Io or to perform the final cleanup of the IoRuns array.
+
+    In all cases this is where we will deallocate any buffer and mdl
+    allocated to perform the unaligned transfer.  If this is not the
+    final cleanup then we also transfer the bytes to the user buffer
+    and flush the hardware cache.
+
+    We walk backwards through the run array because we may be shifting data
+    in the user's buffer.  Typical case is where we allocated a buffer for
+    the first part of a read and then used the user's buffer for the
+    next section (but stored it at the beginning of the buffer.
+
+Arguments:
+
+    IoRuns - Pointer to the IoRuns array.
+
+    RunCount - Number of entries in the IoRuns array filled here.
+
+    FinalCleanup - Indicates if we should be deallocating temporary buffers
+        (TRUE) or transferring bytes for a unaligned transfers and
+        deallocating the buffers (FALSE).  Flush the system cache if
+        transferring data.
+
+    SaveXABuffer - TRUE if we should try to save an XA buffer, FALSE otherwise
+
+Return Value:
+
+    BOOLEAN - TRUE if this request needs the Io buffers to be flushed, FALSE otherwise.
+
+--*/
+
+{
+    BOOLEAN FlushIoBuffers = FALSE;
+
+    ULONG RemainingEntries = RunCount;
+    PIO_RUN ThisIoRun = &IoRuns[RunCount - 1];
+    PVCB Vcb;
+
+    PAGED_CODE();
+
+    //
+    //  Walk through each entry in the IoRun array.
+    //
+
+    while (RemainingEntries != 0) {
+
+        //
+        //  We only need to deal with the case of an unaligned transfer.
+        //
+
+        if (ThisIoRun->TransferByteCount != 0) {
+
+            //
+            //  If not the final cleanup then transfer the data to the
+            //  user's buffer and remember that we will need to flush
+            //  the user's buffer to memory.
+            //
+
+            if (!FinalCleanup) {
+
+                //
+                //  If we are shifting in the user's buffer then use
+                //  MoveMemory.
+                //
+
+                if (ThisIoRun->TransferMdl == IrpContext->Irp->MdlAddress) {
+
+                    RtlMoveMemory( ThisIoRun->UserBuffer,
+                                   Add2Ptr( ThisIoRun->TransferBuffer,
+                                            ThisIoRun->TransferBufferOffset,
+                                            PVOID ),
+                                   ThisIoRun->TransferByteCount );
+
+                } else {
+
+                    RtlCopyMemory( ThisIoRun->UserBuffer,
+                                   Add2Ptr( ThisIoRun->TransferBuffer,
+                                            ThisIoRun->TransferBufferOffset,
+                                            PVOID ),
+                                   ThisIoRun->TransferByteCount );
+                }
+
+                FlushIoBuffers = TRUE;
+            }
+
+            //
+            //  Free any Mdl we may have allocated.  If the Mdl isn't
+            //  present then we must have failed during the allocation
+            //  phase.
+            //
+
+            if (ThisIoRun->TransferMdl != IrpContext->Irp->MdlAddress) {
+
+                if (ThisIoRun->TransferMdl != NULL) {
+
+                    IoFreeMdl( ThisIoRun->TransferMdl );
+                }
+
+                //
+                //  Now free any buffer we may have allocated.  If the Mdl
+                //  doesn't match the original Mdl then free the buffer.
+                //
+
+                if (ThisIoRun->TransferBuffer != NULL) {
+
+                    //
+                    //  If this is the final buffer for an XA read then store this buffer
+                    //  into the Vcb so that we will have it when reading any remaining
+                    //  portion of this buffer.
+                    //
+
+                    if (SaveXABuffer) {
+
+                        Vcb = IrpContext->Vcb;
+
+                        CdLockVcb( IrpContext, Vcb );
+
+                        if (Vcb->XASector != NULL) {
+
+                            CdFreePool( &Vcb->XASector );
+                        }
+
+                        Vcb->XASector = ThisIoRun->TransferBuffer;
+                        Vcb->XADiskOffset = ThisIoRun->DiskOffset;
+
+                        SaveXABuffer = FALSE;
+
+                        CdUnlockVcb( IrpContext, Vcb );
+
+                    //
+                    //  Otherwise just free the buffer.
+                    //
+
+                    } else {
+
+                        CdFreePool( &ThisIoRun->TransferBuffer );
+                    }
+                }
+            }
+        }
+
+        //
+        //  Now handle the case where we failed in the process
+        //  of allocating associated Irps and Mdls.
+        //
+
+        if (ThisIoRun->SavedIrp != NULL) {
+
+            if (ThisIoRun->SavedIrp->MdlAddress != NULL) {
+
+                IoFreeMdl( ThisIoRun->SavedIrp->MdlAddress );
+            }
+
+            IoFreeIrp( ThisIoRun->SavedIrp );
+        }
+
+        //
+        //  Move to the previous IoRun entry.
+        //
+
+        ThisIoRun -= 1;
+        RemainingEntries -= 1;
+    }
+
+    //
+    //  If we copied any data then flush the Io buffers.
+    //
+
+    return FlushIoBuffers;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdMultipleAsync (
+    IN PIRP_CONTEXT IrpContext,
+    IN ULONG RunCount,
+    IN PIO_RUN IoRuns
+    )
+
+/*++
+
+Routine Description:
+
+    This routine first does the initial setup required of a Master IRP that is
+    going to be completed using associated IRPs.  This routine should not
+    be used if only one async request is needed, instead the single read
+    async routines should be called.
+
+    A context parameter is initialized, to serve as a communications area
+    between here and the common completion routine.
+
+    Next this routine reads or writes one or more contiguous sectors from
+    a device asynchronously, and is used if there are multiple reads for a
+    master IRP.  A completion routine is used to synchronize with the
+    completion of all of the I/O requests started by calls to this routine.
+
+    Also, prior to calling this routine the caller must initialize the
+    IoStatus field in the Context, with the correct success status and byte
+    count which are expected if all of the parallel transfers complete
+    successfully.  After return this status will be unchanged if all requests
+    were, in fact, successful.  However, if one or more errors occur, the
+    IoStatus will be modified to reflect the error status and byte count
+    from the first run (by Vbo) which encountered an error.  I/O status
+    from all subsequent runs will not be indicated.
+
+Arguments:
+
+    RunCount - Supplies the number of multiple async requests
+        that will be issued against the master irp.
+
+    IoRuns - Supplies an array containing the Offset and ByteCount for the
+        separate requests.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    PIO_COMPLETION_ROUTINE CompletionRoutine;
+    PIO_STACK_LOCATION IrpSp;
+    PMDL Mdl;
+    PIRP Irp;
+    PIRP MasterIrp;
+    ULONG UnwindRunCount;
+
+    PAGED_CODE();
+
+    //
+    //  Set up things according to whether this is truely async.
+    //
+
+    CompletionRoutine = CdMultiSyncCompletionRoutine;
+
+    if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
+
+        CompletionRoutine = CdMultiAsyncCompletionRoutine;
+    }
+
+    //
+    //  Initialize some local variables.
+    //
+
+    MasterIrp = IrpContext->Irp;
+
+    //
+    //  Itterate through the runs, doing everything that can fail.
+    //  We let the cleanup in CdFinishBuffers clean up on error.
+    //
+
+    for (UnwindRunCount = 0;
+         UnwindRunCount < RunCount;
+         UnwindRunCount += 1) {
+
+        //
+        //  Create an associated IRP, making sure there is one stack entry for
+        //  us, as well.
+        //
+
+        IoRuns[UnwindRunCount].SavedIrp =
+        Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
+
+        if (Irp == NULL) {
+
+            IrpContext->Irp->IoStatus.Information = 0;
+            CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
+        }
+
+        //
+        // Allocate and build a partial Mdl for the request.
+        //
+
+        Mdl = IoAllocateMdl( IoRuns[UnwindRunCount].TransferVirtualAddress,
+                             IoRuns[UnwindRunCount].DiskByteCount,
+                             FALSE,
+                             FALSE,
+                             Irp );
+
+        if (Mdl == NULL) {
+
+            IrpContext->Irp->IoStatus.Information = 0;
+            CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
+        }
+
+        IoBuildPartialMdl( IoRuns[UnwindRunCount].TransferMdl,
+                           Mdl,
+                           IoRuns[UnwindRunCount].TransferVirtualAddress,
+                           IoRuns[UnwindRunCount].DiskByteCount );
+
+        //
+        //  Get the first IRP stack location in the associated Irp
+        //
+
+        IoSetNextIrpStackLocation( Irp );
+        IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+        //
+        //  Setup the Stack location to describe our read.
+        //
+
+        IrpSp->MajorFunction = IRP_MJ_READ;
+        IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
+        IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
+
+        //
+        // Set up the completion routine address in our stack frame.
+        //
+
+        IoSetCompletionRoutine( Irp,
+                                CompletionRoutine,
+                                IrpContext->IoContext,
+                                TRUE,
+                                TRUE,
+                                TRUE );
+
+        //
+        //  Setup the next IRP stack location in the associated Irp for the disk
+        //  driver beneath us.
+        //
+
+        IrpSp = IoGetNextIrpStackLocation( Irp );
+
+        //
+        //  Setup the Stack location to do a read from the disk driver.
+        //
+
+        IrpSp->MajorFunction = IRP_MJ_READ;
+        IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
+        IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
+    }
+
+    //
+    //  We only need to set the associated IRP count in the master irp to
+    //  make it a master IRP.  But we set the count to one more than our
+    //  caller requested, because we do not want the I/O system to complete
+    //  the I/O.  We also set our own count.
+    //
+
+    IrpContext->IoContext->IrpCount = RunCount;
+    IrpContext->IoContext->MasterIrp = MasterIrp;
+
+    //
+    //  We set the count in the master Irp to 1 since typically we
+    //  will clean up the associated irps ourselves.  Setting this to one
+    //  means completing the last associated Irp with SUCCESS (in the async
+    //  case) will complete the master irp.
+    //
+
+    MasterIrp->AssociatedIrp.IrpCount = 1;
+
+    //
+    //  Now that all the dangerous work is done, issue the Io requests
+    //
+
+    for (UnwindRunCount = 0;
+         UnwindRunCount < RunCount;
+         UnwindRunCount++) {
+
+        Irp = IoRuns[UnwindRunCount].SavedIrp;
+        IoRuns[UnwindRunCount].SavedIrp = NULL;
+
+        //
+        //  If IoCallDriver returns an error, it has completed the Irp
+        //  and the error will be caught by our completion routines
+        //  and dealt with as a normal IO error.
+        //
+
+        (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
+    }
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdMultipleXAAsync (
+    IN PIRP_CONTEXT IrpContext,
+    IN ULONG RunCount,
+    IN PIO_RUN IoRuns,
+    IN PRAW_READ_INFO RawReads,
+    IN TRACK_MODE_TYPE TrackMode
+    )
+
+/*++
+
+Routine Description:
+
+    This routine first does the initial setup required of a Master IRP that is
+    going to be completed using associated IRPs.  This routine is used to generate
+    the associated Irps used to read raw sectors from the disk.
+
+    A context parameter is initialized, to serve as a communications area
+    between here and the common completion routine.
+
+    Next this routine reads or writes one or more contiguous sectors from
+    a device asynchronously, and is used if there are multiple reads for a
+    master IRP.  A completion routine is used to synchronize with the
+    completion of all of the I/O requests started by calls to this routine.
+
+    Also, prior to calling this routine the caller must initialize the
+    IoStatus field in the Context, with the correct success status and byte
+    count which are expected if all of the parallel transfers complete
+    successfully.  After return this status will be unchanged if all requests
+    were, in fact, successful.  However, if one or more errors occur, the
+    IoStatus will be modified to reflect the error status and byte count
+    from the first run (by Vbo) which encountered an error.  I/O status
+    from all subsequent runs will not be indicated.
+
+Arguments:
+
+    RunCount - Supplies the number of multiple async requests
+        that will be issued against the master irp.
+
+    IoRuns - Supplies an array containing the Offset and ByteCount for the
+        separate requests.
+
+    RawReads - Supplies an array of structures to store in the Irps passed to the
+        device driver to perform the low-level Io.
+
+    TrackMode - Supplies the recording mode of sectors in these IoRuns
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    PIO_STACK_LOCATION IrpSp;
+    PMDL Mdl;
+    PIRP Irp;
+    PIRP MasterIrp;
+    ULONG UnwindRunCount;
+    ULONG RawByteCount;
+
+    PIO_RUN ThisIoRun = IoRuns;
+    PRAW_READ_INFO ThisRawRead = RawReads;
+
+    PAGED_CODE();
+
+    //
+    //  Initialize some local variables.
+    //
+
+    MasterIrp = IrpContext->Irp;
+
+    //
+    //  Itterate through the runs, doing everything that can fail.
+    //  We let the cleanup in CdFinishBuffers clean up on error.
+    //
+
+    for (UnwindRunCount = 0;
+         UnwindRunCount < RunCount;
+         UnwindRunCount += 1, ThisIoRun += 1, ThisRawRead += 1) {
+
+        //
+        //  Create an associated IRP, making sure there is one stack entry for
+        //  us, as well.
+        //
+
+        ThisIoRun->SavedIrp =
+        Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
+
+        if (Irp == NULL) {
+
+            IrpContext->Irp->IoStatus.Information = 0;
+            CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
+        }
+        
+        //
+        //  Should have been passed a byte count of at least one sector, and 
+        //  must be a multiple of sector size
+        //
+        
+        ASSERT( ThisIoRun->DiskByteCount && !SectorOffset(ThisIoRun->DiskByteCount));
+
+        RawByteCount = SectorsFromBytes( ThisIoRun->DiskByteCount) * RAW_SECTOR_SIZE;
+
+        //
+        // Allocate and build a partial Mdl for the request.
+        //
+
+        Mdl = IoAllocateMdl( ThisIoRun->TransferVirtualAddress,
+                             RawByteCount,
+                             FALSE,
+                             FALSE,
+                             Irp );
+
+        if (Mdl == NULL) {
+
+            IrpContext->Irp->IoStatus.Information = 0;
+            CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
+        }
+
+        IoBuildPartialMdl( ThisIoRun->TransferMdl,
+                           Mdl,
+                           ThisIoRun->TransferVirtualAddress,
+                           RawByteCount);
+        //
+        //  Get the first IRP stack location in the associated Irp
+        //
+
+        IoSetNextIrpStackLocation( Irp );
+        IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+        //
+        //  Setup the Stack location to describe our read (using cooked values)
+        //  These values won't be used for the raw read in any case.
+        //
+
+        IrpSp->MajorFunction = IRP_MJ_READ;
+        IrpSp->Parameters.Read.Length = ThisIoRun->DiskByteCount;
+        IrpSp->Parameters.Read.ByteOffset.QuadPart = ThisIoRun->DiskOffset;
+
+        //
+        // Set up the completion routine address in our stack frame.
+        //
+
+        IoSetCompletionRoutine( Irp,
+                                CdMultiSyncCompletionRoutine,
+                                IrpContext->IoContext,
+                                TRUE,
+                                TRUE,
+                                TRUE );
+
+        //
+        //  Setup the next IRP stack location in the associated Irp for the disk
+        //  driver beneath us.
+        //
+
+        IrpSp = IoGetNextIrpStackLocation( Irp );
+
+        //
+        //  Setup the stack location to do a read of raw sectors at this location.
+        //  Note that the storage stack always reads multiples of whole XA sectors.
+        //
+
+        ThisRawRead->DiskOffset.QuadPart = ThisIoRun->DiskOffset;
+        ThisRawRead->SectorCount = ThisIoRun->DiskByteCount >> SECTOR_SHIFT;
+        ThisRawRead->TrackMode = TrackMode;
+
+        IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
+
+        IrpSp->Parameters.DeviceIoControl.OutputBufferLength = ThisRawRead->SectorCount * RAW_SECTOR_SIZE;
+        Irp->UserBuffer = ThisIoRun->TransferVirtualAddress;
+
+        IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof( RAW_READ_INFO );
+        IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = ThisRawRead;
+
+        IrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_CDROM_RAW_READ;
+    }
+
+    //
+    //  We only need to set the associated IRP count in the master irp to
+    //  make it a master IRP.  But we set the count to one more than our
+    //  caller requested, because we do not want the I/O system to complete
+    //  the I/O.  We also set our own count.
+    //
+
+    IrpContext->IoContext->IrpCount = RunCount;
+    IrpContext->IoContext->MasterIrp = MasterIrp;
+
+    //
+    //  We set the count in the master Irp to 1 since typically we
+    //  will clean up the associated irps ourselves.  Setting this to one
+    //  means completing the last associated Irp with SUCCESS (in the async
+    //  case) will complete the master irp.
+    //
+
+    MasterIrp->AssociatedIrp.IrpCount = 1;
+
+    //
+    //  Now that all the dangerous work is done, issue the Io requests
+    //
+
+    for (UnwindRunCount = 0;
+         UnwindRunCount < RunCount;
+         UnwindRunCount++) {
+
+        Irp = IoRuns[UnwindRunCount].SavedIrp;
+        IoRuns[UnwindRunCount].SavedIrp = NULL;
+
+        //
+        //
+        //  If IoCallDriver returns an error, it has completed the Irp
+        //  and the error will be caught by our completion routines
+        //  and dealt with as a normal IO error.
+        //
+
+        (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
+    }
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdSingleAsync (
+    IN PIRP_CONTEXT IrpContext,
+    IN LONGLONG ByteOffset,
+    IN ULONG ByteCount
+    )
+
+/*++
+
+Routine Description:
+
+    This routine reads one or more contiguous sectors from a device
+    asynchronously, and is used if there is only one read necessary to
+    complete the IRP.  It implements the read by simply filling
+    in the next stack frame in the Irp, and passing it on.  The transfer
+    occurs to the single buffer originally specified in the user request.
+
+Arguments:
+
+    ByteOffset - Supplies the starting Logical Byte Offset to begin reading from
+
+    ByteCount - Supplies the number of bytes to read from the device
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    PIO_STACK_LOCATION IrpSp;
+    PIO_COMPLETION_ROUTINE CompletionRoutine;
+
+    PAGED_CODE();
+
+    //
+    //  Set up things according to whether this is truely async.
+    //
+
+    if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
+
+        CompletionRoutine = CdSingleSyncCompletionRoutine;
+
+    } else {
+
+        CompletionRoutine = CdSingleAsyncCompletionRoutine;
+    }
+
+    //
+    // Set up the completion routine address in our stack frame.
+    //
+
+    IoSetCompletionRoutine( IrpContext->Irp,
+                            CompletionRoutine,
+                            IrpContext->IoContext,
+                            TRUE,
+                            TRUE,
+                            TRUE );
+
+    //
+    //  Setup the next IRP stack location in the associated Irp for the disk
+    //  driver beneath us.
+    //
+
+    IrpSp = IoGetNextIrpStackLocation( IrpContext->Irp );
+
+    //
+    //  Setup the Stack location to do a read from the disk driver.
+    //
+
+    IrpSp->MajorFunction = IRP_MJ_READ;
+    IrpSp->Parameters.Read.Length = ByteCount;
+    IrpSp->Parameters.Read.ByteOffset.QuadPart = ByteOffset;
+
+    //
+    //  Issue the Io request
+    //
+
+    //
+    //  If IoCallDriver returns an error, it has completed the Irp
+    //  and the error will be caught by our completion routines
+    //  and dealt with as a normal IO error.
+    //
+
+    (VOID)IoCallDriver( IrpContext->Vcb->TargetDeviceObject, IrpContext->Irp );
+
+    //
+    //  And return to our caller
+    //
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdWaitSync (
+    IN PIRP_CONTEXT IrpContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine waits for one or more previously started I/O requests
+    from the above routines, by simply waiting on the event.
+
+Arguments:
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    KeWaitForSingleObject( &IrpContext->IoContext->SyncEvent,
+                           Executive,
+                           KernelMode,
+                           FALSE,
+                           NULL );
+
+    KeClearEvent( &IrpContext->IoContext->SyncEvent );
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdMultiSyncCompletionRoutine (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN PVOID Context
+    )
+
+/*++
+
+Routine Description:
+
+    This is the completion routine for all synchronous reads
+    started via CdMultipleAsynch.
+
+    The completion routine has has the following responsibilities:
+
+        If the individual request was completed with an error, then
+        this completion routine must see if this is the first error
+        and remember the error status in the Context.
+
+        If the IrpCount goes to 1, then it sets the event in the Context
+        parameter to signal the caller that all of the asynch requests
+        are done.
+
+Arguments:
+
+    DeviceObject - Pointer to the file system device object.
+
+    Irp - Pointer to the associated Irp which is being completed.  (This
+        Irp will no longer be accessible after this routine returns.)
+
+    Context - The context parameter which was specified for all of
+        the multiple asynch I/O requests for this MasterIrp.
+
+Return Value:
+
+    The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
+    immediately complete the Master Irp without being in a race condition
+    with the IoCompleteRequest thread trying to decrement the IrpCount in
+    the Master Irp.
+
+--*/
+
+{
+    PCD_IO_CONTEXT IoContext = Context;
+
+    AssertVerifyDeviceIrp( Irp );
+
+    //
+    //  If we got an error (or verify required), remember it in the Irp
+    //
+
+    if (!NT_SUCCESS( Irp->IoStatus.Status )) {
+
+        InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
+        IoContext->MasterIrp->IoStatus.Information = 0;
+    }
+
+    //
+    //  We must do this here since IoCompleteRequest won't get a chance
+    //  on this associated Irp.
+    //
+
+    IoFreeMdl( Irp->MdlAddress );
+    IoFreeIrp( Irp );
+
+    if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
+
+        //
+        //  Update the Master Irp with any error status from the associated Irps.
+        //
+
+        IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
+        KeSetEvent( &IoContext->SyncEvent, 0, FALSE );
+    }
+
+    UNREFERENCED_PARAMETER( DeviceObject );
+
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdMultiAsyncCompletionRoutine (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN PVOID Context
+    )
+
+/*++
+
+Routine Description:
+
+    This is the completion routine for all asynchronous reads
+    started via CdMultipleAsynch.
+
+    The completion routine has has the following responsibilities:
+
+        If the individual request was completed with an error, then
+        this completion routine must see if this is the first error
+        and remember the error status in the Context.
+
+Arguments:
+
+    DeviceObject - Pointer to the file system device object.
+
+    Irp - Pointer to the associated Irp which is being completed.  (This
+        Irp will no longer be accessible after this routine returns.)
+
+    Context - The context parameter which was specified for all of
+             the multiple asynch I/O requests for this MasterIrp.
+
+Return Value:
+
+    Currently always returns STATUS_SUCCESS.
+
+--*/
+
+{
+    PCD_IO_CONTEXT IoContext = Context;
+    /* ReactOS Change: GCC Unused Variable */
+    //PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    AssertVerifyDeviceIrp( Irp );
+    
+    //
+    //  If we got an error (or verify required), remember it in the Irp
+    //
+
+    if (!NT_SUCCESS( Irp->IoStatus.Status )) {
+
+        InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
+    }
+
+    //
+    //  Decrement IrpCount and see if it goes to zero.
+    //
+
+    if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
+
+        //
+        //  Mark the master Irp pending
+        //
+
+        IoMarkIrpPending( IoContext->MasterIrp );
+
+        //
+        //  Update the Master Irp with any error status from the associated Irps.
+        //
+
+        IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
+
+        //
+        //  Update the information field with the correct value.
+        //
+
+        IoContext->MasterIrp->IoStatus.Information = 0;
+
+        if (NT_SUCCESS( IoContext->MasterIrp->IoStatus.Status )) {
+
+            IoContext->MasterIrp->IoStatus.Information = IoContext->RequestedByteCount;
+        }
+
+        //
+        //  Now release the resource
+        //
+
+        ExReleaseResourceForThreadLite( IoContext->Resource,
+                                    IoContext->ResourceThreadId );
+
+        //
+        //  and finally, free the context record.
+        //
+
+        CdFreeIoContext( IoContext );
+
+        //
+        //  Return success in this case.
+        //
+
+        return STATUS_SUCCESS;
+
+    } else {
+
+        //
+        //  We need to cleanup the associated Irp and its Mdl.
+        //
+
+        IoFreeMdl( Irp->MdlAddress );
+        IoFreeIrp( Irp );
+
+        return STATUS_MORE_PROCESSING_REQUIRED;
+    }
+
+    UNREFERENCED_PARAMETER( DeviceObject );
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdSingleSyncCompletionRoutine (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN PVOID Context
+    )
+
+/*++
+
+Routine Description:
+
+    This is the completion routine for all reads started via CdSingleAsynch.
+
+    The completion routine has has the following responsibilities:
+
+        It sets the event in the Context parameter to signal the caller
+        that all of the asynch requests are done.
+
+Arguments:
+
+    DeviceObject - Pointer to the file system device object.
+
+    Irp - Pointer to the Irp for this request.  (This Irp will no longer
+        be accessible after this routine returns.)
+
+    Context - The context parameter which was specified in the call to
+        CdSingleAsynch.
+
+Return Value:
+
+    The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
+    immediately complete the Master Irp without being in a race condition
+    with the IoCompleteRequest thread trying to decrement the IrpCount in
+    the Master Irp.
+
+--*/
+
+{
+    AssertVerifyDeviceIrp( Irp );
+    
+    //
+    //  Store the correct information field into the Irp.
+    //
+
+    if (!NT_SUCCESS( Irp->IoStatus.Status )) {
+
+        Irp->IoStatus.Information = 0;
+    }
+
+    KeSetEvent( &((PCD_IO_CONTEXT)Context)->SyncEvent, 0, FALSE );
+
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdSingleAsyncCompletionRoutine (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN PVOID Context
+    )
+
+/*++
+
+Routine Description:
+
+    This is the completion routine for all asynchronous reads
+    started via CdSingleAsynch.
+
+Arguments:
+
+    DeviceObject - Pointer to the file system device object.
+
+    Irp - Pointer to the Irp for this request.  (This Irp will no longer
+        be accessible after this routine returns.)
+
+    Context - The context parameter which was specified in the call to
+        CdSingleAsynch.
+
+Return Value:
+
+    Currently always returns STATUS_SUCCESS.
+
+--*/
+
+{
+    AssertVerifyDeviceIrp( Irp );
+    
+    //
+    //  Update the information field with the correct value for bytes read.
+    //
+
+    Irp->IoStatus.Information = 0;
+
+    if (NT_SUCCESS( Irp->IoStatus.Status )) {
+
+        Irp->IoStatus.Information = ((PCD_IO_CONTEXT) Context)->RequestedByteCount;
+    }
+
+    //
+    //  Mark the Irp pending
+    //
+
+    IoMarkIrpPending( Irp );
+
+    //
+    //  Now release the resource
+    //
+
+    ExReleaseResourceForThreadLite( ((PCD_IO_CONTEXT) Context)->Resource,
+                                ((PCD_IO_CONTEXT) Context)->ResourceThreadId );
+
+    //
+    //  and finally, free the context record.
+    //
+
+    CdFreeIoContext(  Context ); /* ReactOS Change: GCC "error: invalid lvalue in unary '&'" */
+    return STATUS_SUCCESS;
+
+    UNREFERENCED_PARAMETER( DeviceObject );
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdReadAudioSystemFile (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN LONGLONG StartingOffset,
+    IN ULONG ByteCount,
+    IN PVOID SystemBuffer
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to read the pseudo root directory and path
+    table for a music disk.  We build the individual elements on the
+    stack and copy into the cache buffer.
+
+Arguments:
+
+    Fcb - Fcb representing the file to read.
+
+    StartingOffset - Logical offset in the file to read from.
+
+    ByteCount - Number of bytes to read.
+
+    SystemBuffer - Pointer to buffer to fill in.  This will always be page
+        aligned.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    PRAW_PATH_ISO RawPath;
+    PRAW_DIRENT RawDirent;
+
+    ULONG CurrentTrack;
+    ULONG SectorOffset;
+    ULONG EntryCount;
+    UCHAR TrackOnes;
+    UCHAR TrackTens;
+    PTRACK_DATA ThisTrack;
+
+    LONGLONG CurrentOffset;
+
+    PVOID CurrentSector;
+
+    PSYSTEM_USE_XA SystemUse;
+
+    ULONG BytesToCopy;
+
+    UCHAR LocalBuffer[FIELD_OFFSET( RAW_DIRENT, FileId ) + 12];
+
+    PAGED_CODE();
+
+    //
+    //  If this is the path table then we just need a single entry.
+    //
+
+    if (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE) {
+
+        //
+        //  Sanity check that the offset is zero.
+        //
+
+        ASSERT( StartingOffset == 0 );
+
+        //
+        //  Store a pseudo path entry in our local buffer.
+        //
+
+        RawPath = (PRAW_PATH_ISO) LocalBuffer;
+
+        RtlZeroMemory( RawPath, sizeof( LocalBuffer ));
+
+        RawPath->DirIdLen = 1;
+        RawPath->ParentNum = 1;
+        RawPath->DirId[0] = '\0';
+
+        //
+        //  Now copy to the user's buffer.
+        //
+
+        BytesToCopy = FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2;
+
+        if (BytesToCopy > ByteCount) {
+
+            BytesToCopy = ByteCount;
+        }
+
+        RtlCopyMemory( SystemBuffer,
+                       RawPath,
+                       BytesToCopy );
+
+    //
+    //  We need to deal with the multiple sector case for the root directory.
+    //
+
+    } else {
+
+        //
+        //  Initialize the first track to return to our caller.
+        //
+
+        CurrentTrack = 0;
+
+        //
+        //  If the offset is zero then store the entries for the self and parent
+        //  entries.
+        //
+
+        if (StartingOffset == 0) {
+
+            RawDirent = SystemBuffer;
+
+            //
+            //  Clear all of the fields initially.
+            //
+
+            RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
+
+            //
+            //  Now fill in the interesting fields.
+            //
+
+            RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
+            RawDirent->FileIdLen = 1;
+            RawDirent->FileId[0] = '\0';
+            SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
+
+            //
+            //  Set the time stamp to be Jan 1, 1995
+            //
+
+            RawDirent->RecordTime[0] = 95;
+            RawDirent->RecordTime[1] = 1;
+            RawDirent->RecordTime[2] = 1;
+
+            SectorOffset = RawDirent->DirLen;
+
+            RawDirent = Add2Ptr( RawDirent, SectorOffset, PRAW_DIRENT );
+
+            //
+            //  Clear all of the fields initially.
+            //
+
+            RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
+
+            //
+            //  Now fill in the interesting fields.
+            //
+
+            RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
+            RawDirent->FileIdLen = 1;
+            RawDirent->FileId[0] = '\1';
+            SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
+
+            //
+            //  Set the time stamp to be Jan 1, 1995
+            //
+
+            RawDirent->RecordTime[0] = 95;
+            RawDirent->RecordTime[1] = 1;
+            RawDirent->RecordTime[2] = 1;
+
+            SectorOffset += RawDirent->DirLen;
+            EntryCount = 2;
+
+        //
+        //  Otherwise compute the starting track to write to the buffer.
+        //
+
+        } else {
+
+            //
+            //  Count the tracks in each preceding sector.
+            //
+
+            CurrentOffset = 0;
+
+            do {
+
+                CurrentTrack += CdAudioDirentsPerSector;
+                CurrentOffset += SECTOR_SIZE;
+
+            } while (CurrentOffset < StartingOffset);
+
+            //
+            //  Bias the track count to reflect the two default entries.
+            //
+
+            CurrentTrack -= 2;
+
+            SectorOffset = 0;
+            EntryCount = 0;
+        }
+
+        //
+        //  We now know the first track to return as well as where we are in
+        //  the current sector.  We will walk through sector by sector adding
+        //  the entries for the separate tracks in the TOC.  We will zero
+        //  any sectors or partial sectors without data.
+        //
+
+        CurrentSector = SystemBuffer;
+        BytesToCopy = SECTOR_SIZE;
+
+        //
+        //  Loop for each sector.
+        //
+
+        do {
+
+            //
+            //  Add entries until we reach our threshold for each sector.
+            //
+
+            do {
+
+                //
+                //  If we are beyond the entries in the TOC then exit.
+                //
+
+                if (CurrentTrack >= IrpContext->Vcb->TrackCount) {
+
+                    break;
+                }
+
+                ThisTrack = &IrpContext->Vcb->CdromToc->TrackData[CurrentTrack];
+
+                //
+                //  Point to the current position in the buffer.
+                //
+
+                RawDirent = Add2Ptr( CurrentSector, SectorOffset, PRAW_DIRENT );
+
+                //
+                //  Clear all of the fields initially.
+                //
+
+                RtlZeroMemory( RawDirent, CdAudioDirentSize );
+
+                //
+                //  Now fill in the interesting fields.
+                //
+
+                RawDirent->DirLen = (UCHAR) CdAudioDirentSize;
+                RawDirent->FileIdLen = CdAudioFileNameLength;
+
+                RtlCopyMemory( RawDirent->FileId,
+                               CdAudioFileName,
+                               CdAudioFileNameLength );
+
+                //
+                //  Set the time stamp to be Jan 1, 1995
+                //
+
+                RawDirent->RecordTime[0] = 95;
+                RawDirent->RecordTime[1] = 1;
+                RawDirent->RecordTime[2] = 1;
+
+                //
+                //  Now bias by the values in the TOC.
+                //
+
+                RawDirent->RecordTime[4] = ThisTrack->Address[1] % 60;
+                RawDirent->RecordTime[5] = ThisTrack->Address[2] % 60;
+
+                //
+                //  Put the track number into the file name.
+                //
+
+                TrackTens = TrackOnes = ThisTrack->TrackNumber;
+
+                TrackOnes = (TrackOnes % 10) + '0';
+
+                TrackTens /= 10;
+                TrackTens = (TrackTens % 10) + '0';
+
+                RawDirent->FileId[AUDIO_NAME_TENS_OFFSET] = TrackTens;
+                RawDirent->FileId[AUDIO_NAME_ONES_OFFSET] = TrackOnes;
+
+                SystemUse = Add2Ptr( RawDirent, CdAudioSystemUseOffset, PSYSTEM_USE_XA );
+
+                SystemUse->Attributes = SYSTEM_USE_XA_DA;
+                SystemUse->Signature = SYSTEM_XA_SIGNATURE;
+
+                //
+                //  Store the track number as the file number.
+                //
+
+                SystemUse->FileNumber = (UCHAR) CurrentTrack;
+
+                EntryCount += 1;
+                SectorOffset += CdAudioDirentSize;
+                CurrentTrack += 1;
+
+            } while (EntryCount < CdAudioDirentsPerSector);
+
+            //
+            //  Zero the remaining portion of this buffer.
+            //
+
+            RtlZeroMemory( Add2Ptr( CurrentSector, SectorOffset, PVOID ),
+                           SECTOR_SIZE - SectorOffset );
+
+            //
+            //  Prepare for the next sector.
+            //
+
+            EntryCount = 0;
+            BytesToCopy += SECTOR_SIZE;
+            SectorOffset = 0;
+            CurrentSector = Add2Ptr( CurrentSector, SECTOR_SIZE, PVOID );
+
+        } while (BytesToCopy <= ByteCount);
+    }
+
+    return;
+}
+
diff --git a/reactos/drivers/filesystems/cdfs_new/dirctrl.c b/reactos/drivers/filesystems/cdfs_new/dirctrl.c
new file mode 100755 (executable)
index 0000000..53e9e31
--- /dev/null
@@ -0,0 +1,1523 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    DirCtrl.c
+
+Abstract:
+
+    This module implements the File Directory Control routines for Cdfs called
+    by the Fsd/Fsp dispatch drivers.
+
+
+--*/
+
+#include "CdProcs.h"
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (CDFS_BUG_CHECK_DIRCTRL)
+
+//
+//  Local support routines
+//
+
+NTSTATUS
+CdQueryDirectory (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PFCB Fcb,
+    IN PCCB Ccb
+    );
+
+NTSTATUS
+CdNotifyChangeDirectory (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PCCB Ccb
+    );
+
+VOID
+CdInitializeEnumeration (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PFCB Fcb,
+    IN OUT PCCB Ccb,
+    IN OUT PFILE_ENUM_CONTEXT FileContext,
+    OUT PBOOLEAN ReturnNextEntry,
+    OUT PBOOLEAN ReturnSingleEntry,
+    OUT PBOOLEAN InitialQuery
+    );
+
+BOOLEAN
+CdEnumerateIndex (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCCB Ccb,
+    IN OUT PFILE_ENUM_CONTEXT FileContext,
+    IN BOOLEAN ReturnNextEntry
+    );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdCommonDirControl)
+#pragma alloc_text(PAGE, CdEnumerateIndex)
+#pragma alloc_text(PAGE, CdInitializeEnumeration)
+#pragma alloc_text(PAGE, CdNotifyChangeDirectory)
+#pragma alloc_text(PAGE, CdQueryDirectory)
+#endif
+
+\f
+NTSTATUS
+CdCommonDirControl (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is the entry point for the directory control operations.  These
+    are directory enumerations and directory notify calls.  We verify the
+    user's handle is for a directory and then call the appropriate routine.
+
+Arguments:
+
+    Irp - Irp for this request.
+
+Return Value:
+
+    NTSTATUS - Status returned from the lower level routines.
+
+--*/
+
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PFCB Fcb;
+    PCCB Ccb;
+
+    PAGED_CODE();
+
+    //
+    //  Decode the user file object and fail this request if it is not
+    //  a user directory.
+    //
+
+    if (CdDecodeFileObject( IrpContext,
+                            IrpSp->FileObject,
+                            &Fcb,
+                            &Ccb ) != UserDirectoryOpen) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    //
+    //  We know this is a directory control so we'll case on the
+    //  minor function, and call a internal worker routine to complete
+    //  the irp.
+    //
+
+    switch (IrpSp->MinorFunction) {
+
+    case IRP_MN_QUERY_DIRECTORY:
+
+        Status = CdQueryDirectory( IrpContext, Irp, IrpSp, Fcb, Ccb );
+        break;
+
+    case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
+
+        Status = CdNotifyChangeDirectory( IrpContext, Irp, IrpSp, Ccb );
+        break;
+
+    default:
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
+        Status = STATUS_INVALID_DEVICE_REQUEST;
+        break;
+    }
+
+    return Status;
+}
+
+\f
+//
+//  Local support routines
+//
+
+NTSTATUS
+CdQueryDirectory (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PFCB Fcb,
+    IN PCCB Ccb
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the query directory operation.  It is responsible
+    for either completing of enqueuing the input Irp.  We store the state of the
+    search in the Ccb.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+    IrpSp - Stack location for this Irp.
+
+    Fcb - Fcb for this directory.
+
+    Ccb - Ccb for this directory open.
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG Information = 0;
+
+    ULONG LastEntry = 0;
+    ULONG NextEntry = 0;
+
+    ULONG FileNameBytes;
+    ULONG SeparatorBytes;
+    ULONG VersionStringBytes;
+
+    FILE_ENUM_CONTEXT FileContext;
+    PDIRENT ThisDirent;
+    BOOLEAN InitialQuery;
+    BOOLEAN ReturnNextEntry;
+    BOOLEAN ReturnSingleEntry;
+    BOOLEAN Found;
+    BOOLEAN DoCcbUpdate = FALSE;
+
+    PCHAR UserBuffer;
+    ULONG BytesRemainingInBuffer;
+
+    ULONG BaseLength;
+
+    PFILE_BOTH_DIR_INFORMATION DirInfo = NULL; /* ReactOS Change: GCC Uninit var */
+    PFILE_NAMES_INFORMATION NamesInfo;
+    PFILE_ID_FULL_DIR_INFORMATION IdFullDirInfo;
+    PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo;
+
+    PAGED_CODE();
+
+    //
+    //  Check if we support this search mode.  Also remember the size of the base part of
+    //  each of these structures.
+    //
+
+    switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
+
+    case FileDirectoryInformation:
+
+        BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
+                                   FileName[0] );
+        break;
+
+    case FileFullDirectoryInformation:
+
+        BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
+                                   FileName[0] );
+        break;
+
+    case FileIdFullDirectoryInformation:
+
+        BaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
+                                   FileName[0] );
+        break;
+
+    case FileNamesInformation:
+
+        BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
+                                   FileName[0] );
+        break;
+
+    case FileBothDirectoryInformation:
+
+        BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
+                                   FileName[0] );
+        break;
+
+    case FileIdBothDirectoryInformation:
+
+        BaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
+                                   FileName[0] );
+        break;
+
+    default:
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_INFO_CLASS );
+        return STATUS_INVALID_INFO_CLASS;
+    }
+
+    //
+    //  Get the user buffer.
+    //
+
+    CdMapUserBuffer( IrpContext, &UserBuffer);
+
+    //
+    //  Initialize our search context.
+    //
+
+    CdInitializeFileContext( IrpContext, &FileContext );
+
+    //
+    //  Acquire the directory.
+    //
+
+    CdAcquireFileShared( IrpContext, Fcb );
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Verify the Fcb is still good.
+        //
+
+        CdVerifyFcbOperation( IrpContext, Fcb );
+
+        //
+        //  Start by getting the initial state for the enumeration.  This will set up the Ccb with
+        //  the initial search parameters and let us know the starting offset in the directory
+        //  to search.
+        //
+
+        CdInitializeEnumeration( IrpContext,
+                                 IrpSp,
+                                 Fcb,
+                                 Ccb,
+                                 &FileContext,
+                                 &ReturnNextEntry,
+                                 &ReturnSingleEntry,
+                                 &InitialQuery );
+
+        //
+        //  The current dirent is stored in the InitialDirent field.  We capture
+        //  this here so that we have a valid restart point even if we don't
+        //  find a single entry.
+        //
+
+        ThisDirent = &FileContext.InitialDirent->Dirent;
+
+        //
+        //  At this point we are about to enter our query loop.  We have
+        //  determined the index into the directory file to begin the
+        //  search.  LastEntry and NextEntry are used to index into the user
+        //  buffer.  LastEntry is the last entry we've added, NextEntry is
+        //  current one we're working on.  If NextEntry is non-zero, then
+        //  at least one entry was added.
+        //
+
+        while (TRUE) {
+
+            //
+            //  If the user had requested only a single match and we have
+            //  returned that, then we stop at this point.  We update the Ccb with
+            //  the status based on the last entry returned.
+            //
+
+            if ((NextEntry != 0) && ReturnSingleEntry) {
+
+                DoCcbUpdate = TRUE;
+                try_leave( Status );
+            }
+
+            //
+            //  We try to locate the next matching dirent.  Our search if based on a starting
+            //  dirent offset, whether we should return the current or next entry, whether
+            //  we should be doing a short name search and finally whether we should be
+            //  checking for a version match.
+            //
+
+            Found = CdEnumerateIndex( IrpContext, Ccb, &FileContext, ReturnNextEntry );
+
+            //
+            //  Initialize the value for the next search.
+            //
+
+            ReturnNextEntry = TRUE;
+
+            //
+            //  If we didn't receive a dirent, then we are at the end of the
+            //  directory.  If we have returned any files, we exit with
+            //  success, otherwise we return STATUS_NO_MORE_FILES.
+            //
+
+            if (!Found) {
+
+                if (NextEntry == 0) {
+
+                    Status = STATUS_NO_MORE_FILES;
+
+                    if (InitialQuery) {
+
+                        Status = STATUS_NO_SUCH_FILE;
+                    }
+                }
+
+                DoCcbUpdate = TRUE;
+                try_leave( Status );
+            }
+
+            //
+            //  Remember the dirent for the file we just found.
+            //
+
+            ThisDirent = &FileContext.InitialDirent->Dirent;
+
+            //
+            //  Here are the rules concerning filling up the buffer:
+            //
+            //  1.  The Io system garentees that there will always be
+            //      enough room for at least one base record.
+            //
+            //  2.  If the full first record (including file name) cannot
+            //      fit, as much of the name as possible is copied and
+            //      STATUS_BUFFER_OVERFLOW is returned.
+            //
+            //  3.  If a subsequent record cannot completely fit into the
+            //      buffer, none of it (as in 0 bytes) is copied, and
+            //      STATUS_SUCCESS is returned.  A subsequent query will
+            //      pick up with this record.
+            //
+
+            //
+            //  Let's compute the number of bytes we need to transfer the current entry.
+            //
+
+            SeparatorBytes =
+            VersionStringBytes = 0;
+
+            //
+            //  We can look directly at the dirent that we found.
+            //
+
+            FileNameBytes = ThisDirent->CdFileName.FileName.Length;
+
+            //
+            //  Compute the number of bytes for the version string if
+            //  we will return this. Allow directories with illegal ";".
+            //
+
+            if (((Ccb->SearchExpression.VersionString.Length != 0) ||
+                 (FlagOn(ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY))) &&
+                (ThisDirent->CdFileName.VersionString.Length != 0)) {
+
+                SeparatorBytes = 2;
+
+                VersionStringBytes = ThisDirent->CdFileName.VersionString.Length;
+            }
+
+            //
+            //  If the slot for the next entry would be beyond the length of the
+            //  user's buffer just exit (we know we've returned at least one entry
+            //  already). This will happen when we align the pointer past the end.
+            //
+
+            if (NextEntry > IrpSp->Parameters.QueryDirectory.Length) {
+
+                ReturnNextEntry = FALSE;
+                DoCcbUpdate = TRUE;
+                try_leave( Status = STATUS_SUCCESS );
+            }
+
+            //
+            //  Compute the number of bytes remaining in the buffer.  Round this
+            //  down to a WCHAR boundary so we can copy full characters.
+            //
+
+            BytesRemainingInBuffer = IrpSp->Parameters.QueryDirectory.Length - NextEntry;
+            ClearFlag( BytesRemainingInBuffer, 1 );
+
+            //
+            //  If this won't fit and we have returned a previous entry then just
+            //  return STATUS_SUCCESS.
+            //
+
+            if ((BaseLength + FileNameBytes + SeparatorBytes + VersionStringBytes) > BytesRemainingInBuffer) {
+
+                //
+                //  If we already found an entry then just exit.
+                //
+
+                if (NextEntry != 0) {
+
+                    ReturnNextEntry = FALSE;
+                    DoCcbUpdate = TRUE;
+                    try_leave( Status = STATUS_SUCCESS );
+                }
+
+                //
+                //  Don't even try to return the version string if it doesn't all fit.
+                //  Reduce the FileNameBytes to just fit in the buffer.
+                //
+
+                if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) {
+
+                    FileNameBytes = BytesRemainingInBuffer - BaseLength;
+                }
+
+                //
+                //  Don't return any version string bytes.
+                //
+
+                VersionStringBytes =
+                SeparatorBytes = 0;
+
+                //
+                //  Use a status code of STATUS_BUFFER_OVERFLOW.  Also set
+                //  ReturnSingleEntry so that we will exit the loop at the top.
+                //
+
+                Status = STATUS_BUFFER_OVERFLOW;
+                ReturnSingleEntry = TRUE;
+            }
+
+            //
+            //  Protect access to the user buffer with an exception handler.
+            //  Since (at our request) IO doesn't buffer these requests, we have
+            //  to guard against a user messing with the page protection and other
+            //  such trickery.
+            //
+            
+            try {
+            
+                //
+                //  Zero and initialize the base part of the current entry.
+                //
+
+                RtlZeroMemory( Add2Ptr( UserBuffer, NextEntry, PVOID ),
+                               BaseLength );
+    
+                //
+                //  Now we have an entry to return to our caller.
+                //  We'll case on the type of information requested and fill up
+                //  the user buffer if everything fits.
+                //
+
+                switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
+    
+                case FileBothDirectoryInformation:
+                case FileFullDirectoryInformation:
+                case FileIdBothDirectoryInformation:
+                case FileIdFullDirectoryInformation:
+                case FileDirectoryInformation:
+    
+                    DirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_BOTH_DIR_INFORMATION );
+    
+                    //
+                    //  Use the create time for all the time stamps.
+                    //
+    
+                    CdConvertCdTimeToNtTime( IrpContext,
+                                             FileContext.InitialDirent->Dirent.CdTime,
+                                             &DirInfo->CreationTime );
+    
+                    DirInfo->LastWriteTime = DirInfo->ChangeTime = DirInfo->CreationTime;
+    
+                    //
+                    //  Set the attributes and sizes separately for directories and
+                    //  files.
+                    //
+    
+                    if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {
+    
+                        DirInfo->EndOfFile.QuadPart = DirInfo->AllocationSize.QuadPart = 0;
+    
+                        SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY );
+    
+                    } else {
+    
+                        DirInfo->EndOfFile.QuadPart = FileContext.FileSize;
+                        DirInfo->AllocationSize.QuadPart = LlSectorAlign( FileContext.FileSize );
+                    }
+    
+                    //
+                    //  All Cdrom files are readonly.  We also copy the existence
+                    //  bit to the hidden attribute.
+                    //
+    
+                    SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_READONLY );
+    
+                    if (FlagOn( ThisDirent->DirentFlags,
+                                CD_ATTRIBUTE_HIDDEN )) {
+    
+                        SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
+                    }
+    
+                    DirInfo->FileIndex = ThisDirent->DirentOffset;
+    
+                    DirInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
+    
+                    break;
+    
+                case FileNamesInformation:
+    
+                    NamesInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_NAMES_INFORMATION );
+    
+                    NamesInfo->FileIndex = ThisDirent->DirentOffset;
+    
+                    NamesInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
+    
+                    break;
+
+                /* ReactOS Change: GCC "enumeration value not handled in switch" */
+                default: break;
+                }
+
+                //
+                //  Fill in the FileId
+                //
+
+                switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
+
+                case FileIdBothDirectoryInformation:
+
+                    IdBothDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_BOTH_DIR_INFORMATION );
+                    CdSetFidFromParentAndDirent( IdBothDirInfo->FileId, Fcb, ThisDirent );
+                    break;
+
+                case FileIdFullDirectoryInformation:
+
+                    IdFullDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_FULL_DIR_INFORMATION );
+                    CdSetFidFromParentAndDirent( IdFullDirInfo->FileId, Fcb, ThisDirent );
+                    break;
+
+                default:
+                    break;
+                }
+    
+                //
+                //  Now copy as much of the name as possible.  We also may have a version
+                //  string to copy.
+                //
+    
+                if (FileNameBytes != 0) {
+    
+                    //
+                    //  This is a Unicode name, we can copy the bytes directly.
+                    //
+    
+                    RtlCopyMemory( Add2Ptr( UserBuffer, NextEntry + BaseLength, PVOID ),
+                                   ThisDirent->CdFileName.FileName.Buffer,
+                                   FileNameBytes );
+    
+                    if (SeparatorBytes != 0) {
+    
+                        *(Add2Ptr( UserBuffer,
+                                   NextEntry + BaseLength + FileNameBytes,
+                                   PWCHAR )) = L';';
+    
+                        if (VersionStringBytes != 0) {
+    
+                            RtlCopyMemory( Add2Ptr( UserBuffer,
+                                                    NextEntry + BaseLength + FileNameBytes + sizeof( WCHAR ),
+                                                    PVOID ),
+                                           ThisDirent->CdFileName.VersionString.Buffer,
+                                           VersionStringBytes );
+                        }
+                    }
+                }
+
+                //
+                //  Fill in the short name if we got STATUS_SUCCESS.  The short name
+                //  may already be in the file context.  Otherwise we will check
+                //  whether the long name is 8.3.  Special case the self and parent
+                //  directory names.
+                //
+
+                if ((Status == STATUS_SUCCESS) &&
+                    (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation ||
+                     IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation) &&
+                    (Ccb->SearchExpression.VersionString.Length == 0) &&
+                    !FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) {
+    
+                    //
+                    //  If we already have the short name then copy into the user's buffer.
+                    //
+    
+                    if (FileContext.ShortName.FileName.Length != 0) {
+    
+                        RtlCopyMemory( DirInfo->ShortName,
+                                       FileContext.ShortName.FileName.Buffer,
+                                       FileContext.ShortName.FileName.Length );
+    
+                        DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.Length;
+    
+                    //
+                    //  If the short name length is currently zero then check if
+                    //  the long name is not 8.3.  We can copy the short name in
+                    //  unicode form directly into the caller's buffer.
+                    //
+    
+                    } else {
+    
+                        if (!CdIs8dot3Name( IrpContext,
+                                            ThisDirent->CdFileName.FileName )) {
+    
+                            CdGenerate8dot3Name( IrpContext,
+                                                 &ThisDirent->CdCaseFileName.FileName,
+                                                 ThisDirent->DirentOffset,
+                                                 DirInfo->ShortName,
+                                                 &FileContext.ShortName.FileName.Length );
+    
+                            DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.Length;
+                        }
+                    }
+    
+                }
+
+                //
+                //  Sum the total number of bytes for the information field.
+                //
+
+                FileNameBytes += SeparatorBytes + VersionStringBytes;
+
+                //
+                //  Update the information with the number of bytes stored in the
+                //  buffer.  We quad-align the existing buffer to add any necessary
+                //  pad bytes.
+                //
+
+                Information = NextEntry + BaseLength + FileNameBytes;
+
+                //
+                //  Go back to the previous entry and fill in the update to this entry.
+                //
+
+                *(Add2Ptr( UserBuffer, LastEntry, PULONG )) = NextEntry - LastEntry;
+
+                //
+                //  Set up our variables for the next dirent.
+                //
+
+                InitialQuery = FALSE;
+
+                LastEntry = NextEntry;
+                NextEntry = QuadAlign( Information );
+            
+            } except (EXCEPTION_EXECUTE_HANDLER) {
+
+                  //
+                  //  We had a problem filling in the user's buffer, so stop and
+                  //  fail this request.  This is the only reason any exception
+                  //  would have occured at this level.
+                  //
+                  
+                  Information = 0;
+                  try_leave( Status = GetExceptionCode());
+            }
+        }
+        
+        DoCcbUpdate = TRUE;
+
+    } finally {
+
+        //
+        //  Cleanup our search context - *before* aquiring the FCB mutex exclusive,
+        //  else can block on threads in cdcreateinternalstream/purge which 
+        //  hold the FCB but are waiting for all maps in this stream to be released.
+        //
+
+        CdCleanupFileContext( IrpContext, &FileContext );
+
+        //
+        //  Now we can safely aqure the FCB mutex if we need to.
+        //
+
+        if (DoCcbUpdate && !NT_ERROR( Status )) {
+        
+            //
+            //  Update the Ccb to show the current state of the enumeration.
+            //
+
+            CdLockFcb( IrpContext, Fcb );
+            
+            Ccb->CurrentDirentOffset = ThisDirent->DirentOffset;
+
+            ClearFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
+
+            if (ReturnNextEntry) {
+
+                SetFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
+            }
+
+            CdUnlockFcb( IrpContext, Fcb );
+        }
+
+        //
+        //  Release the Fcb.
+        //
+
+        CdReleaseFile( IrpContext, Fcb );
+    }
+
+    //
+    //  Complete the request here.
+    //
+
+    Irp->IoStatus.Information = Information;
+
+    CdCompleteRequest( IrpContext, Irp, Status );
+    return Status;
+}
+
+\f
+//
+//  Local support routines
+//
+
+NTSTATUS
+CdNotifyChangeDirectory (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PCCB Ccb
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the notify change directory operation.  It is
+    responsible for either completing of enqueuing the input Irp.  Although there
+    will never be a notify signalled on a CDROM disk we still support this call.
+
+    We have already checked that this is not an OpenById handle.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+    IrpSp - Io stack location for this request.
+
+    Ccb - Handle to the directory being watched.
+
+Return Value:
+
+    NTSTATUS - STATUS_PENDING, any other error will raise.
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  Always set the wait bit in the IrpContext so the initial wait can't fail.
+    //
+
+    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
+
+    //
+    //  Acquire the Vcb shared.
+    //
+
+    CdAcquireVcbShared( IrpContext, IrpContext->Vcb, FALSE );
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Verify the Vcb.
+        //
+
+        CdVerifyVcb( IrpContext, IrpContext->Vcb );
+
+        //
+        //  Call the Fsrtl package to process the request.  We cast the
+        //  unicode strings to ansi strings as the dir notify package
+        //  only deals with memory matching.
+        //
+
+        FsRtlNotifyFullChangeDirectory( IrpContext->Vcb->NotifySync,
+                                        &IrpContext->Vcb->DirNotifyList,
+                                        Ccb,
+                                        (PSTRING) &IrpSp->FileObject->FileName,
+                                        BooleanFlagOn( IrpSp->Flags, SL_WATCH_TREE ),
+                                        FALSE,
+                                        IrpSp->Parameters.NotifyDirectory.CompletionFilter,
+                                        Irp,
+                                        NULL,
+                                        NULL );
+
+    } finally {
+
+        //
+        //  Release the Vcb.
+        //
+
+        CdReleaseVcb( IrpContext, IrpContext->Vcb );
+    }
+
+    //
+    //  Cleanup the IrpContext.
+    //
+
+    CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
+
+    return STATUS_PENDING;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdInitializeEnumeration (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIO_STACK_LOCATION IrpSp,
+    IN PFCB Fcb,
+    IN OUT PCCB Ccb,
+    IN OUT PFILE_ENUM_CONTEXT FileContext,
+    OUT PBOOLEAN ReturnNextEntry,
+    OUT PBOOLEAN ReturnSingleEntry,
+    OUT PBOOLEAN InitialQuery
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to initialize the enumeration variables and structures.
+    We look at the state of a previous enumeration from the Ccb as well as any
+    input values from the user.  On exit we will position the FileContext at
+    a file in the directory and let the caller know whether this entry or the
+    next entry should be returned.
+
+Arguments:
+
+    IrpSp - Irp stack location for this request.
+
+    Fcb - Fcb for this directory.
+
+    Ccb - Ccb for the directory handle.
+
+    FileContext - FileContext to use for this enumeration.
+
+    ReturnNextEntry - Address to store whether we should return the entry at
+        the FileContext position or the next entry.
+
+    ReturnSingleEntry - Address to store whether we should only return
+        a single entry.
+
+    InitialQuery - Address to store whether this is the first enumeration
+        query on this handle.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    NTSTATUS Status;
+
+    PUNICODE_STRING FileName;
+    CD_NAME WildCardName;
+    CD_NAME SearchExpression;
+
+    ULONG CcbFlags;
+
+    ULONG DirentOffset;
+    ULONG LastDirentOffset;
+    BOOLEAN KnownOffset;
+
+    BOOLEAN Found;
+
+    PAGED_CODE();
+
+    //
+    //  If this is the initial query then build a search expression from the input
+    //  file name.
+    //
+
+    if (!FlagOn( Ccb->Flags, CCB_FLAG_ENUM_INITIALIZED )) {
+
+        FileName = IrpSp->Parameters.QueryDirectory.FileName;
+
+        CcbFlags = 0;
+
+        //
+        //  If the filename is not specified or is a single '*' then we will
+        //  match all names.
+        //
+
+        if ((FileName == NULL) ||
+            (FileName->Buffer == NULL) ||
+            (FileName->Length == 0) ||
+            ((FileName->Length == sizeof( WCHAR )) &&
+             (FileName->Buffer[0] == L'*'))) {
+
+            SetFlag( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL );
+            RtlZeroMemory( &SearchExpression, sizeof( SearchExpression ));
+
+        //
+        //  Otherwise build the CdName from the name in the stack location.
+        //  This involves building both the name and version portions and
+        //  checking for wild card characters.  We also upcase the string if
+        //  this is a case-insensitive search.
+        //
+
+        } else {
+
+            //
+            //  Create a CdName to check for wild cards.
+            //
+
+            WildCardName.FileName = *FileName;
+
+            CdConvertNameToCdName( IrpContext, &WildCardName );
+
+            //
+            //  The name better have at least one character.
+            //
+
+            if (WildCardName.FileName.Length == 0) {
+
+                CdRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER );
+            }
+
+            //
+            //  Check for wildcards in the separate components.
+            //
+
+            if (FsRtlDoesNameContainWildCards( &WildCardName.FileName)) {
+
+                SetFlag( CcbFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD );
+            }
+
+            if ((WildCardName.VersionString.Length != 0) &&
+                (FsRtlDoesNameContainWildCards( &WildCardName.VersionString ))) {
+
+                SetFlag( CcbFlags, CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD );
+
+                //
+                //  Check if this is a wild card only and match all version
+                //  strings.
+                //
+
+                if ((WildCardName.VersionString.Length == sizeof( WCHAR )) &&
+                    (WildCardName.VersionString.Buffer[0] == L'*')) {
+
+                    SetFlag( CcbFlags, CCB_FLAG_ENUM_VERSION_MATCH_ALL );
+                }
+            }
+
+            //
+            //  Now create the search expression to store in the Ccb.
+            //
+
+            SearchExpression.FileName.Buffer = FsRtlAllocatePoolWithTag( CdPagedPool,
+                                                                         FileName->Length,
+                                                                         TAG_ENUM_EXPRESSION );
+
+            SearchExpression.FileName.MaximumLength = FileName->Length;
+
+            //
+            //  Either copy the name directly or perform the upcase.
+            //
+
+            if (FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE )) {
+
+                Status = RtlUpcaseUnicodeString( (PUNICODE_STRING) &SearchExpression.FileName,
+                                                 FileName,
+                                                 FALSE );
+
+                //
+                //  This should never fail.
+                //
+
+                ASSERT( Status == STATUS_SUCCESS );
+
+            } else {
+
+                RtlCopyMemory( SearchExpression.FileName.Buffer,
+                               FileName->Buffer,
+                               FileName->Length );
+            }
+
+            //
+            //  Now split into the separate name and version components.
+            //
+
+            SearchExpression.FileName.Length = WildCardName.FileName.Length;
+            SearchExpression.VersionString.Length = WildCardName.VersionString.Length;
+            SearchExpression.VersionString.MaximumLength = WildCardName.VersionString.MaximumLength;
+
+            SearchExpression.VersionString.Buffer = Add2Ptr( SearchExpression.FileName.Buffer,
+                                                             SearchExpression.FileName.Length + sizeof( WCHAR ),
+                                                             PWCHAR );
+        }
+
+        //
+        //  But we do not want to return the constant "." and ".." entries for
+        //  the root directory, for consistency with the rest of Microsoft's
+        //  filesystems.
+        //
+
+        if (Fcb == Fcb->Vcb->RootIndexFcb) {
+
+            SetFlag( CcbFlags, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY );
+        }
+
+        //
+        //  Now lock the Fcb in order to update the Ccb with the inital
+        //  enumeration values.
+        //
+
+        CdLockFcb( IrpContext, Fcb );
+
+        //
+        //  Check again that this is the initial search.
+        //
+
+        if (!FlagOn( Ccb->Flags, CCB_FLAG_ENUM_INITIALIZED )) {
+
+            //
+            //  Update the values in the Ccb.
+            //
+
+            Ccb->CurrentDirentOffset = Fcb->StreamOffset;
+            Ccb->SearchExpression = SearchExpression;
+
+            //
+            //  Set the appropriate flags in the Ccb.
+            //
+
+            SetFlag( Ccb->Flags, CcbFlags | CCB_FLAG_ENUM_INITIALIZED );
+
+        //
+        //  Otherwise cleanup any buffer allocated here.
+        //
+
+        } else {
+
+            if (!FlagOn( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL )) {
+
+                CdFreePool( &SearchExpression.FileName.Buffer );
+            }
+        }
+
+    //
+    //  Otherwise lock the Fcb so we can read the current enumeration values.
+    //
+
+    } else {
+
+        CdLockFcb( IrpContext, Fcb );
+    }
+
+    //
+    //  Capture the current state of the enumeration.
+    //
+    //  If the user specified an index then use his offset.  We always
+    //  return the next entry in this case.
+    //
+
+    if (FlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED )) {
+
+        KnownOffset = FALSE;
+        DirentOffset = IrpSp->Parameters.QueryDirectory.FileIndex;
+        *ReturnNextEntry = TRUE;
+
+    //
+    //  If we are restarting the scan then go from the self entry.
+    //
+
+    } else if (FlagOn( IrpSp->Flags, SL_RESTART_SCAN )) {
+
+        KnownOffset = TRUE;
+        DirentOffset = Fcb->StreamOffset;
+        *ReturnNextEntry = FALSE;
+
+    //
+    //  Otherwise use the values from the Ccb.
+    //
+
+    } else {
+
+        KnownOffset = TRUE;
+        DirentOffset = Ccb->CurrentDirentOffset;
+        *ReturnNextEntry = BooleanFlagOn( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
+    }
+
+    //
+    //  Unlock the Fcb.
+    //
+
+    CdUnlockFcb( IrpContext, Fcb );
+
+    //
+    //  We have the starting offset in the directory and whether to return
+    //  that entry or the next.  If we are at the beginning of the directory
+    //  and are returning that entry, then tell our caller this is the
+    //  initial query.
+    //
+
+    *InitialQuery = FALSE;
+
+    if ((DirentOffset == Fcb->StreamOffset) &&
+        !(*ReturnNextEntry)) {
+
+        *InitialQuery = TRUE;
+    }
+
+    //
+    //  If there is no file object then create it now.
+    //
+
+    if (Fcb->FileObject == NULL) {
+
+        CdCreateInternalStream( IrpContext, Fcb->Vcb, Fcb );
+    }
+
+    //
+    //  Determine the offset in the stream to position the FileContext and
+    //  whether this offset is known to be a file offset.
+    //
+    //  If this offset is known to be safe then go ahead and position the
+    //  file context.  This handles the cases where the offset is the beginning
+    //  of the stream, the offset is from a previous search or this is the
+    //  initial query.
+    //
+
+    if (KnownOffset) {
+
+        CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, DirentOffset );
+
+    //
+    //  Otherwise we walk through the directory from the beginning until
+    //  we reach the entry which contains this offset.
+    //
+
+    } else {
+
+        LastDirentOffset = Fcb->StreamOffset;
+        Found = TRUE;
+
+        CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, LastDirentOffset );
+
+        //
+        //  If the requested offset is prior to the beginning offset in the stream
+        //  then don't return the next entry.
+        //
+
+        if (DirentOffset < LastDirentOffset) {
+
+            *ReturnNextEntry = FALSE;
+
+        //
+        //  Else look for the last entry which ends past the desired index.
+        //
+
+        } else {
+
+            //
+            //  Keep walking through the directory until we run out of
+            //  entries or we find an entry which ends beyond the input
+            //  index value.
+            //
+
+            do {
+
+                //
+                //  If we have passed the index value then exit.
+                //
+
+                if (FileContext->InitialDirent->Dirent.DirentOffset > DirentOffset) {
+
+                    Found = FALSE;
+                    break;
+                }
+
+                //
+                //  Remember the current position in case we need to go back.
+                //
+
+                LastDirentOffset = FileContext->InitialDirent->Dirent.DirentOffset;
+
+                //
+                //  Exit if the next entry is beyond the desired index value.
+                //
+
+                if (LastDirentOffset + FileContext->InitialDirent->Dirent.DirentLength > DirentOffset) {
+
+                    break;
+                }
+
+                Found = CdLookupNextInitialFileDirent( IrpContext, Fcb, FileContext );
+
+            } while (Found);
+
+            //
+            //  If we didn't find the entry then go back to the last known entry.
+            //  This can happen if the index lies in the unused range at the
+            //  end of a sector.
+            //
+
+            if (!Found) {
+
+                CdCleanupFileContext( IrpContext, FileContext );
+                CdInitializeFileContext( IrpContext, FileContext );
+
+                CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, LastDirentOffset );
+            }
+        }
+    }
+
+    //
+    //  Only update the dirent name if we will need it for some reason.
+    //  Don't update this name if we are returning the next entry and
+    //  the search string has a version component.
+    //
+
+    FileContext->ShortName.FileName.Length = 0;
+
+    if (!(*ReturnNextEntry) ||
+        (Ccb->SearchExpression.VersionString.Length == 0)) {
+
+        //
+        //  Update the name in the dirent into filename and version components.
+        //
+
+        CdUpdateDirentName( IrpContext,
+                            &FileContext->InitialDirent->Dirent,
+                            FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE ));
+    }
+
+    //
+    //  Look at the flag in the IrpSp indicating whether to return just
+    //  one entry.
+    //
+
+    *ReturnSingleEntry = FALSE;
+
+    if (FlagOn( IrpSp->Flags, SL_RETURN_SINGLE_ENTRY )) {
+
+        *ReturnSingleEntry = TRUE;
+    }
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+BOOLEAN
+CdEnumerateIndex (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCCB Ccb,
+    IN OUT PFILE_ENUM_CONTEXT FileContext,
+    IN BOOLEAN ReturnNextEntry
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is the worker routine for index enumeration.  We are positioned
+    at some dirent in the directory and will either return the first match
+    at that point or look to the next entry.  The Ccb contains details about
+    the type of matching to do.  If the user didn't specify a version in
+    his search string then we only return the first version of a sequence
+    of files with versions.  We also don't return any associated files.
+
+Arguments:
+
+    Ccb - Ccb for this directory handle.
+
+    FileContext - File context already positioned at some entry in the directory.
+
+    ReturnNextEntry - Indicates if we are returning this entry or should start
+        with the next entry.
+
+Return Value:
+
+    BOOLEAN - TRUE if next entry is found, FALSE otherwise.
+
+--*/
+
+{
+    PDIRENT PreviousDirent = NULL;
+    PDIRENT ThisDirent = &FileContext->InitialDirent->Dirent;
+
+    BOOLEAN Found = FALSE;
+
+    PAGED_CODE();
+
+    //
+    //  Loop until we find a match or exaust the directory.
+    //
+
+    while (TRUE) {
+
+        //
+        //  Move to the next entry unless we want to consider the current
+        //  entry.
+        //
+
+        if (ReturnNextEntry) {
+
+            if (!CdLookupNextInitialFileDirent( IrpContext, Ccb->Fcb, FileContext )) {
+
+                break;
+            }
+
+            PreviousDirent = ThisDirent;
+            ThisDirent = &FileContext->InitialDirent->Dirent;
+
+            CdUpdateDirentName( IrpContext, ThisDirent, FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE ));
+        
+        } else {
+
+            ReturnNextEntry = TRUE;
+        }
+
+        //
+        //  Don't bother if we have a constant entry and are ignoring them.
+        //
+        
+        if (FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY ) &&
+            FlagOn( Ccb->Flags, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY )) {
+
+            continue;
+        }
+
+        //
+        //  Look at the current entry if it is not an associated file
+        //  and the name doesn't match the previous file if the version
+        //  name is not part of the search.
+        //
+
+        if (!FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_ASSOC )) {
+
+            //
+            //  Check if this entry matches the previous entry except
+            //  for version number and whether we should return the
+            //  entry in that case.  Go directly to the name comparison
+            //  if:
+            //
+            //      There is no previous entry.
+            //      The search expression has a version component.
+            //      The name length doesn't match the length of the previous entry.
+            //      The base name strings don't match.
+            //
+
+            if ((PreviousDirent == NULL) ||
+                (Ccb->SearchExpression.VersionString.Length != 0) ||
+                (PreviousDirent->CdCaseFileName.FileName.Length != ThisDirent->CdCaseFileName.FileName.Length) ||
+                FlagOn( PreviousDirent->DirentFlags, CD_ATTRIBUTE_ASSOC ) ||
+                !RtlEqualMemory( PreviousDirent->CdCaseFileName.FileName.Buffer,
+                                 ThisDirent->CdCaseFileName.FileName.Buffer,
+                                 ThisDirent->CdCaseFileName.FileName.Length )) {
+
+                //
+                //  If we match all names then return to our caller.
+                //
+
+                if (FlagOn( Ccb->Flags, CCB_FLAG_ENUM_MATCH_ALL )) {
+
+                    FileContext->ShortName.FileName.Length = 0;
+                    Found = TRUE;
+                    break;
+                }
+
+                //
+                //  Check if the long name matches the search expression.
+                //
+
+                if (CdIsNameInExpression( IrpContext,
+                                          &ThisDirent->CdCaseFileName,
+                                          &Ccb->SearchExpression,
+                                          Ccb->Flags,
+                                          TRUE )) {
+
+                    //
+                    //  Let our caller know we found an entry.
+                    //
+
+                    Found = TRUE;
+                    FileContext->ShortName.FileName.Length = 0;
+                    break;
+                }
+
+                //
+                //  The long name didn't match so we need to check for a
+                //  possible short name match.  There is no match if the
+                //  long name is 8dot3 or the search expression has a
+                //  version component.  Special case the self and parent
+                //  entries.
+                //
+
+                if ((Ccb->SearchExpression.VersionString.Length == 0) &&
+                    !FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY ) &&
+                    !CdIs8dot3Name( IrpContext,
+                                    ThisDirent->CdFileName.FileName )) {
+
+                    CdGenerate8dot3Name( IrpContext,
+                                         &ThisDirent->CdCaseFileName.FileName,
+                                         ThisDirent->DirentOffset,
+                                         FileContext->ShortName.FileName.Buffer,
+                                         &FileContext->ShortName.FileName.Length );
+
+                    //
+                    //  Check if this name matches.
+                    //
+
+                    if (CdIsNameInExpression( IrpContext,
+                                              &FileContext->ShortName,
+                                              &Ccb->SearchExpression,
+                                              Ccb->Flags,
+                                              FALSE )) {
+
+                        //
+                        //  Let our caller know we found an entry.
+                        //
+
+                        Found = TRUE;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    //
+    //  If we found the entry then make sure we walk through all of the
+    //  file dirents.
+    //
+
+    if (Found) {
+
+        CdLookupLastFileDirent( IrpContext, Ccb->Fcb, FileContext );
+    }
+
+    return Found;
+}
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/dirsup.c b/reactos/drivers/filesystems/cdfs_new/dirsup.c
new file mode 100755 (executable)
index 0000000..6edfc1b
--- /dev/null
@@ -0,0 +1,1863 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    DirSup.c
+
+Abstract:
+
+    This module implements the dirent support routines for Cdfs.
+
+    Directories on a CD consist of a number of contiguous sectors on
+    the disk.  File descriptors consist of one or more directory entries
+    (dirents) within a directory.  Files may contain version numbers.  If
+    present all like-named files will be ordered contiguously in the
+    directory by decreasing version numbers.  We will only return the
+    first of these on a directory query unless the user explicitly
+    asks for version numbers.  Finally dirents will not span sector
+    boundaries.  Unused bytes at the end of a sector will be zero
+    filled.
+
+    Directory sector:                                                   Offset
+                                                                        2048
+        +---------------------------------------------------------------+
+        |            |          |          |           |          |     |
+        | foo;4      | foo;4    | foo;3    |  hat      |  zebra   | Zero|
+        |            |          |          |           |          | Fill|
+        |            |  final   |  single  |           |          |     |
+        |            |  extent  |   extent |           |          |     |
+        +---------------------------------------------------------------+
+
+    Dirent operations:
+
+        - Position scan at known offset in directory.  Dirent at this
+            offset must exist and is valid.  Used when scanning a directory
+            from the beginning when the self entry is known to be valid.
+            Used when positioning at the first dirent for an open
+            file to scan the allocation information.  Used when resuming
+            a directory enumeration from a valid directory entry.
+
+        - Position scan at known offset in directory.  Dirent is known to
+            start at this position but must be checked for validity.
+            Used to read the self-directory entry.
+
+        - Move to the next dirent within a directory.
+
+        - Given a known starting dirent, collect all the dirents for
+            that file.  Scan will finish positioned at the last dirent
+            for the file.  We will accumulate the extent lengths to
+            find the size of the file.
+
+        - Given a known starting dirent, position the scan for the first
+            dirent of the following file.  Used when not interested in
+            all of the details for the current file and are looking for
+            the next file.
+
+        - Update a common dirent structure with the details of the on-disk
+            structure.  This is used to smooth out the differences
+
+        - Build the filename (name and version strings) out of the stream
+            of bytes in the file name on disk.  For Joliet disks we will have
+            to convert to little endian.
+
+
+--*/
+
+#include "CdProcs.h"
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (CDFS_BUG_CHECK_DIRSUP)
+
+//
+//  Local macros
+//
+
+//
+//  PRAW_DIRENT
+//  CdRawDirent (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PDIR_ENUM_CONTEXT DirContext
+//      );
+//
+
+#define CdRawDirent(IC,DC)                                      \
+    Add2Ptr( (DC)->Sector, (DC)->SectorOffset, PRAW_DIRENT )
+
+//
+//  Local support routines
+//
+
+ULONG
+CdCheckRawDirentBounds (
+    IN PIRP_CONTEXT IrpContext,
+    IN PDIRENT_ENUM_CONTEXT DirContext
+    );
+
+XA_EXTENT_TYPE
+CdCheckForXAExtent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PRAW_DIRENT RawDirent,
+    IN OUT PDIRENT Dirent
+    );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdCheckForXAExtent)
+#pragma alloc_text(PAGE, CdCheckRawDirentBounds)
+#pragma alloc_text(PAGE, CdCleanupFileContext)
+#pragma alloc_text(PAGE, CdFindFile)
+#pragma alloc_text(PAGE, CdFindDirectory)
+#pragma alloc_text(PAGE, CdFindFileByShortName)
+#pragma alloc_text(PAGE, CdLookupDirent)
+#pragma alloc_text(PAGE, CdLookupLastFileDirent)
+#pragma alloc_text(PAGE, CdLookupNextDirent)
+#pragma alloc_text(PAGE, CdLookupNextInitialFileDirent)
+#pragma alloc_text(PAGE, CdUpdateDirentFromRawDirent)
+#pragma alloc_text(PAGE, CdUpdateDirentName)
+#endif
+
+\f
+VOID
+CdLookupDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN ULONG DirentOffset,
+    OUT PDIRENT_ENUM_CONTEXT DirContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to initiate a walk through a directory.  We will
+    position ourselves in the directory at offset DirentOffset.  We know that
+    a dirent begins at this boundary but may have to verify the dirent bounds.
+    We will call this routine when looking up the first entry of a known
+    file or verifying the self entry of a directory.
+
+Arguments:
+
+    Fcb - Fcb for the directory being traversed.
+
+    DirentOffset - This is our target point in the directory.  We will map the
+        page containing this entry and possibly verify the dirent bounds at
+        this location.
+
+    DirContext - This is the dirent context for this scan.  We update it with
+        the location of the dirent we found.  This structure has been initialized
+        outside of this call.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    LONGLONG BaseOffset;
+
+    PAGED_CODE();
+
+    //
+    //  Initialize the offset of the first dirent we want to map.
+    //
+
+    DirContext->BaseOffset = SectorTruncate( DirentOffset );
+    BaseOffset = DirContext->BaseOffset;
+
+    DirContext->DataLength = SECTOR_SIZE;
+
+    DirContext->SectorOffset = SectorOffset( DirentOffset );
+
+    //
+    //  Truncate the data length if we are at the end of the file.
+    //
+
+    if (DirContext->DataLength > (Fcb->FileSize.QuadPart - BaseOffset)) {
+
+        DirContext->DataLength = (ULONG) (Fcb->FileSize.QuadPart - BaseOffset);
+    }
+
+    //
+    //  Now map the data at this offset.
+    //
+
+    CcMapData( Fcb->FileObject,
+               (PLARGE_INTEGER) &BaseOffset,
+               DirContext->DataLength,
+               TRUE,
+               &DirContext->Bcb,
+               &DirContext->Sector );
+
+    //
+    //  Verify the dirent bounds.
+    //
+
+    DirContext->NextDirentOffset = CdCheckRawDirentBounds( IrpContext,
+                                                           DirContext );
+
+    return;
+}
+
+\f
+BOOLEAN
+CdLookupNextDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PDIRENT_ENUM_CONTEXT CurrentDirContext,
+    OUT PDIRENT_ENUM_CONTEXT NextDirContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to find the next dirent in the directory.  The
+    current position is given and we look for the next.  We leave the context
+    for the starting position untouched and update the context for the
+    dirent we found.  The target context may already be initialized so we
+    may already have the sector in memory.
+
+    This routine will position the enumeration context for the next dirent and
+    verify the dirent bounds.
+
+    NOTE - This routine can be called with CurrentDirContext and NextDirContext
+        pointing to the same enumeration context.
+
+Arguments:
+
+    Fcb - Fcb for the directory being traversed.
+
+    CurrentDirContext - This is the dirent context for this scan.  We update
+        it with the location of the dirent we found.  This is currently
+        pointing to a dirent location.  The dirent bounds at this location
+        have already been verified.
+
+    NextDirContext - This is the dirent context to update with the dirent we
+        find.  This may already point to a dirent so we need to check if
+        we are in the same sector and unmap any buffer as necessary.
+
+        This dirent is left in an indeterminant state if we don't find a dirent.
+
+Return Value:
+
+    BOOLEAN - TRUE if we find a location for the next dirent, FALSE otherwise.
+        This routine can cause a raise if the directory is corrupt.
+
+--*/
+
+{
+    LONGLONG CurrentBaseOffset = CurrentDirContext->BaseOffset;
+    ULONG TempUlong;
+
+    BOOLEAN FoundDirent = FALSE;
+
+    PAGED_CODE();
+
+    //
+    //  Check if a different sector is mapped.  If so then move our target
+    //  enumeration context to the same sector.
+    //
+
+    if ((CurrentDirContext->BaseOffset != NextDirContext->BaseOffset) ||
+        (NextDirContext->Bcb == NULL)) {
+
+        //
+        //  Unpin the current target Bcb and map the next sector.
+        //
+
+        CdUnpinData( IrpContext, &NextDirContext->Bcb );
+
+        CcMapData( Fcb->FileObject,
+                   (PLARGE_INTEGER) &CurrentBaseOffset,
+                   CurrentDirContext->DataLength,
+                   TRUE,
+                   &NextDirContext->Bcb,
+                   &NextDirContext->Sector );
+
+        //
+        //  Copy the data length and sector offset.
+        //
+
+        NextDirContext->DataLength = CurrentDirContext->DataLength;
+        NextDirContext->BaseOffset = CurrentDirContext->BaseOffset;
+    }
+
+    //
+    //  Now move to the same offset in the sector.
+    //
+
+    NextDirContext->SectorOffset = CurrentDirContext->SectorOffset;
+
+    //
+    //  If the value is zero then unmap the current sector and set up
+    //  the base offset to the beginning of the next sector.
+    //
+
+    if (CurrentDirContext->NextDirentOffset == 0) {
+
+        CurrentBaseOffset = NextDirContext->BaseOffset + NextDirContext->DataLength;
+
+        //
+        //  Unmap the current sector.  We test the value of the Bcb in the
+        //  loop below to see if we need to read in another sector.
+        //
+
+        CdUnpinData( IrpContext, &NextDirContext->Bcb );
+
+    //
+    //  There is another possible dirent in the current sector.  Update the
+    //  enumeration context to reflect this.
+    //
+
+    } else {
+
+        NextDirContext->SectorOffset += CurrentDirContext->NextDirentOffset;
+    }
+
+    //
+    //  Now loop until we find the next possible dirent or walk off the directory.
+    //
+
+    while (TRUE) {
+
+        //
+        //  If we don't currently have a sector mapped then map the
+        //  directory at the current offset.
+        //
+
+        if (NextDirContext->Bcb == NULL) {
+
+            TempUlong = SECTOR_SIZE;
+
+            if (TempUlong > (ULONG) (Fcb->FileSize.QuadPart - CurrentBaseOffset)) {
+
+                TempUlong = (ULONG) (Fcb->FileSize.QuadPart - CurrentBaseOffset);
+
+                //
+                //  If the length is zero then there is no dirent.
+                //
+
+                if (TempUlong == 0) {
+
+                    break;
+                }
+            }
+
+            CcMapData( Fcb->FileObject,
+                       (PLARGE_INTEGER) &CurrentBaseOffset,
+                       TempUlong,
+                       TRUE,
+                       &NextDirContext->Bcb,
+                       &NextDirContext->Sector );
+
+            NextDirContext->BaseOffset = (ULONG) CurrentBaseOffset;
+            NextDirContext->SectorOffset = 0;
+            NextDirContext->DataLength = TempUlong;
+        }
+
+        //
+        //  The CDFS spec allows for sectors in a directory to contain all zeroes.
+        //  In this case we need to move to the next sector.  So look at the
+        //  current potential dirent for a zero length.  Move to the next
+        //  dirent if length is zero.
+        //
+
+        if (*((PCHAR) CdRawDirent( IrpContext, NextDirContext )) != 0) {
+
+            FoundDirent = TRUE;
+            break;
+        }
+
+        CurrentBaseOffset = NextDirContext->BaseOffset + NextDirContext->DataLength;
+        CdUnpinData( IrpContext, &NextDirContext->Bcb );
+    }
+
+    //
+    //  Check the dirent bounds if we found a dirent.
+    //
+
+    if (FoundDirent) {
+
+        NextDirContext->NextDirentOffset = CdCheckRawDirentBounds( IrpContext,
+                                                                   NextDirContext );
+    }
+
+    return FoundDirent;
+}
+
+\f
+VOID
+CdUpdateDirentFromRawDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PDIRENT_ENUM_CONTEXT DirContext,
+    IN OUT PDIRENT Dirent
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to safely copy the data from the dirent on disk
+    to the in-memory dirent.  The fields on disk are unaligned so we
+    need to safely copy them to our structure.
+
+Arguments:
+
+    Fcb - Fcb for the directory being scanned.
+
+    DirContext - Enumeration context for the raw disk dirent.
+
+    Dirent - In-memory dirent to update.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    PRAW_DIRENT RawDirent = CdRawDirent( IrpContext, DirContext );
+
+    PAGED_CODE();
+
+    //
+    //  Clear all of the current state flags except the flag indicating that
+    //  we allocated a name string.
+    //
+
+    ClearFlag( Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT );
+
+    //
+    //  The dirent offset is the sum of the start of the sector and the
+    //  sector offset.
+    //
+
+    Dirent->DirentOffset = DirContext->BaseOffset + DirContext->SectorOffset;
+
+    //
+    //  Copy the dirent length from the raw dirent.
+    //
+
+    Dirent->DirentLength = RawDirent->DirLen;
+
+    //
+    //  The starting offset on disk is computed by finding the starting
+    //  logical block and stepping over the Xar block.
+    //
+
+    CopyUchar4( &Dirent->StartingOffset, RawDirent->FileLoc );
+
+    Dirent->StartingOffset += RawDirent->XarLen;
+
+    //
+    //  Do a safe copy to get the data length.
+    //
+
+    CopyUchar4( &Dirent->DataLength, RawDirent->DataLen );
+
+    //
+    //  Save a pointer to the time stamps.
+    //
+
+    Dirent->CdTime = (PCHAR)RawDirent->RecordTime; /* ReactOS change: GCC "pointer targets in assignment differ in signedness" */
+
+    //
+    //  Copy the dirent flags.
+    //
+
+    Dirent->DirentFlags = CdRawDirentFlags( IrpContext, RawDirent );
+
+    //
+    //  For both the file unit and interleave skip we want to take the
+    //  logical block count.
+    //
+
+    Dirent->FileUnitSize =
+    Dirent->InterleaveGapSize = 0;
+
+    if (RawDirent->IntLeaveSize != 0) {
+
+        Dirent->FileUnitSize = RawDirent->IntLeaveSize;
+        Dirent->InterleaveGapSize = RawDirent->IntLeaveSkip;
+    }
+
+    //
+    //  Get the name length and remember a pointer to the start of the
+    //  name string.  We don't do any processing on the name at this
+    //  point.
+    //
+    //  Check that the name length is non-zero.
+    //
+
+    if (RawDirent->FileIdLen == 0) {
+
+        CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+    }
+
+    Dirent->FileNameLen = RawDirent->FileIdLen;
+    Dirent->FileName = (PCHAR)RawDirent->FileId; /* ReactOS change: GCC "pointer targets in assignment differ in signedness" */
+
+    //
+    //  If there are any remaining bytes at the end of the dirent then
+    //  there may be a system use area.  We protect ourselves from
+    //  disks which don't pad the dirent entries correctly by using
+    //  a fudge factor of one.  All system use areas must have a length
+    //  greater than one.  Don't bother with the system use area
+    //  if this is a directory.
+    //
+
+    Dirent->XAAttributes = 0;
+    Dirent->XAFileNumber = 0;
+    Dirent->ExtentType = Form1Data;
+    Dirent->SystemUseOffset = 0;
+
+    if (!FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY ) &&
+        (Dirent->DirentLength > ((FIELD_OFFSET( RAW_DIRENT, FileId ) + Dirent->FileNameLen) + 1))) {
+
+        Dirent->SystemUseOffset = WordAlign( FIELD_OFFSET( RAW_DIRENT, FileId ) + Dirent->FileNameLen );
+    }
+
+    return;
+}
+
+\f
+VOID
+CdUpdateDirentName (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PDIRENT Dirent,
+    IN ULONG IgnoreCase
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to update the name in the dirent with the name
+    from the disk.  We will look for the special case of the self and
+    parent entries and also construct the Unicode name for the Joliet disk
+    in order to work around the BigEndian on-disk structure.
+
+Arguments:
+
+    Dirent - Pointer to the in-memory dirent structure.
+
+    IgnoreCase - TRUE if we should build the upcased version.  Otherwise we
+        use the exact case name.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    UCHAR DirectoryValue;
+    ULONG Length;
+
+    NTSTATUS Status;
+
+    PAGED_CODE();
+
+    //
+    //  Check if this is a self or parent entry.  There is no version number
+    //  in these cases.  We use a fixed string for these.
+    //
+    //      Self-Entry - Length is 1, value is 0.
+    //      Parent-Entry - Length is 1, value is 1.
+    //
+
+    if ((Dirent->FileNameLen == 1) &&
+        FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {
+
+        DirectoryValue = *((PCHAR) Dirent->FileName);
+
+        if ((DirectoryValue == 0) || (DirectoryValue == 1)) {
+
+            //
+            //  We should not have allocated a name by the time we see these cases.
+            //  If we have, this means that the image is in violation of ISO 9660 7.6.2,
+            //  which states that the ./.. entries must be the first two in the directory.
+            //
+
+            if (FlagOn( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER )) {
+
+                CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+            }
+
+            //
+            //  Now use one of the hard coded directory names.
+            //
+
+            Dirent->CdFileName.FileName = CdUnicodeDirectoryNames[DirectoryValue];
+
+            //
+            //  Show that there is no version number.
+            //
+
+            Dirent->CdFileName.VersionString.Length = 0;
+
+            //
+            //  The case name is the same as the exact name.
+            //
+
+            Dirent->CdCaseFileName = Dirent->CdFileName;
+
+            //
+            //  Mark this as a constant value entry.
+            //
+
+            SetFlag( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY );
+
+            //
+            //  Return now.
+            //
+
+            return;
+        }
+    }
+
+    //
+    //  Mark this as a non-constant value entry.
+    //
+
+    ClearFlag( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY );
+
+    //
+    //  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 = Dirent->FileNameLen;
+
+    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( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER ) &&
+        (Length <= sizeof( Dirent->NameBuffer ))) {
+
+        Dirent->CdFileName.FileName.MaximumLength = sizeof( Dirent->NameBuffer );
+        Dirent->CdFileName.FileName.Buffer = Dirent->NameBuffer;
+
+    } else {
+
+        //
+        //  We need to use an allocated buffer.  Check if the current buffer
+        //  is large enough.
+        //
+
+        if (Length > Dirent->CdFileName.FileName.MaximumLength) {
+
+            //
+            //  Free any allocated buffer.
+            //
+
+            if (FlagOn( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER )) {
+
+                CdFreePool( &Dirent->CdFileName.FileName.Buffer );
+                ClearFlag( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER );
+            }
+
+            Dirent->CdFileName.FileName.Buffer = FsRtlAllocatePoolWithTag( CdPagedPool,
+                                                                            Length,
+                                                                            TAG_DIRENT_NAME );
+
+            SetFlag( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER );
+
+            Dirent->CdFileName.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( Dirent->CdFileName.FileName.Buffer,
+                                   Dirent->CdFileName.FileName.MaximumLength,
+                                   &Length,
+                                   Dirent->FileName,
+                                   Dirent->FileNameLen );
+
+        ASSERT( Status == STATUS_SUCCESS );
+        Dirent->CdFileName.FileName.Length = (USHORT) Length;
+
+    } else {
+
+        //
+        //  Convert this string to little endian.
+        //
+
+        CdConvertBigToLittleEndian( IrpContext,
+                                    Dirent->FileName,
+                                    Dirent->FileNameLen,
+                                    (PCHAR) Dirent->CdFileName.FileName.Buffer );
+
+        Dirent->CdFileName.FileName.Length = (USHORT) Dirent->FileNameLen;
+    }
+
+    //
+    //  Split the name into name and version strings.
+    //
+
+    CdConvertNameToCdName( IrpContext,
+                           &Dirent->CdFileName );
+
+    //
+    //  The name length better be non-zero.
+    //
+
+    if (Dirent->CdFileName.FileName.Length == 0) {
+
+        CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+    }
+
+    //
+    //  If the filename ends with a period then back up one character.
+    //
+
+    if (Dirent->CdFileName.FileName.Buffer[(Dirent->CdFileName.FileName.Length - sizeof( WCHAR )) / 2] == L'.') {
+
+        //
+        //  Slide the version string down.
+        //
+
+        if (Dirent->CdFileName.VersionString.Length != 0) {
+
+            PWCHAR NewVersion;
+
+            //
+            //  Start from the position currently containing the separator.
+            //
+
+            NewVersion = Add2Ptr( Dirent->CdFileName.FileName.Buffer,
+                                  Dirent->CdFileName.FileName.Length,
+                                  PWCHAR );
+
+            //
+            //  Now overwrite the period.
+            //
+
+            RtlMoveMemory( NewVersion - 1,
+                           NewVersion,
+                           Dirent->CdFileName.VersionString.Length + sizeof( WCHAR ));
+
+            //
+            //  Now point to the new version string.
+            //
+
+            Dirent->CdFileName.VersionString.Buffer = NewVersion;
+        }
+
+        //
+        //  Shrink the filename length.
+        //
+
+        Dirent->CdFileName.FileName.Length -= sizeof( WCHAR );
+    }
+
+    //
+    //  If this an exact case operation then use the filename exactly.
+    //
+
+    if (!IgnoreCase) {
+
+        Dirent->CdCaseFileName = Dirent->CdFileName;
+
+    //
+    //  Otherwise perform our upcase operation.  We already have guaranteed the buffers are
+    //  there.
+    //
+
+    } else {
+
+        Dirent->CdCaseFileName.FileName.Buffer = Add2Ptr( Dirent->CdFileName.FileName.Buffer,
+                                                          Dirent->CdFileName.FileName.MaximumLength / 2,
+                                                          PWCHAR);
+
+        Dirent->CdCaseFileName.FileName.MaximumLength = Dirent->CdFileName.FileName.MaximumLength / 2;
+
+        CdUpcaseName( IrpContext,
+                      &Dirent->CdFileName,
+                      &Dirent->CdCaseFileName );
+    }
+
+    return;
+}
+
+\f
+BOOLEAN
+CdFindFile (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PCD_NAME Name,
+    IN BOOLEAN IgnoreCase,
+    IN OUT PFILE_ENUM_CONTEXT FileContext,
+    OUT PCD_NAME *MatchingName
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to search a dirctory for a file matching the input
+    name.  This name has been upcased at this point if this a case-insensitive
+    search.  The name has been separated into separate name and version strings.
+    We look for an exact match in the name and only consider the version if
+    there is a version specified in the search name.
+
+Arguments:
+
+    Fcb - Fcb for the directory being scanned.
+
+    Name - Name to search for.
+
+    IgnoreCase - Indicates the case of the search.
+
+    FileContext - File context to use for the search.  This has already been
+        initialized.
+
+    MatchingName - Pointer to buffer containing matching name.  We need this
+        in case we don't match the name in the directory but match the
+        short name instead.
+
+Return Value:
+
+    BOOLEAN - TRUE if matching entry is found, FALSE otherwise.
+
+--*/
+
+{
+    PDIRENT Dirent;
+    ULONG ShortNameDirentOffset;
+
+    BOOLEAN Found = FALSE;
+
+    PAGED_CODE();
+
+    //
+    //  Make sure there is a stream file for this Fcb.
+    //
+
+    if (Fcb->FileObject == NULL) {
+
+        CdCreateInternalStream( IrpContext, Fcb->Vcb, Fcb );
+    }
+
+    //
+    //  Check to see whether we need to check for a possible short name.
+    //
+
+    ShortNameDirentOffset = CdShortNameDirentOffset( IrpContext, &Name->FileName );
+
+    //
+    //  Position ourselves at the first entry.
+    //
+
+    CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, Fcb->StreamOffset );
+
+    //
+    //  Loop while there are more entries in this directory.
+    //
+
+    do {
+
+        Dirent = &FileContext->InitialDirent->Dirent;
+
+        //
+        //  We only consider files which don't have the associated bit set.
+        //  We also only look for files.  All directories would already
+        //  have been found.
+        //
+
+        if (!FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_ASSOC | CD_ATTRIBUTE_DIRECTORY )) {
+
+            //
+            //  Update the name in the current dirent.
+            //
+
+            CdUpdateDirentName( IrpContext, Dirent, IgnoreCase );
+
+            //
+            //  Don't bother with constant entries.
+            //
+
+            if (FlagOn( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) {
+
+                continue;
+            }
+
+            //
+            //  Now check whether we have a name match.
+            //  We exit the loop if we have a match.
+            //
+
+            if (CdIsNameInExpression( IrpContext,
+                                      &Dirent->CdCaseFileName,
+                                      Name,
+                                      0,
+                                      TRUE )) {
+
+                *MatchingName = &Dirent->CdCaseFileName;
+                Found = TRUE;
+                break;
+            }
+
+            //
+            //  The names didn't match.  If the input name is a possible short
+            //  name and we are at the correct offset in the directory then
+            //  check if the short names match.
+            //
+
+            if (((Dirent->DirentOffset >> SHORT_NAME_SHIFT) == ShortNameDirentOffset) &&
+                (Name->VersionString.Length == 0) &&
+                !CdIs8dot3Name( IrpContext,
+                                Dirent->CdFileName.FileName )) {
+
+                //
+                //  Create the short name and check for a match.
+                //
+
+                CdGenerate8dot3Name( IrpContext,
+                                     &Dirent->CdCaseFileName.FileName,
+                                     Dirent->DirentOffset,
+                                     FileContext->ShortName.FileName.Buffer,
+                                     &FileContext->ShortName.FileName.Length );
+
+                //
+                //  Now check whether we have a name match.
+                //  We exit the loop if we have a match.
+                //
+
+                if (CdIsNameInExpression( IrpContext,
+                                          &FileContext->ShortName,
+                                          Name,
+                                          0,
+                                          FALSE )) {
+
+                    *MatchingName = &FileContext->ShortName,
+                    Found = TRUE;
+                    break;
+                }
+            }
+        }
+
+        //
+        //  Go to the next initial dirent for a file.
+        //
+
+    } while (CdLookupNextInitialFileDirent( IrpContext, Fcb, FileContext ));
+
+    //
+    //  If we find the file then collect all of the dirents.
+    //
+
+    if (Found) {
+
+        CdLookupLastFileDirent( IrpContext, Fcb, FileContext );
+
+    }
+
+    return Found;
+}
+
+\f
+BOOLEAN
+CdFindDirectory (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PCD_NAME Name,
+    IN BOOLEAN IgnoreCase,
+    IN OUT PFILE_ENUM_CONTEXT FileContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to search a dirctory for a directory matching the input
+    name.  This name has been upcased at this point if this a case-insensitive
+    search.  We look for an exact match in the name and do not look for shortname
+    equivalents.
+
+Arguments:
+
+    Fcb - Fcb for the directory being scanned.
+
+    Name - Name to search for.
+
+    IgnoreCase - Indicates the case of the search.
+
+    FileContext - File context to use for the search.  This has already been
+        initialized.
+
+Return Value:
+
+    BOOLEAN - TRUE if matching entry is found, FALSE otherwise.
+
+--*/
+
+{
+    PDIRENT Dirent;
+
+    BOOLEAN Found = FALSE;
+
+    PAGED_CODE();
+
+    //
+    //  Make sure there is a stream file for this Fcb.
+    //
+
+    if (Fcb->FileObject == NULL) {
+
+        CdCreateInternalStream( IrpContext, Fcb->Vcb, Fcb );
+    }
+
+    //
+    //  Position ourselves at the first entry.
+    //
+
+    CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, Fcb->StreamOffset );
+
+    //
+    //  Loop while there are more entries in this directory.
+    //
+
+    do {
+
+        Dirent = &FileContext->InitialDirent->Dirent;
+
+        //
+        //  We only look for directories.  Directories cannot have the
+        //  associated bit set.
+        //
+
+        if (FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {
+
+            //
+            //  Update the name in the current dirent.
+            //
+
+            CdUpdateDirentName( IrpContext, Dirent, IgnoreCase );
+
+            //
+            //  Don't bother with constant entries.
+            //
+
+            if (FlagOn( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) {
+
+                continue;
+            }
+
+            //
+            //  Now check whether we have a name match.
+            //  We exit the loop if we have a match.
+            //
+
+            if (CdIsNameInExpression( IrpContext,
+                                      &Dirent->CdCaseFileName,
+                                      Name,
+                                      0,
+                                      TRUE )) {
+
+                Found = TRUE;
+                break;
+            }
+        }
+
+        //
+        //  Go to the next initial dirent.
+        //
+
+    } while (CdLookupNextInitialFileDirent( IrpContext, Fcb, FileContext ));
+
+    return Found;
+}
+
+\f
+BOOLEAN
+CdFindFileByShortName (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PCD_NAME Name,
+    IN BOOLEAN IgnoreCase,
+    IN ULONG ShortNameDirentOffset,
+    IN OUT PFILE_ENUM_CONTEXT FileContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to find the file name entry whose short name
+    is defined by the input DirentOffset.  The dirent offset here is
+    multiplied by 32 and we look for the dirent begins in this 32 byte offset in
+    directory.  The minimum dirent length is 34 so we are guaranteed that only
+    one dirent can begin in each 32 byte block in the directory.
+
+Arguments:
+
+    Fcb - Fcb for the directory being scanned.
+
+    Name - Name we are trying to match.  We know this contains the tilde
+        character followed by decimal characters.
+
+    IgnoreCase - Indicates whether we need to upcase the long name and
+        generated short name.
+
+    ShortNameDirentOffset - This is the shifted value for the offset of the
+        name in the directory.
+
+    FileContext - This is the initialized file context to use for the search.
+
+Return Value:
+
+    BOOLEAN - TRUE if a matching name was found, FALSE otherwise.
+
+--*/
+
+{
+    BOOLEAN Found = FALSE;
+    PDIRENT Dirent;
+
+    ULONG ThisShortNameDirentOffset;
+
+    PAGED_CODE();
+
+    //
+    //  Make sure there is a stream file for this Fcb.
+    //
+
+    if (Fcb->FileObject == NULL) {
+
+        CdCreateInternalStream( IrpContext, Fcb->Vcb, Fcb );
+    }
+
+    //
+    //  Position ourselves at the start of the directory and update
+    //
+    //
+
+    CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, Fcb->StreamOffset );
+
+    //
+    //  Loop until we have found the entry or are beyond this dirent.
+    //
+
+    do {
+
+        //
+        //  Compute the short name dirent offset for the current dirent.
+        //
+
+        Dirent = &FileContext->InitialDirent->Dirent;
+        ThisShortNameDirentOffset = Dirent->DirentOffset >> SHORT_NAME_SHIFT;
+
+        //
+        //  If beyond the target then exit.
+        //
+
+        if (ThisShortNameDirentOffset > ShortNameDirentOffset) {
+
+            break;
+        }
+
+        //
+        //  If equal to the target then check if we have a name match.
+        //  We will either match or fail here.
+        //
+
+        if (ThisShortNameDirentOffset == ShortNameDirentOffset) {
+
+            //
+            //  If this is an associated file then get out.
+            //
+
+            if (FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_ASSOC )) {
+
+                break;
+            }
+
+            //
+            //  Update the name in the dirent and check if it is not
+            //  an 8.3 name.
+            //
+
+            CdUpdateDirentName( IrpContext, Dirent, IgnoreCase );
+
+            if (CdIs8dot3Name( IrpContext,
+                               Dirent->CdFileName.FileName )) {
+
+                break;
+            }
+
+            //
+            //  Generate the 8.3 name see if it matches our input name.
+            //
+
+            CdGenerate8dot3Name( IrpContext,
+                                 &Dirent->CdCaseFileName.FileName,
+                                 Dirent->DirentOffset,
+                                 FileContext->ShortName.FileName.Buffer,
+                                 &FileContext->ShortName.FileName.Length );
+
+            //
+            //  Check if this name matches.
+            //
+
+            if (CdIsNameInExpression( IrpContext,
+                                      Name,
+                                      &FileContext->ShortName,
+                                      0,
+                                      FALSE )) {
+
+                //
+                //  Let our caller know we found an entry.
+                //
+
+                Found = TRUE;
+            }
+
+            //
+            //  Break out of the loop.
+            //
+
+            break;
+        }
+
+        //
+        //  Continue until there are no more entries.
+        //
+
+    } while (CdLookupNextInitialFileDirent( IrpContext, Fcb, FileContext ));
+
+    //
+    //  If we find the file then collect all of the dirents.
+    //
+
+    if (Found) {
+
+        CdLookupLastFileDirent( IrpContext, Fcb, FileContext );
+
+    }
+
+    return Found;
+}
+
+\f
+BOOLEAN
+CdLookupNextInitialFileDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_ENUM_CONTEXT FileContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to walk through the directory until we find the
+    first possible dirent for file.  We are positioned at some point described
+    by the FileContext.  We will walk through any remaing dirents for the
+    current file until we find the first dirent for some subsequent file.
+
+    We can be called when we have found just one dirent for a file or all
+    of them.  We first check the CurrentDirContext.  In the typical
+    single-extent case this is unused.  Then we look to the InitialDirContext
+    which must be initialized.
+
+    This routine will save the initial DirContext to the PriorDirContext and
+    clean up any existing DirContext for the Prior or Current positions in
+    the enumeration context.
+
+Arguments:
+
+    Fcb - This is the directory to scan.
+
+    FileContext - This is the file enumeration context.  It is currently pointing
+        at some file in the directory.
+
+Return Value:
+
+--*/
+
+{
+    PRAW_DIRENT RawDirent;
+
+    PDIRENT_ENUM_CONTEXT CurrentDirContext;
+    PDIRENT_ENUM_CONTEXT TargetDirContext;
+    PCOMPOUND_DIRENT TempDirent;
+
+    BOOLEAN FoundDirent = FALSE;
+    BOOLEAN FoundLastDirent;
+
+    PAGED_CODE();
+
+    //
+    //  Start by saving the initial dirent of the current file as the
+    //  previous file.
+    //
+
+    TempDirent = FileContext->PriorDirent;
+    FileContext->PriorDirent = FileContext->InitialDirent;
+    FileContext->InitialDirent = TempDirent;
+
+    //
+    //  We will use the initial dirent of the prior file unless the
+    //  previous search returned multiple extents.
+    //
+
+    CurrentDirContext = &FileContext->PriorDirent->DirContext;
+
+    if (FlagOn( FileContext->Flags, FILE_CONTEXT_MULTIPLE_DIRENTS )) {
+
+        CurrentDirContext = &FileContext->CurrentDirent->DirContext;
+    }
+
+    //
+    //  Clear all of the flags and file size for the next file.
+    //
+
+    FileContext->Flags = 0;
+    FileContext->FileSize = 0;
+
+    FileContext->ShortName.FileName.Length = 0;
+
+    //
+    //  We always want to store the result into the updated initial dirent
+    //  context.
+    //
+
+    TargetDirContext = &FileContext->InitialDirent->DirContext;
+
+    //
+    //  Loop until we find the first dirent after the last dirent of the
+    //  current file.  We may not be at the last dirent for the current file yet
+    //  so we may walk forward looking for the last and then find the
+    //  initial dirent for the next file after that.
+    //
+
+    while (TRUE) {
+
+        //
+        //  Remember if the last dirent we visited was the last dirent for
+        //  a file.
+        //
+
+        RawDirent = CdRawDirent( IrpContext, CurrentDirContext );
+
+        FoundLastDirent = !FlagOn( CdRawDirentFlags( IrpContext, RawDirent ), CD_ATTRIBUTE_MULTI );
+
+        //
+        //  Try to find another dirent.
+        //
+
+        FoundDirent = CdLookupNextDirent( IrpContext,
+                                          Fcb,
+                                          CurrentDirContext,
+                                          TargetDirContext );
+
+        //
+        //  Exit the loop if no entry found.
+        //
+
+        if (!FoundDirent) {
+
+            break;
+
+        }
+
+        //
+        //  Update the in-memory dirent.
+        //
+
+        CdUpdateDirentFromRawDirent( IrpContext,
+                                     Fcb,
+                                     TargetDirContext,
+                                     &FileContext->InitialDirent->Dirent );
+
+        //
+        //  Exit the loop if we had the end for the previous file.
+        //
+
+        if (FoundLastDirent) {
+
+            break;
+        }
+
+        //
+        //  Always use a single dirent from this point on.
+        //
+
+        CurrentDirContext = TargetDirContext;
+    }
+
+    return FoundDirent;
+}
+
+\f
+VOID
+CdLookupLastFileDirent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PFILE_ENUM_CONTEXT FileContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called when we've found the matching initial dirent for
+    a file.  Now we want to find all of the dirents for a file as well as
+    compute the running total for the file size.
+
+    We also go out to the system use area and check whether this is an
+    XA sector.  In that case we will compute the real file size.
+
+    The dirent in the initial compound dirent has been updated from the
+    raw dirent when this routine is called.
+
+Arguments:
+
+    Fcb - Directory containing the entries for the file.
+
+    FileContext - Enumeration context for this search.  It currently points
+        to the first dirent of the file and the in-memory dirent has been
+        updated.
+
+Return Value:
+
+    None.  This routine may raise STATUS_FILE_CORRUPT.
+
+--*/
+
+{
+    XA_EXTENT_TYPE ExtentType = 0; /* ReactOS Change: GCC Uninit var */
+    PCOMPOUND_DIRENT CurrentCompoundDirent;
+    PDIRENT CurrentDirent;
+
+    BOOLEAN FirstPass = TRUE;
+    BOOLEAN FoundDirent;
+
+    PAGED_CODE();
+
+    //
+    //  The current dirent to look at is the initial dirent for the file.
+    //
+
+    CurrentCompoundDirent = FileContext->InitialDirent;
+
+    //
+    //  Loop until we reach the last dirent for the file.
+    //
+
+    while (TRUE) {
+
+        CurrentDirent = &CurrentCompoundDirent->Dirent;
+
+        //
+        //  Check if this extent has XA sectors.
+        //
+
+        if ((CurrentDirent->SystemUseOffset != 0) &&
+            FlagOn( Fcb->Vcb->VcbState, VCB_STATE_CDXA ) &&
+            CdCheckForXAExtent( IrpContext,
+                                CdRawDirent( IrpContext, &CurrentCompoundDirent->DirContext ),
+                                CurrentDirent )) {
+
+            //
+            //  Any previous dirent must describe XA sectors as well.
+            //
+
+            if (!FirstPass && (ExtentType != CurrentDirent->ExtentType)) {
+
+                CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+            }
+
+            //
+            //  If there are XA sectors then the data on the disk must
+            //  be correctly aligned on sectors and be an integral number of
+            //  sectors.  Only an issue if the logical block size is not
+            //  2048.
+            //
+
+            if (Fcb->Vcb->BlockSize != SECTOR_SIZE) {
+
+                //
+                //  We will do the following checks.
+                //
+                //      Data must start on a sector boundary.
+                //      Data length must be integral number of sectors.
+                //
+
+                if ((SectorBlockOffset( Fcb->Vcb, CurrentDirent->StartingOffset ) != 0) ||
+                    (SectorBlockOffset( Fcb->Vcb, CurrentDirent->DataLength ) != 0)) {
+
+                    CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+                }
+
+                //
+                //  If interleaved then both the file unit and interleave
+                //  gap must be integral number of sectors.
+                //
+
+                if ((CurrentDirent->FileUnitSize != 0) &&
+                    ((SectorBlockOffset( Fcb->Vcb, CurrentDirent->FileUnitSize ) != 0) ||
+                     (SectorBlockOffset( Fcb->Vcb, CurrentDirent->InterleaveGapSize ) != 0))) {
+
+                    CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+                }
+            }
+
+            //
+            //  If this is the first dirent then add the bytes for the RIFF
+            //  header.
+            //
+
+            if (FirstPass) {
+
+                FileContext->FileSize = sizeof( RIFF_HEADER );
+            }
+
+            //
+            //  Add the size of the mode2-form2 sector for each sector
+            //  we have here.
+            //
+
+            FileContext->FileSize += Int32x32To64( CurrentDirent->DataLength >> SECTOR_SHIFT,
+                                                   XA_SECTOR_SIZE);
+
+        } else {
+
+            //
+            //  This extent does not have XA sectors.  Any previous dirent
+            //  better not have XA sectors.
+            //
+
+            if (!FirstPass && (ExtentType != CurrentDirent->ExtentType)) {
+
+                CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+            }
+
+            //
+            //  Add these bytes to the file size.
+            //
+
+            FileContext->FileSize += CurrentDirent->DataLength;
+        }
+
+        //
+        //  If we are at the last dirent then exit.
+        //
+
+        if (!FlagOn( CurrentDirent->DirentFlags, CD_ATTRIBUTE_MULTI )) {
+
+            break;
+        }
+
+        //
+        //  Remember the extent type of the current extent.
+        //
+
+        ExtentType = CurrentDirent->ExtentType;
+
+        //
+        //  Look for the next dirent of the file.
+        //
+
+        FoundDirent = CdLookupNextDirent( IrpContext,
+                                          Fcb,
+                                          &CurrentCompoundDirent->DirContext,
+                                          &FileContext->CurrentDirent->DirContext );
+
+        //
+        //  If we didn't find the entry then this is a corrupt directory.
+        //
+
+        if (!FoundDirent) {
+
+            CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+        }
+
+        //
+        //  Remember the dirent we just found.
+        //
+
+        CurrentCompoundDirent = FileContext->CurrentDirent;
+        FirstPass = FALSE;
+
+        //
+        //  Look up all of the dirent information for the given dirent.
+        //
+
+        CdUpdateDirentFromRawDirent( IrpContext,
+                                     Fcb,
+                                     &CurrentCompoundDirent->DirContext,
+                                     &CurrentCompoundDirent->Dirent );
+
+        //
+        //  Set flag to show there were multiple extents.
+        //
+
+        SetFlag( FileContext->Flags, FILE_CONTEXT_MULTIPLE_DIRENTS );
+    }
+
+    return;
+}
+
+\f
+VOID
+CdCleanupFileContext (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFILE_ENUM_CONTEXT FileContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to cleanup the enumeration context for a file
+    search in a directory.  We will unpin any remaining Bcbs and free
+    any allocated buffers.
+
+Arguments:
+
+    FileContext - Enumeration context for the file search.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    PCOMPOUND_DIRENT CurrentCompoundDirent;
+    ULONG Count = 2;
+
+    PAGED_CODE();
+
+    //
+    //  Cleanup the individual compound dirents.
+    //
+
+    do {
+
+        CurrentCompoundDirent = &FileContext->Dirents[ Count ];
+        CdCleanupDirContext( IrpContext, &CurrentCompoundDirent->DirContext );
+        CdCleanupDirent( IrpContext, &CurrentCompoundDirent->Dirent );
+
+    } while (Count--);
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+ULONG
+CdCheckRawDirentBounds (
+    IN PIRP_CONTEXT IrpContext,
+    IN PDIRENT_ENUM_CONTEXT DirContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine takes a Dirent enumeration context and computes the offset
+    to the next dirent.  A non-zero value indicates the offset within this
+    sector.  A zero value indicates to move to the next sector.  If the
+    current dirent does not fit within the sector then we will raise
+    STATUS_CORRUPT.
+
+Arguments:
+
+    DirContext - Enumeration context indicating the current position in
+        the sector.
+
+Return Value:
+
+    ULONG - Offset to the next dirent in this sector or zero if the
+        next dirent is in the next sector.
+
+    This routine will raise on a dirent which does not fit into the
+    described data buffer.
+
+--*/
+
+{
+    ULONG NextDirentOffset;
+    PRAW_DIRENT RawDirent;
+
+    PAGED_CODE();
+
+    //
+    //  We should always have at least a byte still available in the
+    //  current buffer.
+    //
+
+    ASSERT( (DirContext->DataLength - DirContext->SectorOffset) >= 1 );
+
+    //
+    //  Get a pointer to the current dirent.
+    //
+
+    RawDirent = CdRawDirent( IrpContext, DirContext );
+
+    //
+    //  If the dirent length is non-zero then look at the current dirent.
+    //
+
+    if (RawDirent->DirLen != 0) {
+
+        //
+        //  Check the following bound for the dirent length.
+        //
+        //      - Fits in the available bytes in the sector.
+        //      - Is at least the minimal dirent size.
+        //      - Is large enough to hold the file name.
+        //
+
+        if ((RawDirent->DirLen > (DirContext->DataLength - DirContext->SectorOffset)) ||
+            (RawDirent->DirLen < MIN_RAW_DIRENT_LEN) ||
+            (RawDirent->DirLen < (MIN_RAW_DIRENT_LEN - 1 + RawDirent->FileIdLen))) {
+
+            CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+        }
+
+        //
+        //  Copy the dirent length field.
+        //
+
+        NextDirentOffset = RawDirent->DirLen;
+
+        //
+        //  If we are exactly at the next sector then tell our caller by
+        //  returning zero.
+        //
+
+        if (NextDirentOffset == (DirContext->DataLength - DirContext->SectorOffset)) {
+
+            NextDirentOffset = 0;
+        }
+
+    } else {
+
+        NextDirentOffset = 0;
+    }
+
+    return NextDirentOffset;
+}
+
+\f
+//
+//  Local support routine
+//
+
+XA_EXTENT_TYPE
+CdCheckForXAExtent (
+    IN PIRP_CONTEXT IrpContext,
+    IN PRAW_DIRENT RawDirent,
+    IN OUT PDIRENT Dirent
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to scan through the system use area to test if
+    the current dirent has the XA bit set.  The bit in the in-memory
+    dirent will be set as appropriate.
+
+Arguments:
+
+    RawDirent - Pointer to the on-disk dirent.
+
+    Dirent - Pointer to the in-memory dirent.  We will update this with the
+        appropriate XA flag.
+
+Return Value:
+
+    XA_EXTENT_TYPE - Type of physical extent for this on disk dirent.
+
+--*/
+
+{
+    XA_EXTENT_TYPE ExtentType = Form1Data;
+    PSYSTEM_USE_XA SystemUseArea;
+
+    PAGED_CODE();
+
+    //
+    //  Check if there is enough space for the XA system use area.
+    //
+
+    if (Dirent->DirentLength - Dirent->SystemUseOffset >= sizeof( SYSTEM_USE_XA )) {
+
+        SystemUseArea = Add2Ptr( RawDirent, Dirent->SystemUseOffset, PSYSTEM_USE_XA );
+
+        //
+        //  Check for a valid signature.
+        //
+
+        if (SystemUseArea->Signature == SYSTEM_XA_SIGNATURE) {
+
+            //
+            //  Check for an audio track.
+            //
+
+            if (FlagOn( SystemUseArea->Attributes, SYSTEM_USE_XA_DA )) {
+
+                ExtentType = CDAudio;
+
+            } else if (FlagOn( SystemUseArea->Attributes, SYSTEM_USE_XA_FORM2 )) {
+
+                //
+                //  Check for XA data.  Note that a number of discs (video CDs)
+                //  have files marked as type XA Mode 2 Form 1 (2048 bytes of 
+                //  user data),  but actually record these sectors as Mode2 Form 2 
+                //  (2352). We will fail to read these files,  since for M2F1,  
+                //  a normal read CD command is issued (as per SCSI specs).
+                //
+                
+                ExtentType = Mode2Form2Data;
+            }
+
+            Dirent->XAAttributes = SystemUseArea->Attributes;
+            Dirent->XAFileNumber = SystemUseArea->FileNumber;
+        }
+    }
+
+    Dirent->ExtentType = ExtentType;
+    return ExtentType;
+}
+
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/fieldoff.c b/reactos/drivers/filesystems/cdfs_new/fieldoff.c
new file mode 100755 (executable)
index 0000000..c307c10
--- /dev/null
@@ -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 );
+    }
+}
+
diff --git a/reactos/drivers/filesystems/cdfs_new/fileinfo.c b/reactos/drivers/filesystems/cdfs_new/fileinfo.c
new file mode 100755 (executable)
index 0000000..c357d3c
--- /dev/null
@@ -0,0 +1,1504 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    FileInfo.c
+
+Abstract:
+
+    This module implements the File Information routines for Cdfs called by
+    the Fsd/Fsp dispatch drivers.
+
+
+--*/
+
+#include "CdProcs.h"
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (CDFS_BUG_CHECK_FILEINFO)
+
+//
+//  Local support routines
+//
+
+VOID
+CdQueryBasicInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_BASIC_INFORMATION Buffer,
+    IN OUT PULONG Length
+    );
+
+VOID
+CdQueryStandardInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_STANDARD_INFORMATION Buffer,
+    IN OUT PULONG Length
+    );
+
+VOID
+CdQueryInternalInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_INTERNAL_INFORMATION Buffer,
+    IN OUT PULONG Length
+    );
+
+VOID
+CdQueryEaInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_EA_INFORMATION Buffer,
+    IN OUT PULONG Length
+    );
+
+VOID
+CdQueryPositionInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFILE_OBJECT FileObject,
+    IN OUT PFILE_POSITION_INFORMATION Buffer,
+    IN OUT PULONG Length
+    );
+
+NTSTATUS
+CdQueryNameInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFILE_OBJECT FileObject,
+    IN OUT PFILE_NAME_INFORMATION Buffer,
+    IN OUT PULONG Length
+    );
+
+NTSTATUS
+CdQueryAlternateNameInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PCCB Ccb,
+    IN OUT PFILE_NAME_INFORMATION Buffer,
+    IN OUT PULONG Length
+    );
+
+VOID
+CdQueryNetworkInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
+    IN OUT PULONG Length
+    );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdCommonQueryInfo)
+#pragma alloc_text(PAGE, CdCommonSetInfo)
+#pragma alloc_text(PAGE, CdFastQueryBasicInfo)
+#pragma alloc_text(PAGE, CdFastQueryStdInfo)
+#pragma alloc_text(PAGE, CdFastQueryNetworkInfo)
+#pragma alloc_text(PAGE, CdQueryAlternateNameInfo)
+#pragma alloc_text(PAGE, CdQueryBasicInfo)
+#pragma alloc_text(PAGE, CdQueryEaInfo)
+#pragma alloc_text(PAGE, CdQueryInternalInfo)
+#pragma alloc_text(PAGE, CdQueryNameInfo)
+#pragma alloc_text(PAGE, CdQueryNetworkInfo)
+#pragma alloc_text(PAGE, CdQueryPositionInfo)
+#pragma alloc_text(PAGE, CdQueryStandardInfo)
+#endif
+
+\f
+NTSTATUS
+CdCommonQueryInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This is the common routine for query file information called by both the
+    fsd and fsp threads.
+
+Arguments:
+
+    Irp - Supplies the Irp to process.
+
+Return Value:
+
+    NTSTATUS - The return status for this operation.
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    ULONG Length;
+    FILE_INFORMATION_CLASS FileInformationClass;
+    PFILE_ALL_INFORMATION Buffer;
+
+    TYPE_OF_OPEN TypeOfOpen;
+    PFCB Fcb;
+    PCCB Ccb;
+
+    BOOLEAN ReleaseFcb = FALSE;
+
+    PAGED_CODE();
+
+    //
+    //  Reference our input parameters to make things easier
+    //
+
+    Length = IrpSp->Parameters.QueryFile.Length;
+    FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
+    Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+    //
+    //  Decode the file object
+    //
+
+    TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  We only support query on file and directory handles.
+        //
+
+        switch (TypeOfOpen) {
+
+        case UserDirectoryOpen :
+        case UserFileOpen :
+
+            //
+            //  Acquire shared access to this file.  NOTE that this could be
+            //  a recursive acquire,  if we already preacquired in
+            //  CdAcquireForCreateSection().
+            //
+
+            CdAcquireFileShared( IrpContext, Fcb );
+            ReleaseFcb = TRUE;
+
+            //
+            //  Make sure we have the correct sizes for a directory.
+            //
+
+            if (!FlagOn( Fcb->FcbState, FCB_STATE_INITIALIZED )) {
+
+                ASSERT( TypeOfOpen == UserDirectoryOpen );
+                CdCreateInternalStream( IrpContext, Fcb->Vcb, Fcb );
+            }
+
+            //
+            //  Make sure the Fcb is in a usable condition.  This will raise
+            //  an error condition if the volume is unusable
+            //
+
+            CdVerifyFcbOperation( IrpContext, Fcb );
+
+            //
+            //  Based on the information class we'll do different
+            //  actions.  Each of hte procedures that we're calling fills
+            //  up the output buffer, if possible.  They will raise the
+            //  status STATUS_BUFFER_OVERFLOW for an insufficient buffer.
+            //  This is considered a somewhat unusual case and is handled
+            //  more cleanly with the exception mechanism rather than
+            //  testing a return status value for each call.
+            //
+
+            switch (FileInformationClass) {
+
+            case FileAllInformation:
+
+                //
+                //  We don't allow this operation on a file opened by file Id.
+                //
+
+                if (FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_ID )) {
+
+                    Status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+
+                //
+                //  In this case go ahead and call the individual routines to
+                //  fill in the buffer.  Only the name routine will
+                //  pointer to the output buffer and then call the
+                //  individual routines to fill in the buffer.
+                //
+
+                Length -= (sizeof( FILE_ACCESS_INFORMATION ) +
+                           sizeof( FILE_MODE_INFORMATION ) +
+                           sizeof( FILE_ALIGNMENT_INFORMATION ));
+
+                CdQueryBasicInfo( IrpContext, Fcb, &Buffer->BasicInformation, &Length );
+                CdQueryStandardInfo( IrpContext, Fcb, &Buffer->StandardInformation, &Length );
+                CdQueryInternalInfo( IrpContext, Fcb, &Buffer->InternalInformation, &Length );
+                CdQueryEaInfo( IrpContext, Fcb, &Buffer->EaInformation, &Length );
+                CdQueryPositionInfo( IrpContext, IrpSp->FileObject, &Buffer->PositionInformation, &Length );
+                Status = CdQueryNameInfo( IrpContext, IrpSp->FileObject, &Buffer->NameInformation, &Length );
+
+                break;
+
+            case FileBasicInformation:
+
+                CdQueryBasicInfo( IrpContext, Fcb, (PFILE_BASIC_INFORMATION) Buffer, &Length );
+                break;
+
+            case FileStandardInformation:
+
+                CdQueryStandardInfo( IrpContext, Fcb, (PFILE_STANDARD_INFORMATION) Buffer, &Length );
+                break;
+
+            case FileInternalInformation:
+
+                CdQueryInternalInfo( IrpContext, Fcb, (PFILE_INTERNAL_INFORMATION) Buffer, &Length );
+                break;
+
+            case FileEaInformation:
+
+                CdQueryEaInfo( IrpContext, Fcb, (PFILE_EA_INFORMATION) Buffer, &Length );
+                break;
+
+            case FilePositionInformation:
+
+                CdQueryPositionInfo( IrpContext, IrpSp->FileObject, (PFILE_POSITION_INFORMATION) Buffer, &Length );
+                break;
+
+            case FileNameInformation:
+
+                //
+                //  We don't allow this operation on a file opened by file Id.
+                //
+
+                if (!FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_ID )) {
+
+                    Status = CdQueryNameInfo( IrpContext, IrpSp->FileObject, (PFILE_NAME_INFORMATION) Buffer, &Length );
+
+                } else {
+
+                    Status = STATUS_INVALID_PARAMETER;
+                }
+
+                break;
+
+            case FileAlternateNameInformation:
+
+                if (!FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_ID )) {
+
+                    Status = CdQueryAlternateNameInfo( IrpContext, Fcb, Ccb, (PFILE_NAME_INFORMATION) Buffer, &Length );
+
+                } else {
+
+                    Status = STATUS_INVALID_PARAMETER;
+                }
+
+                break;
+
+            case FileNetworkOpenInformation:
+
+                CdQueryNetworkInfo( IrpContext, Fcb, (PFILE_NETWORK_OPEN_INFORMATION) Buffer, &Length );
+                break;
+
+            default :
+
+                Status = STATUS_INVALID_PARAMETER;
+            }
+
+            break;
+
+        default :
+
+            Status = STATUS_INVALID_PARAMETER;
+        }
+
+        //
+        //  Set the information field to the number of bytes actually filled in
+        //  and then complete the request
+        //
+
+        Irp->IoStatus.Information = IrpSp->Parameters.QueryFile.Length - Length;
+
+    } finally {
+
+        //
+        //  Release the file.
+        //
+
+        if (ReleaseFcb) {
+
+            CdReleaseFile( IrpContext, Fcb );
+        }
+    }
+
+    //
+    //  Complete the request if we didn't raise.
+    //
+
+    CdCompleteRequest( IrpContext, Irp, Status );
+
+    return Status;
+}
+
+\f
+NTSTATUS
+CdCommonSetInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This is the common routine for set file information called by both the
+    fsd and fsp threads.  We only support operations which set the file position.
+
+Arguments:
+
+    Irp - Supplies the Irp to process.
+
+Return Value:
+
+    NTSTATUS - The return status for this operation.
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+    TYPE_OF_OPEN TypeOfOpen;
+    PFCB Fcb;
+    PCCB Ccb;
+
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PFILE_POSITION_INFORMATION Buffer;
+
+    PAGED_CODE();
+
+    //
+    //  Decode the file object
+    //
+
+    TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
+
+    //
+    //  We only support a SetPositionInformation on a user file.
+    //
+
+    if ((TypeOfOpen != UserFileOpen) ||
+        (IrpSp->Parameters.QueryFile.FileInformationClass != FilePositionInformation)) {
+
+        CdCompleteRequest( IrpContext, Irp, Status );
+        return Status;
+    }
+
+    //
+    //  Acquire shared access to this file.
+    //
+
+    CdAcquireFileShared( IrpContext, Fcb );
+
+    try {
+
+        //
+        //  Make sure the Fcb is in a usable condition.  This
+        //  will raise an error condition if the fcb is unusable
+        //
+
+        CdVerifyFcbOperation( IrpContext, Fcb );
+
+        Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+        //
+        //  Check if the file does not use intermediate buffering.  If it
+        //  does not use intermediate buffering then the new position we're
+        //  supplied must be aligned properly for the device
+        //
+
+        if (FlagOn( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) &&
+            ((Buffer->CurrentByteOffset.LowPart & Fcb->Vcb->BlockMask) != 0)) {
+
+            try_return( NOTHING );
+        }
+
+        //
+        //  The input parameter is fine so set the current byte offset and
+        //  complete the request
+        //
+
+        //
+        //  Lock the Fcb to provide synchronization.
+        //
+
+        CdLockFcb( IrpContext, Fcb );
+        IrpSp->FileObject->CurrentByteOffset = Buffer->CurrentByteOffset;
+        CdUnlockFcb( IrpContext, Fcb );
+
+        Status = STATUS_SUCCESS;
+
+    try_exit: NOTHING;
+    } finally {
+
+        CdReleaseFile( IrpContext, Fcb );
+    }
+
+    //
+    //  Complete the request if there was no raise.
+    //
+
+    CdCompleteRequest( IrpContext, Irp, Status );
+    return Status;
+}
+
+\f
+BOOLEAN
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdFastQueryBasicInfo (
+    IN PFILE_OBJECT FileObject,
+    IN BOOLEAN Wait,
+    IN OUT PFILE_BASIC_INFORMATION Buffer,
+    OUT PIO_STATUS_BLOCK IoStatus,
+    IN PDEVICE_OBJECT DeviceObject
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is for the fast query call for basic file information.
+
+Arguments:
+
+    FileObject - Supplies the file object used in this operation
+
+    Wait - Indicates if we are allowed to wait for the information
+
+    Buffer - Supplies the output buffer to receive the basic information
+
+    IoStatus - Receives the final status of the operation
+
+Return Value:
+
+    BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
+        needs to take the long route.
+
+--*/
+
+{
+    BOOLEAN Result = FALSE;
+    TYPE_OF_OPEN TypeOfOpen;
+
+    PFCB Fcb;
+
+    PAGED_CODE();
+
+    ASSERT_FILE_OBJECT( FileObject );
+
+    FsRtlEnterFileSystem();
+
+    //
+    //  Decode the file object to find the type of open and the data
+    //  structures.
+    //
+
+    TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
+
+    //
+    //  We only support this request on user file or directory objects.
+    //
+
+    if ((TypeOfOpen != UserFileOpen) &&
+        ((TypeOfOpen != UserDirectoryOpen) || !FlagOn( Fcb->FcbState, FCB_STATE_INITIALIZED))) {
+
+        FsRtlExitFileSystem();
+        return FALSE;
+    }
+
+    //
+    //  Acquire the file shared to access the Fcb.
+    //
+
+    if (!ExAcquireResourceSharedLite( Fcb->Resource, Wait )) {
+
+        FsRtlExitFileSystem();
+        return FALSE;
+    }
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Only deal with 'good' Fcb's.
+        //
+
+        if (CdVerifyFcbOperation( NULL, Fcb )) {
+
+            //
+            //  Fill in the input buffer from the Fcb fields.
+            //
+
+            Buffer->CreationTime.QuadPart =
+            Buffer->LastWriteTime.QuadPart =
+            Buffer->ChangeTime.QuadPart = Fcb->CreationTime;
+
+            Buffer->LastAccessTime.QuadPart = 0;
+
+            Buffer->FileAttributes = Fcb->FileAttributes;
+
+            //
+            //  Update the IoStatus block with the size of this data.
+            //
+
+            IoStatus->Status = STATUS_SUCCESS;
+            IoStatus->Information = sizeof( FILE_BASIC_INFORMATION );
+
+            Result = TRUE;
+        }
+
+    } finally {
+
+        ExReleaseResourceLite( Fcb->Resource );
+
+        FsRtlExitFileSystem();
+    }
+
+    return Result;
+}
+
+\f
+BOOLEAN
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdFastQueryStdInfo (
+    IN PFILE_OBJECT FileObject,
+    IN BOOLEAN Wait,
+    IN OUT PFILE_STANDARD_INFORMATION Buffer,
+    OUT PIO_STATUS_BLOCK IoStatus,
+    IN PDEVICE_OBJECT DeviceObject
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is for the fast query call for standard file information.
+
+Arguments:
+
+    FileObject - Supplies the file object used in this operation
+
+    Wait - Indicates if we are allowed to wait for the information
+
+    Buffer - Supplies the output buffer to receive the basic information
+
+    IoStatus - Receives the final status of the operation
+
+Return Value:
+
+    BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
+        needs to take the long route.
+
+--*/
+
+{
+    BOOLEAN Result = FALSE;
+    TYPE_OF_OPEN TypeOfOpen;
+
+    PFCB Fcb;
+
+    PAGED_CODE();
+
+    ASSERT_FILE_OBJECT( FileObject );
+
+    FsRtlEnterFileSystem();
+
+    //
+    //  Decode the file object to find the type of open and the data
+    //  structures.
+    //
+
+    TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
+
+    //
+    //  We only support this request on initialized user file or directory objects.
+    //
+
+    if ((TypeOfOpen != UserFileOpen) &&
+        ((TypeOfOpen != UserDirectoryOpen) || !FlagOn( Fcb->FcbState, FCB_STATE_INITIALIZED ))) {
+
+        FsRtlExitFileSystem();
+        return FALSE;
+    }
+
+    //
+    //  Acquire the file shared to access the Fcb.
+    //
+
+    if (!ExAcquireResourceSharedLite( Fcb->Resource, Wait )) {
+
+        FsRtlExitFileSystem();
+        return FALSE;
+    }
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Only deal with 'good' Fcb's.
+        //
+
+        if (CdVerifyFcbOperation( NULL, Fcb )) {
+
+            //
+            //  Check whether this is a directory.
+            //
+
+            if (FlagOn( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
+
+                Buffer->AllocationSize.QuadPart =
+                Buffer->EndOfFile.QuadPart = 0;
+
+                Buffer->Directory = TRUE;
+
+            } else {
+
+                Buffer->AllocationSize.QuadPart = Fcb->AllocationSize.QuadPart;
+                Buffer->EndOfFile.QuadPart = Fcb->FileSize.QuadPart;
+
+                Buffer->Directory = FALSE;
+            }
+
+            Buffer->NumberOfLinks = 1;
+            Buffer->DeletePending = FALSE;
+
+            //
+            //  Update the IoStatus block with the size of this data.
+            //
+
+            IoStatus->Status = STATUS_SUCCESS;
+            IoStatus->Information = sizeof( FILE_STANDARD_INFORMATION );
+
+            Result = TRUE;
+        }
+
+    } finally {
+
+        ExReleaseResourceLite( Fcb->Resource );
+
+        FsRtlExitFileSystem();
+    }
+
+    return Result;
+}
+
+\f
+BOOLEAN
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdFastQueryNetworkInfo (
+    IN PFILE_OBJECT FileObject,
+    IN BOOLEAN Wait,
+    OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
+    OUT PIO_STATUS_BLOCK IoStatus,
+    IN PDEVICE_OBJECT DeviceObject
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is for the fast query call for network file information.
+
+Arguments:
+
+    FileObject - Supplies the file object used in this operation
+
+    Wait - Indicates if we are allowed to wait for the information
+
+    Buffer - Supplies the output buffer to receive the basic information
+
+    IoStatus - Receives the final status of the operation
+
+Return Value:
+
+    BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
+        needs to take the long route.
+
+--*/
+
+{
+    BOOLEAN Result = FALSE;
+    TYPE_OF_OPEN TypeOfOpen;
+
+    PFCB Fcb;
+
+    PAGED_CODE();
+
+    ASSERT_FILE_OBJECT( FileObject );
+
+    FsRtlEnterFileSystem();
+
+    //
+    //  Decode the file object to find the type of open and the data
+    //  structures.
+    //
+
+    TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
+
+    //
+    //  We only support this request on user file or directory objects.
+    //
+
+    if ((TypeOfOpen != UserFileOpen) &&
+        ((TypeOfOpen != UserDirectoryOpen) || !FlagOn( Fcb->FcbState, FCB_STATE_INITIALIZED))) {
+
+        FsRtlExitFileSystem();
+        return FALSE;
+    }
+
+    //
+    //  Acquire the file shared to access the Fcb.
+    //
+
+    if (!ExAcquireResourceSharedLite( Fcb->Resource, Wait )) {
+
+        FsRtlExitFileSystem();
+        return FALSE;
+    }
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Only deal with 'good' Fcb's.
+        //
+
+        if (CdVerifyFcbOperation( NULL, Fcb )) {
+
+            //
+            //  Fill in the input buffer from the Fcb fields.
+            //
+
+            Buffer->CreationTime.QuadPart =
+            Buffer->LastWriteTime.QuadPart =
+            Buffer->ChangeTime.QuadPart = Fcb->CreationTime;
+
+            Buffer->LastAccessTime.QuadPart = 0;
+
+            Buffer->FileAttributes = Fcb->FileAttributes;
+
+            //
+            //  Check whether this is a directory.
+            //
+
+            if (FlagOn( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
+
+                Buffer->AllocationSize.QuadPart =
+                Buffer->EndOfFile.QuadPart = 0;
+
+            } else {
+
+                Buffer->AllocationSize.QuadPart = Fcb->AllocationSize.QuadPart;
+                Buffer->EndOfFile.QuadPart = Fcb->FileSize.QuadPart;
+            }
+
+            //
+            //  Update the IoStatus block with the size of this data.
+            //
+
+            IoStatus->Status = STATUS_SUCCESS;
+            IoStatus->Information = sizeof( FILE_NETWORK_OPEN_INFORMATION );
+
+            Result = TRUE;
+        }
+
+    } finally {
+
+        ExReleaseResourceLite( Fcb->Resource );
+
+        FsRtlExitFileSystem();
+    }
+
+    return Result;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdQueryBasicInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_BASIC_INFORMATION Buffer,
+    IN OUT PULONG Length
+    )
+
+/*++
+
+ Description:
+
+    This routine performs the query basic information function for Cdfs
+
+Arguments:
+
+    Fcb - Supplies the Fcb being queried, it has been verified
+
+    Buffer - Supplies a pointer to the buffer where the information is to
+        be returned
+
+    Length - Supplies the length of the buffer in bytes, and receives the
+        remaining bytes free in the buffer upon return.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  We only support creation, last modify and last write times on Cdfs.
+    //
+
+    Buffer->LastWriteTime.QuadPart =
+    Buffer->CreationTime.QuadPart =
+    Buffer->ChangeTime.QuadPart = Fcb->CreationTime;
+
+    Buffer->LastAccessTime.QuadPart = 0;
+
+    Buffer->FileAttributes = Fcb->FileAttributes;
+
+    //
+    //  Update the length and status output variables
+    //
+
+    *Length -= sizeof( FILE_BASIC_INFORMATION );
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdQueryStandardInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_STANDARD_INFORMATION Buffer,
+    IN OUT PULONG Length
+    )
+/*++
+
+Routine Description:
+
+    This routine performs the query standard information function for cdfs.
+
+Arguments:
+
+    Fcb - Supplies the Fcb being queried, it has been verified
+
+    Buffer - Supplies a pointer to the buffer where the information is to
+        be returned
+
+    Length - Supplies the length of the buffer in bytes, and receives the
+        remaining bytes free in the buffer upon return.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  There is only one link and delete is never pending on a Cdrom file.
+    //
+
+    Buffer->NumberOfLinks = 1;
+    Buffer->DeletePending = FALSE;
+
+    //
+    //  We get the sizes from the header.  Return a size of zero
+    //  for all directories.
+    //
+
+    if (FlagOn( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
+
+        Buffer->AllocationSize.QuadPart =
+        Buffer->EndOfFile.QuadPart = 0;
+
+        Buffer->Directory = TRUE;
+
+    } else {
+
+        Buffer->AllocationSize.QuadPart = Fcb->AllocationSize.QuadPart;
+        Buffer->EndOfFile.QuadPart = Fcb->FileSize.QuadPart;
+
+        Buffer->Directory = FALSE;
+    }
+
+    //
+    //  Update the length and status output variables
+    //
+
+    *Length -= sizeof( FILE_STANDARD_INFORMATION );
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdQueryInternalInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_INTERNAL_INFORMATION Buffer,
+    IN OUT PULONG Length
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the query internal information function for cdfs.
+
+Arguments:
+
+    Fcb - Supplies the Fcb being queried, it has been verified
+
+    Buffer - Supplies a pointer to the buffer where the information is to
+        be returned
+
+    Length - Supplies the length of the buffer in bytes, and receives the
+        remaining bytes free in the buffer upon return.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  Index number is the file Id number in the Fcb.
+    //
+
+    Buffer->IndexNumber = Fcb->FileId;
+    *Length -= sizeof( FILE_INTERNAL_INFORMATION );
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdQueryEaInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_EA_INFORMATION Buffer,
+    IN OUT PULONG Length
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the query Ea information function for cdfs.
+
+Arguments:
+
+    Fcb - Supplies the Fcb being queried, it has been verified
+
+    Buffer - Supplies a pointer to the buffer where the information is to
+        be returned
+
+    Length - Supplies the length of the buffer in bytes, and receives the
+        remaining bytes free in the buffer upon return.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  No Ea's on Cdfs volumes.
+    //
+
+    Buffer->EaSize = 0;
+    *Length -= sizeof( FILE_EA_INFORMATION );
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdQueryPositionInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFILE_OBJECT FileObject,
+    IN OUT PFILE_POSITION_INFORMATION Buffer,
+    IN OUT PULONG Length
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the query position information function for cdfs.
+
+Arguments:
+
+    FileObject - Supplies the File object being queried
+
+    Buffer - Supplies a pointer to the buffer where the information is to
+        be returned
+
+    Length - Supplies the length of the buffer in bytes, and receives the
+        remaining bytes free in the buffer upon return.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  Get the current position found in the file object.
+    //
+
+    Buffer->CurrentByteOffset = FileObject->CurrentByteOffset;
+
+    //
+    //  Update the length and status output variables
+    //
+
+    *Length -= sizeof( FILE_POSITION_INFORMATION );
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdQueryNameInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFILE_OBJECT FileObject,
+    IN OUT PFILE_NAME_INFORMATION Buffer,
+    IN OUT PULONG Length
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the query name information function for cdfs.
+
+Arguments:
+
+    FileObject - Supplies the file object containing the name.
+
+    Buffer - Supplies a pointer to the buffer where the information is to
+        be returned
+
+    Length - Supplies the length of the buffer in bytes, and receives the
+        remaining bytes free in the buffer upon return.
+
+Return Value:
+
+    NTSTATUS - STATUS_BUFFER_OVERFLOW if the entire name can't be copied.
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG LengthToCopy;
+
+    PAGED_CODE();
+
+    ASSERT(*Length >= sizeof(ULONG));
+    
+    //
+    //  Simply copy the name in the file object to the user's buffer.
+    //
+
+    //
+    //  Place the size of the filename in the user's buffer and reduce the remaining
+    //  size to match.
+    //
+
+    Buffer->FileNameLength = LengthToCopy = FileObject->FileName.Length;
+    *Length -= sizeof(ULONG);
+
+    if (LengthToCopy > *Length) {
+
+        LengthToCopy = *Length;
+        Status = STATUS_BUFFER_OVERFLOW;
+    }
+
+    RtlCopyMemory( Buffer->FileName, FileObject->FileName.Buffer, LengthToCopy );
+
+    //
+    //  Reduce the available bytes by the amount stored into this buffer.  In the overflow
+    //  case, this simply drops to zero.  The returned filenamelength will indicate to the
+    //  caller how much space is required.
+    //
+
+    *Length -= LengthToCopy;
+
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdQueryAlternateNameInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PCCB Ccb,
+    IN OUT PFILE_NAME_INFORMATION Buffer,
+    IN OUT PULONG Length
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the query alternate name information function.
+    We lookup the dirent for this file and then check if there is a
+    short name.
+
+Arguments:
+
+    Fcb - Supplies the Fcb being queried, it has been verified.
+
+    Ccb - Ccb for this open handle.
+
+    Buffer - Supplies a pointer to the buffer where the information is to
+        be returned.
+
+    Length - Supplies the length of the buffer in bytes, and receives the
+        remaining bytes free in the buffer upon return.
+
+Return Value:
+
+    NTSTATUS - STATUS_SUCCESS if the whole name would fit into the user buffer,
+               STATUS_OBJECT_NAME_NOT_FOUND if we can't return the name,
+               STATUS_BUFFER_OVERFLOW otherwise.
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    DIRENT_ENUM_CONTEXT DirContext;
+    DIRENT Dirent;
+
+    PUNICODE_STRING NameToUse;
+    ULONG DirentOffset;
+
+    COMPOUND_PATH_ENTRY CompoundPathEntry;
+    FILE_ENUM_CONTEXT FileContext;
+
+    PFCB ParentFcb;
+    BOOLEAN ReleaseParentFcb = FALSE;
+
+    BOOLEAN CleanupFileLookup = FALSE;
+    BOOLEAN CleanupDirectoryLookup = FALSE;
+
+    WCHAR ShortNameBuffer[ BYTE_COUNT_8_DOT_3 / 2 ];
+    USHORT ShortNameLength;
+
+    PAGED_CODE();
+
+    //
+    //  Initialize the buffer length to zero.
+    //
+
+    Buffer->FileNameLength = 0;
+
+    //
+    //  If this is the root or this file was opened using a version number then
+    //  there is no short name.
+    //
+
+    if ((Fcb == Fcb->Vcb->RootIndexFcb) ||
+        FlagOn( Ccb->Flags, CCB_FLAG_OPEN_WITH_VERSION)) {
+
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
+
+    //
+    //  Use a try-finally to cleanup the structures.
+    //
+
+    try {
+
+        ParentFcb = Fcb->ParentFcb;
+        CdAcquireFileShared( IrpContext, ParentFcb );
+        ReleaseParentFcb = TRUE;
+    
+        //
+        //  Do an unsafe test to see if we need to create a file object.
+        //
+
+        if (ParentFcb->FileObject == NULL) {
+
+            CdCreateInternalStream( IrpContext, ParentFcb->Vcb, ParentFcb );
+        }
+
+        if (CdFidIsDirectory( Fcb->FileId)) {
+
+            //
+            //  Fcb is for a directory, so we need to dig the dirent from the parent.  In
+            //  order to do this we need to get the name of the directory from its pathtable
+            //  entry and then search in the parent for a matching dirent.
+            //
+            //  This could be optimized somewhat.
+            //
+
+            CdInitializeCompoundPathEntry( IrpContext, &CompoundPathEntry );
+            CdInitializeFileContext( IrpContext, &FileContext );
+
+            CleanupDirectoryLookup = TRUE;
+
+            CdLookupPathEntry( IrpContext,
+                               CdQueryFidPathTableOffset( Fcb->FileId ),
+                               Fcb->Ordinal,
+                               FALSE,
+                               &CompoundPathEntry );
+
+            CdUpdatePathEntryName( IrpContext, &CompoundPathEntry.PathEntry, TRUE );
+
+            if (!CdFindDirectory( IrpContext,
+                                  ParentFcb,
+                                  &CompoundPathEntry.PathEntry.CdCaseDirName,
+                                  TRUE,
+                                  &FileContext )) {
+
+                //
+                //  If we failed to find the child directory by name in the parent
+                //  something is quite wrong with this disc.
+                //
+
+                CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
+            }
+
+            NameToUse = &FileContext.InitialDirent->Dirent.CdCaseFileName.FileName;
+            DirentOffset = FileContext.InitialDirent->Dirent.DirentOffset;
+        
+        } else {
+
+            //
+            //  Initialize the search dirent structures.
+            //
+        
+            CdInitializeDirContext( IrpContext, &DirContext );
+            CdInitializeDirent( IrpContext, &Dirent );
+    
+            CleanupFileLookup = TRUE;
+        
+            CdLookupDirent( IrpContext,
+                            ParentFcb,
+                            CdQueryFidDirentOffset( Fcb->FileId ),
+                            &DirContext );
+    
+            CdUpdateDirentFromRawDirent( IrpContext,
+                                         ParentFcb,
+                                         &DirContext,
+                                         &Dirent );
+
+            //
+            //  Now update the dirent name.
+            //
+    
+            CdUpdateDirentName( IrpContext, &Dirent, TRUE );
+    
+            NameToUse = &Dirent.CdCaseFileName.FileName;
+            DirentOffset = Dirent.DirentOffset;
+        }
+
+        //
+        //  If the name is 8.3 then fail this request.
+        //
+
+        if (CdIs8dot3Name( IrpContext,
+                           *NameToUse )) {
+
+
+            try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND );
+        }
+
+        CdGenerate8dot3Name( IrpContext,
+                             NameToUse,
+                             DirentOffset,
+                             ShortNameBuffer,
+                             &ShortNameLength );
+
+        //
+        //  We now have the short name.  We have left it in Unicode form so copy it directly.
+        //
+
+        Buffer->FileNameLength = ShortNameLength;
+
+        if (Buffer->FileNameLength + sizeof( ULONG ) > *Length) {
+
+            Buffer->FileNameLength = *Length - sizeof( ULONG );
+            Status = STATUS_BUFFER_OVERFLOW;
+        }
+
+        RtlCopyMemory( Buffer->FileName, ShortNameBuffer, Buffer->FileNameLength );
+
+    try_exit:  NOTHING;
+    } finally {
+
+        if (CleanupFileLookup) {
+
+            CdCleanupDirContext( IrpContext, &DirContext );
+            CdCleanupDirent( IrpContext, &Dirent );
+
+        } else if (CleanupDirectoryLookup) {
+
+            CdCleanupCompoundPathEntry( IrpContext, &CompoundPathEntry );
+            CdCleanupFileContext( IrpContext, &FileContext );
+        }
+
+        if (ReleaseParentFcb) {
+
+            CdReleaseFile( IrpContext, ParentFcb );
+        }
+    }
+
+    //
+    //  Reduce the available bytes by the amount stored into this buffer.
+    //
+
+    if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+
+        *Length -= sizeof( ULONG ) + Buffer->FileNameLength;
+    }
+
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdQueryNetworkInfo (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
+    IN OUT PULONG Length
+    )
+
+/*++
+
+ Description:
+
+    This routine performs the query network open information function for Cdfs
+
+Arguments:
+
+    Fcb - Supplies the Fcb being queried, it has been verified
+
+    Buffer - Supplies a pointer to the buffer where the information is to
+        be returned
+
+    Length - Supplies the length of the buffer in bytes, and receives the
+        remaining bytes free in the buffer upon return.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  We only support creation, last modify and last write times on Cdfs.
+    //
+
+    Buffer->LastWriteTime.QuadPart =
+    Buffer->CreationTime.QuadPart =
+    Buffer->ChangeTime.QuadPart = Fcb->CreationTime;
+
+    Buffer->LastAccessTime.QuadPart = 0;
+
+    Buffer->FileAttributes = Fcb->FileAttributes;
+
+    //
+    //  We get the sizes from the header.  Return a size of zero
+    //  for all directories.
+    //
+
+    if (FlagOn( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
+
+        Buffer->AllocationSize.QuadPart =
+        Buffer->EndOfFile.QuadPart = 0;
+
+    } else {
+
+        Buffer->AllocationSize.QuadPart = Fcb->AllocationSize.QuadPart;
+        Buffer->EndOfFile.QuadPart = Fcb->FileSize.QuadPart;
+    }
+
+    //
+    //  Update the length and status output variables
+    //
+
+    *Length -= sizeof( FILE_NETWORK_OPEN_INFORMATION );
+
+    return;
+}
+
diff --git a/reactos/drivers/filesystems/cdfs_new/filobsup.c b/reactos/drivers/filesystems/cdfs_new/filobsup.c
new file mode 100755 (executable)
index 0000000..909d1a8
--- /dev/null
@@ -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
+
+\f
+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;
+}
+
+
+\f
+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;
+}
+
+\f
+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 );
+}
+
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/fsctrl.c b/reactos/drivers/filesystems/cdfs_new/fsctrl.c
new file mode 100755 (executable)
index 0000000..f2a9db1
--- /dev/null
@@ -0,0 +1,3167 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    FsCtrl.c
+
+Abstract:
+
+    This module implements the File System Control routines for Cdfs called
+    by the Fsd/Fsp dispatch drivers.
+
+
+--*/
+
+#include "CdProcs.h"
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (CDFS_BUG_CHECK_FSCTRL)
+
+//
+//  Local constants
+//
+
+BOOLEAN CdDisable = FALSE;
+BOOLEAN CdNoJoliet = FALSE;
+
+//
+//  Local support routines
+//
+
+NTSTATUS
+CdUserFsctl (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+VOID
+CdReMountOldVcb(
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB OldVcb,
+    IN PVCB NewVcb,
+    IN PDEVICE_OBJECT DeviceObjectWeTalkTo
+    );
+
+NTSTATUS
+CdMountVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdVerifyVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdOplockRequest (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdLockVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdUnlockVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdDismountVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+    
+NTSTATUS /* ReactOS Change: Function did not have a type??? */
+CdIsVolumeDirty (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdIsVolumeMounted (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdIsPathnameValid (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+CdInvalidateVolumes (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    );
+
+VOID
+CdScanForDismountedVcb (
+    IN PIRP_CONTEXT IrpContext
+    );
+
+BOOLEAN
+CdFindPrimaryVd (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PCHAR RawIsoVd,
+    IN ULONG BlockFactor,
+    IN BOOLEAN ReturnOnError,
+    IN BOOLEAN VerifyVolume
+    );
+
+BOOLEAN
+CdIsRemount (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    OUT PVCB *OldVcb
+    );
+
+VOID
+CdFindActiveVolDescriptor (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN OUT PCHAR RawIsoVd,
+    IN BOOLEAN VerifyVolume
+    );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdCommonFsControl)
+#pragma alloc_text(PAGE, CdDismountVolume)
+#pragma alloc_text(PAGE, CdFindActiveVolDescriptor)
+#pragma alloc_text(PAGE, CdFindPrimaryVd)
+#pragma alloc_text(PAGE, CdIsPathnameValid)
+#pragma alloc_text(PAGE, CdIsRemount)
+#pragma alloc_text(PAGE, CdIsVolumeDirty)
+#pragma alloc_text(PAGE, CdIsVolumeMounted)
+#pragma alloc_text(PAGE, CdLockVolume)
+#pragma alloc_text(PAGE, CdMountVolume)
+#pragma alloc_text(PAGE, CdOplockRequest)
+#pragma alloc_text(PAGE, CdScanForDismountedVcb)
+#pragma alloc_text(PAGE, CdUnlockVolume)
+#pragma alloc_text(PAGE, CdUserFsctl)
+#pragma alloc_text(PAGE, CdVerifyVolume)
+#endif
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdLockVolumeInternal (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PFILE_OBJECT FileObject OPTIONAL
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the actual lock volume operation.  It will be called
+    by anyone wishing to try to protect the volume for a long duration.  PNP
+    operations are such a user.
+    
+    The volume must be held exclusive by the caller.
+
+Arguments:
+
+    Vcb - The volume being locked.
+    
+    FileObject - File corresponding to the handle locking the volume.  If this
+        is not specified, a system lock is assumed.
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    NTSTATUS Status;
+    KIRQL SavedIrql;
+    NTSTATUS FinalStatus = (FileObject? STATUS_ACCESS_DENIED: STATUS_DEVICE_BUSY);
+    ULONG RemainingUserReferences = (FileObject? 1: 0);
+
+    //
+    //  The cleanup count for the volume only reflects the fileobject that
+    //  will lock the volume.  Otherwise, we must fail the request.
+    //
+    //  Since the only cleanup is for the provided fileobject, we will try
+    //  to get rid of all of the other user references.  If there is only one
+    //  remaining after the purge then we can allow the volume to be locked.
+    //
+    
+    CdPurgeVolume( IrpContext, Vcb, FALSE );
+
+    //
+    //  Now back out of our synchronization and wait for the lazy writer
+    //  to finish off any lazy closes that could have been outstanding.
+    //
+    //  Since we purged, we know that the lazy writer will issue all
+    //  possible lazy closes in the next tick - if we hadn't, an otherwise
+    //  unopened file with a large amount of dirty data could have hung
+    //  around for a while as the data trickled out to the disk.
+    //
+    //  This is even more important now since we send notification to
+    //  alert other folks that this style of check is about to happen so
+    //  that they can close their handles.  We don't want to enter a fast
+    //  race with the lazy writer tearing down his references to the file.
+    //
+
+    CdReleaseVcb( IrpContext, Vcb );
+
+    Status = CcWaitForCurrentLazyWriterActivity();
+
+    //
+    //  This is intentional. If we were able to get the Vcb before, just
+    //  wait for it and take advantage of knowing that it is OK to leave
+    //  the flag up.
+    //
+
+    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
+    CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
+    
+    if (!NT_SUCCESS( Status )) {
+
+        return Status;
+    }
+
+    CdFspClose( Vcb );
+
+    //
+    //  If the volume is already explicitly locked then fail.  We use the
+    //  Vpb locked flag as an 'explicit lock' flag in the same way as Fat.
+    //
+
+    IoAcquireVpbSpinLock( &SavedIrql ); 
+        
+    if (!FlagOn( Vcb->Vpb->Flags, VPB_LOCKED ) && 
+        (Vcb->VcbCleanup == RemainingUserReferences) &&
+        (Vcb->VcbUserReference == CDFS_RESIDUAL_USER_REFERENCE + RemainingUserReferences))  {
+
+        SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
+        SetFlag( Vcb->Vpb->Flags, VPB_LOCKED);
+        Vcb->VolumeLockFileObject = FileObject;
+        FinalStatus = STATUS_SUCCESS;
+    }
+    
+    IoReleaseVpbSpinLock( SavedIrql );  
+    
+    return FinalStatus;
+}
+
+\f
+NTSTATUS
+CdUnlockVolumeInternal (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PFILE_OBJECT FileObject OPTIONAL
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the actual unlock volume operation. 
+    
+    The volume must be held exclusive by the caller.
+
+Arguments:
+
+    Vcb - The volume being locked.
+    
+    FileObject - File corresponding to the handle locking the volume.  If this
+        is not specified, a system lock is assumed.
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+    
+    Attempting to remove a system lock that did not exist is OK.
+
+--*/
+
+{
+    NTSTATUS Status = STATUS_NOT_LOCKED;
+    KIRQL SavedIrql;
+
+    //
+    //  Note that we check the VPB_LOCKED flag here rather than the Vcb
+    //  lock flag.  The Vpb flag is only set for an explicit lock request,  not
+    //  for the implicit lock obtained on a volume open with zero share mode.
+    //
+    
+    IoAcquireVpbSpinLock( &SavedIrql ); 
+    if (FlagOn(Vcb->Vpb->Flags, VPB_LOCKED) && 
+        (FileObject == Vcb->VolumeLockFileObject))  {
+
+        ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED );
+        ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED);
+        Vcb->VolumeLockFileObject = NULL;
+        Status = STATUS_SUCCESS;
+    }
+    
+    IoReleaseVpbSpinLock( SavedIrql );  
+
+    return Status;
+}
+
+\f
+NTSTATUS
+CdCommonFsControl (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This is the common routine for doing FileSystem control 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;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    //
+    //  Get a pointer to the current Irp stack location
+    //
+
+    IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PAGED_CODE();
+
+    //
+    //  We know this is a file system control so we'll case on the
+    //  minor function, and call a internal worker routine to complete
+    //  the irp.
+    //
+
+    switch (IrpSp->MinorFunction) {
+
+    case IRP_MN_USER_FS_REQUEST:
+
+        Status = CdUserFsctl( IrpContext, Irp );
+        break;
+
+    case IRP_MN_MOUNT_VOLUME:
+
+        Status = CdMountVolume( IrpContext, Irp );
+        break;
+
+    case IRP_MN_VERIFY_VOLUME:
+
+        Status = CdVerifyVolume( IrpContext, Irp );
+        break;
+
+    default:
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
+        Status = STATUS_INVALID_DEVICE_REQUEST;
+        break;
+    }
+
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdUserFsctl (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+/*++
+
+Routine Description:
+
+    This is the common routine for implementing the user's requests made
+    through NtFsControlFile.
+
+Arguments:
+
+    Irp - Supplies the Irp being processed
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PAGED_CODE();
+
+    //
+    //  Case on the control code.
+    //
+
+    switch ( IrpSp->Parameters.FileSystemControl.FsControlCode ) {
+
+    case FSCTL_REQUEST_OPLOCK_LEVEL_1 :
+    case FSCTL_REQUEST_OPLOCK_LEVEL_2 :
+    case FSCTL_REQUEST_BATCH_OPLOCK :
+    case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE :
+    case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
+    case FSCTL_OPLOCK_BREAK_NOTIFY :
+    case FSCTL_OPLOCK_BREAK_ACK_NO_2 :
+    case FSCTL_REQUEST_FILTER_OPLOCK :
+
+        Status = CdOplockRequest( IrpContext, Irp );
+        break;
+
+    case FSCTL_LOCK_VOLUME :
+
+        Status = CdLockVolume( IrpContext, Irp );
+        break;
+
+    case FSCTL_UNLOCK_VOLUME :
+
+        Status = CdUnlockVolume( IrpContext, Irp );
+        break;
+
+    case FSCTL_DISMOUNT_VOLUME :
+
+        Status = CdDismountVolume( IrpContext, Irp );
+        break;
+
+    case FSCTL_IS_VOLUME_DIRTY :
+
+        Status = CdIsVolumeDirty( IrpContext, Irp );
+        break;
+
+    case FSCTL_IS_VOLUME_MOUNTED :
+
+        Status = CdIsVolumeMounted( IrpContext, Irp );
+        break;
+
+    case FSCTL_IS_PATHNAME_VALID :
+
+        Status = CdIsPathnameValid( IrpContext, Irp );
+        break;
+
+    case FSCTL_INVALIDATE_VOLUMES :
+
+        Status = CdInvalidateVolumes( IrpContext, Irp );
+        break;
+
+
+    //
+    //  We don't support any of the known or unknown requests.
+    //
+
+    default:
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
+        Status = STATUS_INVALID_DEVICE_REQUEST;
+        break;
+    }
+
+    return Status;
+}
+
+
+VOID
+CdReMountOldVcb(
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB OldVcb,
+    IN PVCB NewVcb,
+    IN PDEVICE_OBJECT DeviceObjectWeTalkTo
+    )
+{
+    KIRQL SavedIrql;
+    
+    ObDereferenceObject( OldVcb->TargetDeviceObject );
+
+    IoAcquireVpbSpinLock( &SavedIrql );
+
+    NewVcb->Vpb->RealDevice->Vpb = OldVcb->Vpb;
+    
+    OldVcb->Vpb->RealDevice = NewVcb->Vpb->RealDevice;
+    OldVcb->TargetDeviceObject = DeviceObjectWeTalkTo;
+    
+    CdUpdateVcbCondition( OldVcb, VcbMounted);
+    CdUpdateMediaChangeCount( OldVcb, NewVcb->MediaChangeCount);
+
+    ClearFlag( OldVcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE);
+
+    IoReleaseVpbSpinLock( SavedIrql );
+}
+
+
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdMountVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the mount volume operation.  It is responsible for
+    either completing of enqueuing the input Irp.
+
+    Its job is to verify that the volume denoted in the IRP is a Cdrom volume,
+    and create the VCB and root DCB structures.  The algorithm it
+    uses is essentially as follows:
+
+    1. Create a new Vcb Structure, and initialize it enough to do I/O
+       through the on-disk volume descriptors.
+
+    2. Read the disk and check if it is a Cdrom volume.
+
+    3. If it is not a Cdrom volume then delete the Vcb and
+       complete the IRP back with an appropriate status.
+
+    4. Check if the volume was previously mounted and if it was then do a
+       remount operation.  This involves deleting the VCB, hook in the
+       old VCB, and complete the IRP.
+
+    5. Otherwise create a Vcb and root DCB for each valid volume descriptor.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    NTSTATUS Status;
+
+    PVOLUME_DEVICE_OBJECT VolDo = NULL;
+    PVCB Vcb = NULL;
+    PVCB OldVcb;
+    
+    BOOLEAN FoundPvd = FALSE;
+    BOOLEAN SetDoVerifyOnFail;
+
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+    PDEVICE_OBJECT DeviceObjectWeTalkTo = IrpSp->Parameters.MountVolume.DeviceObject;
+    PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb;
+
+    PFILE_OBJECT FileObjectToNotify = NULL;
+
+    ULONG BlockFactor;
+    DISK_GEOMETRY DiskGeometry;
+
+    IO_SCSI_CAPABILITIES Capabilities;
+
+    IO_STATUS_BLOCK Iosb;
+
+    PCHAR RawIsoVd = NULL;
+
+    PCDROM_TOC CdromToc = NULL;
+    ULONG TocLength = 0;
+    ULONG TocTrackCount = 0;
+    ULONG TocDiskFlags = 0;
+    ULONG MediaChangeCount = 0;
+
+    PAGED_CODE();
+
+    //
+    //  Check that we are talking to a Cdrom device.  This request should
+    //  always be waitable.
+    //
+
+    ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM );
+    ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ));
+
+    //
+    //  Update the real device in the IrpContext from the Vpb.  There was no available
+    //  file object when the IrpContext was created.
+    //
+
+    IrpContext->RealDevice = Vpb->RealDevice;
+
+    SetDoVerifyOnFail = CdRealDevNeedsVerify( IrpContext->RealDevice);
+
+    //
+    //  Check if we have disabled the mount process.
+    //
+
+    if (CdDisable) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
+        return STATUS_UNRECOGNIZED_VOLUME;
+    }
+
+    //
+    //  Do a CheckVerify here to lift the MediaChange ticker from the driver
+    //
+
+    Status = CdPerformDevIoCtrl( IrpContext,
+                                 IOCTL_CDROM_CHECK_VERIFY,
+                                 DeviceObjectWeTalkTo,
+                                 &MediaChangeCount,
+                                 sizeof(ULONG),
+                                 FALSE,
+                                 TRUE,
+                                 &Iosb );
+
+    if (!NT_SUCCESS( Status )) {
+        
+        CdCompleteRequest( IrpContext, Irp, Status );
+        return Status;
+    }
+    
+    if (Iosb.Information != sizeof(ULONG)) {
+
+        //
+        //  Be safe about the count in case the driver didn't fill it in
+        //
+
+        MediaChangeCount = 0;
+    }
+
+    //
+    //  Now let's make Jeff delirious and call to get the disk geometry.  This
+    //  will fix the case where the first change line is swallowed.
+    //
+
+    Status = CdPerformDevIoCtrl( IrpContext,
+                                 IOCTL_CDROM_GET_DRIVE_GEOMETRY,
+                                 DeviceObjectWeTalkTo,
+                                 &DiskGeometry,
+                                 sizeof( DISK_GEOMETRY ),
+                                 FALSE,
+                                 TRUE,
+                                 NULL );
+
+    //
+    //  Return insufficient sources to our caller.
+    //
+
+    if (Status == STATUS_INSUFFICIENT_RESOURCES) {
+
+        CdCompleteRequest( IrpContext, Irp, Status );
+        return Status;
+    }
+
+    //
+    //  Now check the block factor for addressing the volume descriptors.
+    //  If the call for the disk geometry failed then assume there is one
+    //  block per sector.
+    //
+
+    BlockFactor = 1;
+
+    if (NT_SUCCESS( Status ) &&
+        (DiskGeometry.BytesPerSector != 0) &&
+        (DiskGeometry.BytesPerSector < SECTOR_SIZE)) {
+
+        BlockFactor = SECTOR_SIZE / DiskGeometry.BytesPerSector;
+    }
+
+    //
+    //  Acquire the global resource to do mount operations.
+    //
+
+    CdAcquireCdData( IrpContext );
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Allocate a buffer to query the TOC.
+        //
+
+        CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
+                                             sizeof( CDROM_TOC ),
+                                             TAG_CDROM_TOC );
+
+        RtlZeroMemory( CdromToc, sizeof( CDROM_TOC ));
+
+        //
+        //  Do a quick check to see if there any Vcb's which can be removed.
+        //
+
+        CdScanForDismountedVcb( IrpContext );
+
+        //
+        //  Get our device object and alignment requirement.
+        //
+
+        Status = IoCreateDevice( CdData.DriverObject,
+                                 sizeof( VOLUME_DEVICE_OBJECT ) - sizeof( DEVICE_OBJECT ),
+                                 NULL,
+                                 FILE_DEVICE_CD_ROM_FILE_SYSTEM,
+                                 0,
+                                 FALSE,
+                                 (PDEVICE_OBJECT *) &VolDo );
+
+        if (!NT_SUCCESS( Status )) { try_leave( Status ); }
+
+        //
+        //  Our alignment requirement is the larger of the processor alignment requirement
+        //  already in the volume device object and that in the DeviceObjectWeTalkTo
+        //
+
+        if (DeviceObjectWeTalkTo->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) {
+
+            VolDo->DeviceObject.AlignmentRequirement = DeviceObjectWeTalkTo->AlignmentRequirement;
+        }
+
+        //
+        //  We must initialize the stack size in our device object before
+        //  the following reads, because the I/O system has not done it yet.
+        //
+
+        ((PDEVICE_OBJECT) VolDo)->StackSize = (CCHAR) (DeviceObjectWeTalkTo->StackSize + 1);
+
+        ClearFlag( VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING );
+
+        //
+        //  Initialize the overflow queue for the volume
+        //
+
+        VolDo->OverflowQueueCount = 0;
+        InitializeListHead( &VolDo->OverflowQueue );
+
+        VolDo->PostedRequestCount = 0;
+        KeInitializeSpinLock( &VolDo->OverflowQueueSpinLock );
+
+        //
+        //  Let's query for the Toc now and handle any error we get from this operation.
+        //
+
+        Status = CdProcessToc( IrpContext,
+                               DeviceObjectWeTalkTo,
+                               CdromToc,
+                               &TocLength,
+                               &TocTrackCount,
+                               &TocDiskFlags );
+
+        //
+        //  If we failed to read the TOC, then bail out.  Probably blank media.
+        //
+
+        if (Status != STATUS_SUCCESS)  { 
+
+            try_leave( Status ); 
+        }
+
+        //
+        //  Now before we can initialize the Vcb we need to set up the
+        //  device object field in the VPB to point to our new volume device
+        //  object.
+        //
+
+        Vpb->DeviceObject = (PDEVICE_OBJECT) VolDo;
+
+        //
+        //  Initialize the Vcb.  This routine will raise on an allocation
+        //  failure.
+        //
+
+        CdInitializeVcb( IrpContext,
+                         &VolDo->Vcb,
+                         DeviceObjectWeTalkTo,
+                         Vpb,
+                         CdromToc,
+                         TocLength,
+                         TocTrackCount,
+                         TocDiskFlags,
+                         BlockFactor,
+                         MediaChangeCount );
+
+        //
+        //  Show that we initialized the Vcb and can cleanup with the Vcb.
+        //
+
+        Vcb = &VolDo->Vcb;
+        VolDo = NULL;
+        Vpb = NULL;
+        CdromToc = NULL;
+
+        //
+        //  Store the Vcb in the IrpContext as we didn't have one before.
+        //
+
+        IrpContext->Vcb = Vcb;
+
+        CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
+
+        //
+        //  Let's reference the Vpb to make sure we are the one to
+        //  have the last dereference.
+        //
+
+        Vcb->Vpb->ReferenceCount += 1;
+
+        //
+        //  Clear the verify bit for the start of mount.
+        //
+
+        CdMarkRealDevVerifyOk( Vcb->Vpb->RealDevice);
+
+        if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK))  {
+            
+            //
+            //  Allocate a buffer to read in the volume descriptors.  We allocate a full
+            //  page to make sure we don't hit any alignment problems.
+            //
+
+            RawIsoVd = FsRtlAllocatePoolWithTag( CdNonPagedPool,
+                                                 ROUND_TO_PAGES( SECTOR_SIZE ),
+                                                 TAG_VOL_DESC );
+
+            //
+            //  Try to find the primary volume descriptor.
+            //
+
+            FoundPvd = CdFindPrimaryVd(   IrpContext,
+                                          Vcb,
+                                          RawIsoVd,
+                                          BlockFactor,
+                                          TRUE,
+                                          FALSE );
+
+            if (!FoundPvd)  {
+
+                //
+                //  We failed to find a valid VD in the data track,  but there were also
+                //  audio tracks on this disc,  so we'll try to mount it as an audio CD.
+                //  Since we're always last in the mount order,  we won't be preventing
+                //  any other FS from trying to mount the data track.  However if the 
+                //  data track was at the start of the disc,  then we abort,  to avoid
+                //  having to filter it from our synthesised directory listing later.  We
+                //  already filtered off any data track at the end.
+                //
+
+                if (!(TocDiskFlags & CDROM_DISK_AUDIO_TRACK) ||
+                     BooleanFlagOn( Vcb->CdromToc->TrackData[0].Control, TOC_DATA_TRACK))  {
+                
+                    try_leave( Status = STATUS_UNRECOGNIZED_VOLUME);
+                }
+
+                SetFlag( Vcb->VcbState, VCB_STATE_AUDIO_DISK | VCB_STATE_CDXA );
+
+                CdFreePool( &RawIsoVd );
+                RawIsoVd = NULL;
+            }
+        }
+        
+        //
+        //  Look and see if there is a secondary volume descriptor we want to
+        //  use.
+        //
+
+        if (FoundPvd) {
+
+            //
+            //  Store the primary volume descriptor in the second half of
+            //  RawIsoVd.  Then if our search for a secondary fails we can
+            //  recover this immediately.
+            //
+
+            RtlCopyMemory( Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ),
+                           RawIsoVd,
+                           SECTOR_SIZE );
+
+            //
+            //  We have the initial volume descriptor.  Locate a secondary
+            //  volume descriptor if present.
+            //
+
+            CdFindActiveVolDescriptor( IrpContext,
+                                       Vcb,
+                                       RawIsoVd,
+                                       FALSE);
+        }
+
+        //
+        //  Check if this is a remount operation.  If so then clean up
+        //  the data structures passed in and created here.
+        //
+
+        if (CdIsRemount( IrpContext, Vcb, &OldVcb )) {
+
+            //KIRQL SavedIrql; /* ReactOS Change: GCC Unused variable */
+
+            ASSERT( NULL != OldVcb->SwapVpb );
+
+            //
+            //  Link the old Vcb to point to the new device object that we
+            //  should be talking to, dereferencing the previous.  Call a 
+            //  nonpaged routine to do this since we take the Vpb spinlock.
+            //
+
+            CdReMountOldVcb( IrpContext, 
+                             OldVcb, 
+                             Vcb, 
+                             DeviceObjectWeTalkTo);
+
+            //
+            //  See if we will need to provide notification of the remount.  This is the readonly
+            //  filesystem's form of dismount/mount notification - we promise that whenever a
+            //  volume is "dismounted", that a mount notification will occur when it is revalidated.
+            //  Note that we do not send mount on normal remounts - that would duplicate the media
+            //  arrival notification of the device driver.
+            //
+    
+            if (FlagOn( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) {
+    
+                ClearFlag( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT );
+                
+                FileObjectToNotify = OldVcb->RootIndexFcb->FileObject;
+                ObReferenceObject( FileObjectToNotify );
+            }
+            
+            try_leave( Status = STATUS_SUCCESS );
+        }
+
+        //
+        //  This is a new mount.  Go ahead and initialize the
+        //  Vcb from the volume descriptor.
+        //
+
+        CdUpdateVcbFromVolDescriptor( IrpContext,
+                                      Vcb,
+                                      RawIsoVd );
+
+        //
+        //  Drop an extra reference on the root dir file so we'll be able to send
+        //  notification.
+        //
+
+        if (Vcb->RootIndexFcb) {
+
+            FileObjectToNotify = Vcb->RootIndexFcb->FileObject;
+            ObReferenceObject( FileObjectToNotify );
+        }
+
+        //
+        //  Now check the maximum transfer limits on the device in case we
+        //  get raw reads on this volume.
+        //
+
+        Status = CdPerformDevIoCtrl( IrpContext,
+                                     IOCTL_SCSI_GET_CAPABILITIES,
+                                     DeviceObjectWeTalkTo,
+                                     &Capabilities,
+                                     sizeof( IO_SCSI_CAPABILITIES ),
+                                     FALSE,
+                                     TRUE,
+                                     NULL );
+
+        if (NT_SUCCESS(Status)) {
+
+            Vcb->MaximumTransferRawSectors = Capabilities.MaximumTransferLength / RAW_SECTOR_SIZE;
+            Vcb->MaximumPhysicalPages = Capabilities.MaximumPhysicalPages;
+
+        } else {
+
+            //
+            //  This should never happen, but we can safely assume 64k and 16 pages.
+            //
+
+            Vcb->MaximumTransferRawSectors = (64 * 1024) / RAW_SECTOR_SIZE;
+            Vcb->MaximumPhysicalPages = 16;
+        }
+
+        //
+        //  The new mount is complete.  Remove the additional references on this
+        //  Vcb and the device we are mounted on top of.
+        //
+
+        Vcb->VcbReference -= CDFS_RESIDUAL_REFERENCE;
+        ASSERT( Vcb->VcbReference == CDFS_RESIDUAL_REFERENCE );
+
+        ObDereferenceObject( Vcb->TargetDeviceObject );
+
+        CdUpdateVcbCondition( Vcb, VcbMounted);
+
+        CdReleaseVcb( IrpContext, Vcb );
+        Vcb = NULL;
+
+        Status = STATUS_SUCCESS;
+
+    } finally {
+
+        //
+        //  Free the TOC buffer if not in the Vcb.
+        //
+
+        if (CdromToc != NULL) {
+
+            CdFreePool( &CdromToc );
+        }
+
+        //
+        //  Free the sector buffer if allocated.
+        //
+
+        if (RawIsoVd != NULL) {
+
+            CdFreePool( &RawIsoVd );
+        }
+
+        //
+        //  If we are not mounting the device,  then set the verify bit again.
+        //
+        
+        if ((AbnormalTermination() || (Status != STATUS_SUCCESS)) && 
+            SetDoVerifyOnFail)  {
+
+            CdMarkRealDevForVerify( IrpContext->RealDevice);
+        }
+
+        //
+        //  If we didn't complete the mount then cleanup any remaining structures.
+        //
+
+        if (Vpb != NULL) { Vpb->DeviceObject = NULL; }
+
+        if (Vcb != NULL) {
+
+            //
+            //  Make sure there is no Vcb in the IrpContext since it could go away
+            //
+
+            IrpContext->Vcb = NULL;
+
+            Vcb->VcbReference -= CDFS_RESIDUAL_REFERENCE;
+
+            if (CdDismountVcb( IrpContext, Vcb )) {
+
+                CdReleaseVcb( IrpContext, Vcb );
+            }
+
+        } else if (VolDo != NULL) {
+
+            IoDeleteDevice( (PDEVICE_OBJECT) VolDo );
+        }
+
+        //
+        //  Release the global resource.
+        //
+
+        CdReleaseCdData( IrpContext );
+    }
+
+    //
+    //  Now send mount notification.
+    //
+    
+    if (FileObjectToNotify) {
+
+        FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT );
+        ObDereferenceObject( FileObjectToNotify );
+    }
+
+    //
+    //  Complete the request if no exception.
+    //
+
+    CdCompleteRequest( IrpContext, Irp, Status );
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdVerifyVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the verify volume operation.  It is responsible for
+    either completing of enqueuing the input Irp.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+    PVPB Vpb = IrpSp->Parameters.VerifyVolume.Vpb;
+    PVCB Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->Parameters.VerifyVolume.DeviceObject)->Vcb;
+
+    PCHAR RawIsoVd = NULL;
+
+    PCDROM_TOC CdromToc = NULL;
+    ULONG TocLength = 0;
+    ULONG TocTrackCount = 0;
+    ULONG TocDiskFlags = 0;
+
+    ULONG MediaChangeCount = Vcb->MediaChangeCount;
+
+    PFILE_OBJECT FileObjectToNotify = NULL;
+
+    BOOLEAN ReturnError;
+    BOOLEAN ReleaseVcb = FALSE;
+
+    IO_STATUS_BLOCK Iosb;
+
+    STRING AnsiLabel;
+    UNICODE_STRING UnicodeLabel;
+
+    WCHAR VolumeLabel[ VOLUME_ID_LENGTH ];
+    ULONG VolumeLabelLength;
+
+    ULONG Index;
+
+    NTSTATUS Status;
+
+    PAGED_CODE();
+
+    //
+    //  We check that we are talking to a Cdrom device.
+    //
+
+    ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM );
+    ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ));
+
+    //
+    //  Update the real device in the IrpContext from the Vpb.  There was no available
+    //  file object when the IrpContext was created.
+    //
+
+    IrpContext->RealDevice = Vpb->RealDevice;
+
+    //
+    //  Acquire the global resource to synchronise against mounts and teardown,
+    //  finally clause releases.
+    //
+
+    CdAcquireCdData( IrpContext );
+
+    try {
+
+        CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
+        ReleaseVcb = TRUE;
+
+        //
+        //  Verify that there is a disk here.
+        //
+
+        Status = CdPerformDevIoCtrl( IrpContext,
+                                     IOCTL_CDROM_CHECK_VERIFY,
+                                     Vcb->TargetDeviceObject,
+                                     &MediaChangeCount,
+                                     sizeof(ULONG),
+                                     FALSE,
+                                     TRUE,
+                                     &Iosb );
+
+        if (!NT_SUCCESS( Status )) {
+
+            //
+            //  If we will allow a raw mount then return WRONG_VOLUME to
+            //  allow the volume to be mounted by raw.
+            //
+
+            if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) {
+
+                Status = STATUS_WRONG_VOLUME;
+            }
+
+            try_return( Status );
+        }
+        
+        if (Iosb.Information != sizeof(ULONG)) {
+
+            //
+            //  Be safe about the count in case the driver didn't fill it in
+            //
+
+            MediaChangeCount = 0;
+        }
+
+        //
+        //  Verify that the device actually saw a change. If the driver does not
+        //  support the MCC, then we must verify the volume in any case.
+        //
+
+        if (MediaChangeCount == 0 ||
+            (Vcb->MediaChangeCount != MediaChangeCount)) {
+
+            //
+            //  Allocate a buffer to query the TOC.
+            //
+
+            CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
+                                                 sizeof( CDROM_TOC ),
+                                                 TAG_CDROM_TOC );
+
+            RtlZeroMemory( CdromToc, sizeof( CDROM_TOC ));
+
+            //
+            //  Let's query for the Toc now and handle any error we get from this operation.
+            //
+
+            Status = CdProcessToc( IrpContext,
+                                   Vcb->TargetDeviceObject,
+                                   CdromToc,
+                                   &TocLength,
+                                   &TocTrackCount,
+                                   &TocDiskFlags );
+
+            //
+            //  If we failed to read the TOC,  then give up now.  Drives will fail
+            //  a TOC read on,  for example,  erased CD-RW media.
+            //
+
+            if (Status != STATUS_SUCCESS) {
+
+                //
+                //  For any errors other than no media and not ready,  commute the
+                //  status to ensure that the current VPB is kicked off the device
+                //  below - there is probably blank media in the drive,  since we got
+                //  further than the check verify.
+                //
+
+                if (!CdIsRawDevice( IrpContext, Status )) {
+
+                    Status = STATUS_WRONG_VOLUME;
+                }
+
+                try_return( Status );
+
+            //
+            //  We got a TOC.  Verify that it matches the previous Toc.
+            //
+
+            } else if ((Vcb->TocLength != TocLength) ||
+                       (Vcb->TrackCount != TocTrackCount) ||
+                       (Vcb->DiskFlags != TocDiskFlags) ||
+                       !RtlEqualMemory( CdromToc,
+                                        Vcb->CdromToc,
+                                        TocLength )) {
+
+                try_return( Status = STATUS_WRONG_VOLUME );
+            }
+
+            //
+            //  If the disk to verify is an audio disk then we already have a
+            //  match.  Otherwise we need to check the volume descriptor.
+            //
+
+            if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
+
+                //
+                //  Allocate a buffer for the sector buffer.
+                //
+
+                RawIsoVd = FsRtlAllocatePoolWithTag( CdNonPagedPool,
+                                                     ROUND_TO_PAGES( 2 * SECTOR_SIZE ),
+                                                     TAG_VOL_DESC );
+
+                //
+                //  Read the primary volume descriptor for this volume.  If we
+                //  get an io error and this verify was a the result of DASD open,
+                //  commute the Io error to STATUS_WRONG_VOLUME.  Note that if we currently
+                //  expect a music disk then this request should fail.
+                //
+
+                ReturnError = FALSE;
+
+                if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) {
+
+                    ReturnError = TRUE;
+                }
+
+                if (!CdFindPrimaryVd( IrpContext,
+                                      Vcb,
+                                      RawIsoVd,
+                                      Vcb->BlockFactor,
+                                      ReturnError,
+                                      TRUE )) {
+
+                    //
+                    //  If the previous Vcb did not represent a raw disk
+                    //  then show this volume was dismounted.
+                    //
+
+                    try_return( Status = STATUS_WRONG_VOLUME );
+
+                } 
+                else {
+
+                    //
+                    //  Look for a supplementary VD.
+                    //
+                    //  Store the primary volume descriptor in the second half of
+                    //  RawIsoVd.  Then if our search for a secondary fails we can
+                    //  recover this immediately.
+                    //
+
+                    RtlCopyMemory( Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ),
+                                   RawIsoVd,
+                                   SECTOR_SIZE );
+
+                    //
+                    //  We have the initial volume descriptor.  Locate a secondary
+                    //  volume descriptor if present.
+                    //
+
+                    CdFindActiveVolDescriptor( IrpContext,
+                                               Vcb,
+                                               RawIsoVd,
+                                               TRUE);
+                    //
+                    //  Compare the serial numbers.  If they don't match, set the
+                    //  status to wrong volume.
+                    //
+
+                    if (Vpb->SerialNumber != CdSerial32( RawIsoVd, SECTOR_SIZE )) {
+
+                        try_return( Status = STATUS_WRONG_VOLUME );
+                    }
+
+                    //
+                    //  Verify the volume labels.
+                    //
+
+                    if (!FlagOn( Vcb->VcbState, VCB_STATE_JOLIET )) {
+
+                        //
+                        //  Compute the length of the volume name
+                        //
+
+                        AnsiLabel.Buffer = (PCHAR)CdRvdVolId( RawIsoVd, Vcb->VcbState ); /* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+                        AnsiLabel.MaximumLength = AnsiLabel.Length = VOLUME_ID_LENGTH;
+
+                        UnicodeLabel.MaximumLength = VOLUME_ID_LENGTH * sizeof( WCHAR );
+                        UnicodeLabel.Buffer = VolumeLabel;
+
+                        //
+                        //  Convert this to unicode.  If we get any error then use a name
+                        //  length of zero.
+                        //
+
+                        VolumeLabelLength = 0;
+
+                        if (NT_SUCCESS( RtlOemStringToCountedUnicodeString( &UnicodeLabel,
+                                                                            &AnsiLabel,
+                                                                            FALSE ))) {
+
+                            VolumeLabelLength = UnicodeLabel.Length;
+                        }
+
+                    //
+                    //  We need to convert from big-endian to little endian.
+                    //
+
+                    } else {
+
+                        CdConvertBigToLittleEndian( IrpContext,
+                                                    (PCHAR)CdRvdVolId( RawIsoVd, Vcb->VcbState ),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+                                                    VOLUME_ID_LENGTH,
+                                                    (PCHAR) VolumeLabel );
+
+                        VolumeLabelLength = VOLUME_ID_LENGTH;
+                    }
+
+                    //
+                    //  Strip the trailing spaces or zeroes from the name.
+                    //
+
+                    Index = VolumeLabelLength / sizeof( WCHAR );
+
+                    while (Index > 0) {
+
+                        if ((VolumeLabel[ Index - 1 ] != L'\0') &&
+                            (VolumeLabel[ Index - 1 ] != L' ')) {
+
+                            break;
+                        }
+
+                        Index -= 1;
+                    }
+
+                    //
+                    //  Now set the final length for the name.
+                    //
+
+                    VolumeLabelLength = (USHORT) (Index * sizeof( WCHAR ));
+
+                    //
+                    //  Now check that the label matches.
+                    //
+                    if ((Vpb->VolumeLabelLength != VolumeLabelLength) ||
+                        !RtlEqualMemory( Vpb->VolumeLabel,
+                                         VolumeLabel,
+                                         VolumeLabelLength )) {
+
+                        try_return( Status = STATUS_WRONG_VOLUME );
+                    }
+                }
+            }
+        }
+
+        //
+        //  The volume is OK, clear the verify bit.
+        //
+
+        CdUpdateVcbCondition( Vcb, VcbMounted);
+
+        CdMarkRealDevVerifyOk( Vpb->RealDevice);
+
+        //
+        //  See if we will need to provide notification of the remount.  This is the readonly
+        //  filesystem's form of dismount/mount notification.
+        //
+
+        if (FlagOn( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) {
+
+            ClearFlag( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT );
+            
+            FileObjectToNotify = Vcb->RootIndexFcb->FileObject;
+            ObReferenceObject( FileObjectToNotify );
+        }
+        
+    try_exit: NOTHING;
+
+        //
+        //  Update the media change count to note that we have verified the volume
+        //  at this value - regardless of the outcome.
+        //
+
+        CdUpdateMediaChangeCount( Vcb, MediaChangeCount);
+
+        //
+        //  If we got the wrong volume then free any remaining XA sector in
+        //  the current Vcb.  Also mark the Vcb as not mounted.
+        //
+
+        if (Status == STATUS_WRONG_VOLUME) {
+
+            CdUpdateVcbCondition( Vcb, VcbNotMounted);
+
+            if (Vcb->XASector != NULL) {
+
+                CdFreePool( &Vcb->XASector );
+                Vcb->XASector = 0;
+                Vcb->XADiskOffset = 0;
+            }
+
+            //
+            //  Now, if there are no user handles to the volume, try to spark
+            //  teardown by purging the volume.
+            //
+
+            if (Vcb->VcbCleanup == 0) {
+
+                if (NT_SUCCESS( CdPurgeVolume( IrpContext, Vcb, FALSE ))) {
+                    
+                    ReleaseVcb = CdCheckForDismount( IrpContext, Vcb, FALSE );
+                }
+            }
+        }
+
+    } finally {
+
+        //
+        //  Free the TOC buffer if allocated.
+        //
+
+        if (CdromToc != NULL) {
+
+            CdFreePool( &CdromToc );
+        }
+
+        if (RawIsoVd != NULL) {
+
+            CdFreePool( &RawIsoVd );
+        }
+
+        if (ReleaseVcb) {
+            
+            CdReleaseVcb( IrpContext, Vcb );
+        }
+
+        CdReleaseCdData( IrpContext );
+    }
+
+    //
+    //  Now send mount notification.
+    //
+    
+    if (FileObjectToNotify) {
+
+        FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT );
+        ObDereferenceObject( FileObjectToNotify );
+    }
+    
+    //
+    //  Complete the request if no exception.
+    //
+
+    CdCompleteRequest( IrpContext, Irp, Status );
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdOplockRequest (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This is the common routine to handle oplock requests made via the
+    NtFsControlFile call.
+
+Arguments:
+
+    Irp - Supplies the Irp being processed
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    NTSTATUS Status;
+    PFCB Fcb;
+    PCCB Ccb;
+
+    ULONG OplockCount = 0;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PAGED_CODE();
+
+    //
+    //  We only permit oplock requests on files.
+    //
+
+    if (CdDecodeFileObject( IrpContext,
+                            IrpSp->FileObject,
+                            &Fcb,
+                            &Ccb ) != UserFileOpen ) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    //
+    //  Make this a waitable Irpcontext so we don't fail to acquire
+    //  the resources.
+    //
+
+    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
+    ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
+
+    //
+    //  Switch on the function control code.  We grab the Fcb exclusively
+    //  for oplock requests, shared for oplock break acknowledgement.
+    //
+
+    switch (IrpSp->Parameters.FileSystemControl.FsControlCode) {
+
+    case FSCTL_REQUEST_OPLOCK_LEVEL_1 :
+    case FSCTL_REQUEST_OPLOCK_LEVEL_2 :
+    case FSCTL_REQUEST_BATCH_OPLOCK :
+    case FSCTL_REQUEST_FILTER_OPLOCK :
+
+        CdAcquireFcbExclusive( IrpContext, Fcb, FALSE );
+
+        if (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
+
+            if (Fcb->FileLock != NULL) {
+
+                OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( Fcb->FileLock );
+            }
+
+        } else {
+
+            OplockCount = Fcb->FcbCleanup;
+        }
+
+        break;
+
+    case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
+    case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
+    case FSCTL_OPLOCK_BREAK_NOTIFY:
+    case FSCTL_OPLOCK_BREAK_ACK_NO_2:
+
+        CdAcquireFcbShared( IrpContext, Fcb, FALSE );
+        break;
+
+    default:
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    //
+    //  Use a try finally to free the Fcb.
+    //
+
+    try {
+
+        //
+        //  Verify the Fcb.
+        //
+
+        CdVerifyFcbOperation( IrpContext, Fcb );
+
+        //
+        //  Call the FsRtl routine to grant/acknowledge oplock.
+        //
+
+        Status = FsRtlOplockFsctrl( &Fcb->Oplock,
+                                    Irp,
+                                    OplockCount );
+
+        //
+        //  Set the flag indicating if Fast I/O is possible
+        //
+
+        CdLockFcb( IrpContext, Fcb );
+        Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
+        CdUnlockFcb( IrpContext, Fcb );
+
+        //
+        //  The oplock package will complete the Irp.
+        //
+
+        Irp = NULL;
+
+    } finally {
+
+        //
+        //  Release all of our resources
+        //
+
+        CdReleaseFcb( IrpContext, Fcb );
+    }
+
+    //
+    //  Complete the request if there was no exception.
+    //
+
+    CdCompleteRequest( IrpContext, Irp, Status );
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdLockVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the lock volume operation.  It is responsible for
+    either completing of enqueuing the input Irp.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    NTSTATUS Status;
+
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PVCB Vcb;
+    PFCB Fcb;
+    PCCB Ccb;
+
+    PAGED_CODE();
+
+    //
+    //  Decode the file object, the only type of opens we accept are
+    //  user volume opens.
+    //
+
+    if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    //
+    //  Send our notification so that folks that like to hold handles on
+    //  volumes can get out of the way.
+    //
+
+    FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK );
+
+    //
+    //  Acquire exclusive access to the Vcb.
+    //
+
+    Vcb = Fcb->Vcb;
+    CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
+
+    try {
+
+        //
+        //  Verify the Vcb.
+        //
+
+        CdVerifyVcb( IrpContext, Vcb );
+
+        Status = CdLockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
+
+    } finally {
+
+        //
+        //  Release the Vcb.
+        //
+
+        CdReleaseVcb( IrpContext, Vcb );
+        
+        if (AbnormalTermination() || !NT_SUCCESS( Status )) {
+
+            FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED );
+        }
+    }
+
+    //
+    //  Complete the request if there haven't been any exceptions.
+    //
+
+    CdCompleteRequest( IrpContext, Irp, Status );
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdUnlockVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the unlock volume operation.  It is responsible for
+    either completing of enqueuing the input Irp.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    NTSTATUS Status;
+
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PVCB Vcb;
+    PFCB Fcb;
+    PCCB Ccb;
+
+    PAGED_CODE();
+
+    //
+    //  Decode the file object, the only type of opens we accept are
+    //  user volume opens.
+    //
+
+    if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    //
+    //  Acquire exclusive access to the Vcb.
+    //
+
+    Vcb = Fcb->Vcb;
+
+    CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
+
+    //
+    //  We won't check for a valid Vcb for this request.  An unlock will always
+    //  succeed on a locked volume.
+    //
+
+    Status = CdUnlockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
+
+    //
+    //  Release all of our resources
+    //
+
+    CdReleaseVcb( IrpContext, Vcb );
+
+    //
+    //  Send notification that the volume is avaliable.
+    //
+
+    if (NT_SUCCESS( Status )) {
+
+        FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_UNLOCK );
+    }
+
+    //
+    //  Complete the request if there haven't been any exceptions.
+    //
+
+    CdCompleteRequest( IrpContext, Irp, Status );
+    return Status;
+}
+
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdDismountVolume (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs the dismount volume operation.  It is responsible for
+    either completing of enqueuing the input Irp.  We only dismount a volume which
+    has been locked.  The intent here is that someone has locked the volume (they are the
+    only remaining handle).  We set the verify bit here and the user will close his handle.
+    We will dismount a volume with no user's handles in the verify path.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PVCB Vcb;
+    PFCB Fcb;
+    PCCB Ccb;
+
+    PAGED_CODE();
+
+    if (CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Vcb = Fcb->Vcb;
+
+    //
+    //  Make this request waitable.
+    //
+
+    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+    
+    //
+    //  Acquire exclusive access to the Vcb,  and take the global resource to
+    //  sync. against mounts,  verifies etc.
+    //
+
+    CdAcquireCdData( IrpContext );
+    CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
+
+    //
+    //  Mark the volume as needs to be verified, but only do it if
+    //  the vcb is locked by this handle and the volume is currently mounted.
+    //
+
+    if (Vcb->VcbCondition != VcbMounted) {
+
+        Status = STATUS_VOLUME_DISMOUNTED;
+
+    } else {
+
+        //
+        //  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 );
+
+        //
+        //  Set flag to tell the close path that we want to force dismount
+        //  the volume when this handle is closed.
+        //
+        
+        SetFlag( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE);
+        
+        Status = STATUS_SUCCESS;
+    }
+
+    //
+    //  Release all of our resources
+    //
+
+    CdReleaseVcb( IrpContext, Vcb );
+    CdReleaseCdData( IrpContext);
+
+    //
+    //  Complete the request if there haven't been any exceptions.
+    //
+
+    CdCompleteRequest( IrpContext, Irp, Status );
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+NTSTATUS /* ReactOS Change: Function did not have a type??? */
+CdIsVolumeDirty (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine determines if a volume is currently dirty.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    PIO_STACK_LOCATION IrpSp;
+
+    TYPE_OF_OPEN TypeOfOpen;
+    PFCB Fcb;
+    PCCB Ccb;
+
+    PULONG VolumeState;
+    
+    //
+    //  Get the current stack location and extract the output
+    //  buffer information.
+    //
+
+    IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    //
+    //  Get a pointer to the output buffer.
+    //
+
+    if (Irp->AssociatedIrp.SystemBuffer != NULL) {
+
+        VolumeState = Irp->AssociatedIrp.SystemBuffer;
+
+    } else {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER );
+        return STATUS_INVALID_USER_BUFFER;
+    }
+
+    //
+    //  Make sure the output buffer is large enough and then initialize
+    //  the answer to be that the volume isn't dirty.
+    //
+
+    if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    *VolumeState = 0;
+
+    //
+    //  Decode the file object
+    //
+
+    TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
+
+    if (TypeOfOpen != UserVolumeOpen) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (Fcb->Vcb->VcbCondition != VcbMounted) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED );
+        return STATUS_VOLUME_DISMOUNTED;
+    }
+
+    //
+    //  Now set up to return the clean state.  CDs obviously can never be dirty
+    //  but we want to make sure we have enforced the full semantics of this call.
+    //
+    
+    Irp->IoStatus.Information = sizeof( ULONG );
+
+    CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
+    return STATUS_SUCCESS;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdIsVolumeMounted (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine determines if a volume is currently mounted.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PFCB Fcb;
+    PCCB Ccb;
+
+    PAGED_CODE();
+
+    //
+    //  Decode the file object.
+    //
+
+    CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
+
+    if (Fcb != NULL) {
+
+        //
+        //  Disable PopUps, we want to return any error.
+        //
+
+        SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS );
+
+        //
+        //  Verify the Vcb.  This will raise in the error condition.
+        //
+
+        CdVerifyVcb( IrpContext, Fcb->Vcb );
+    }
+
+    CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
+
+    return STATUS_SUCCESS;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdIsPathnameValid (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine determines if pathname is a valid CDFS pathname.
+    We always succeed this request.
+
+Arguments:
+
+    Irp - Supplies the Irp to process.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
+    return STATUS_SUCCESS;
+}
+
+\f
+//
+//  Local support routine
+//
+
+NTSTATUS
+CdInvalidateVolumes (
+    IN PIRP_CONTEXT IrpContext,
+    IN PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine searches for all the volumes mounted on the same real device
+    of the current DASD handle, and marks them all bad.  The only operation
+    that can be done on such handles is cleanup and close.
+
+Arguments:
+
+    Irp - Supplies the Irp to process
+
+Return Value:
+
+    NTSTATUS - The return status for the operation
+
+--*/
+
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+    KIRQL SavedIrql;
+    
+    BOOLEAN UnlockVcb = FALSE;
+    
+    LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0};
+
+    HANDLE Handle;
+
+    PVCB Vcb;
+
+    PLIST_ENTRY Links;
+
+    PFILE_OBJECT FileToMarkBad;
+    PDEVICE_OBJECT DeviceToMarkBad;
+
+    //
+    //  We only allow the invalidate call to come in on our file system devices.
+    //
+    
+    if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject)  {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
+
+        return STATUS_INVALID_DEVICE_REQUEST;
+    }
+
+    //
+    //  Check for the correct security access.
+    //  The caller must have the SeTcbPrivilege.
+    //
+
+    if (!SeSinglePrivilegeCheck( TcbPrivilege, Irp->RequestorMode )) {
+
+        CdCompleteRequest( IrpContext, Irp, STATUS_PRIVILEGE_NOT_HELD );
+
+        return STATUS_PRIVILEGE_NOT_HELD;
+    }
+
+    //
+    //  Try to get a pointer to the device object from the handle passed in.
+    //
+
+#if defined(_WIN64)
+    if (IoIs32bitProcess( Irp )) {
+        
+        if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( UINT32 )) {
+
+            CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+            return STATUS_INVALID_PARAMETER;
+        }
+
+        Handle = (HANDLE) LongToHandle( *((PUINT32) Irp->AssociatedIrp.SystemBuffer) );
+    
+    } else {
+#endif
+        if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( HANDLE )) {
+
+            CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
+            return STATUS_INVALID_PARAMETER;
+        }
+        Handle = *((PHANDLE) Irp->AssociatedIrp.SystemBuffer);
+#if defined(_WIN64)
+    }
+#endif
+
+    Status = ObReferenceObjectByHandle( Handle,
+                                        0,
+                                        IoFileObjectType, /* ReactOS Change: GCC/LD Incompatibily with exported kernel data */
+                                        KernelMode,
+                                        (PVOID*)&FileToMarkBad, /* ReactOS Change: GCC "passing argument 5 of 'ObReferenceObjectByHandle' from incompatible pointer type" */
+                                        NULL );
+
+    if (!NT_SUCCESS(Status)) {
+
+        CdCompleteRequest( IrpContext, Irp, Status );
+        return Status;
+    }
+
+    //
+    //  Grab the DeviceObject from the FileObject.
+    //
+
+    DeviceToMarkBad = FileToMarkBad->DeviceObject;
+
+    //
+    //  We only needed the device object involved, not a reference to the file.
+    //
+
+    ObDereferenceObject( FileToMarkBad );
+
+    //
+    //  Make sure this request can wait.
+    //
+
+    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
+    ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
+
+    //
+    //  Synchronise with pnp/mount/verify paths.
+    //
+    
+    CdAcquireCdData( IrpContext );
+
+    //
+    //  Nothing can go wrong now.
+    //
+
+    //
+    //  Now walk through all the mounted Vcb's looking for candidates to
+    //  mark invalid.
+    //
+    //  On volumes we mark invalid, check for dismount possibility (which is
+    //  why we have to get the next link so early).
+    //
+
+    Links = CdData.VcbQueue.Flink;
+
+    while (Links != &CdData.VcbQueue) {
+
+        Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks);
+
+        Links = Links->Flink;
+
+        //
+        //  If we get a match, mark the volume Bad, and also check to
+        //  see if the volume should go away.
+        //
+
+        CdLockVcb( IrpContext, Vcb );
+
+        if (Vcb->Vpb->RealDevice == DeviceToMarkBad) {
+
+            //
+            //  Take the VPB spinlock,  and look to see if this volume is the 
+            //  one currently mounted on the actual device.  If it is,  pull it 
+            //  off immediately.
+            //
+            
+            IoAcquireVpbSpinLock( &SavedIrql );
+
+            if (DeviceToMarkBad->Vpb == Vcb->Vpb)  {
+            
+                PVPB NewVpb = Vcb->SwapVpb;
+
+                ASSERT( FlagOn( Vcb->Vpb->Flags, VPB_MOUNTED));
+                ASSERT( NULL != NewVpb);
+
+                RtlZeroMemory( NewVpb, sizeof( VPB ) );
+
+                NewVpb->Type = IO_TYPE_VPB;
+                NewVpb->Size = sizeof( VPB );
+                NewVpb->RealDevice = DeviceToMarkBad;
+                NewVpb->Flags = FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_REMOVE_PENDING );
+
+                DeviceToMarkBad->Vpb = NewVpb;
+                Vcb->SwapVpb = NULL;
+            }
+
+            IoReleaseVpbSpinLock( SavedIrql );
+
+            if (Vcb->VcbCondition != VcbDismountInProgress) {
+                
+                CdUpdateVcbCondition( Vcb, VcbInvalid);
+            }
+
+            CdUnlockVcb( IrpContext, Vcb );
+
+            CdAcquireVcbExclusive( IrpContext, Vcb, FALSE);
+            
+            CdPurgeVolume( IrpContext, Vcb, FALSE );
+
+            UnlockVcb = CdCheckForDismount( IrpContext, Vcb, FALSE );
+
+            if (UnlockVcb)  {
+
+                CdReleaseVcb( IrpContext, Vcb);
+            }
+
+        } else {
+
+            CdUnlockVcb( IrpContext, Vcb );
+        }
+    }
+
+    CdReleaseCdData( IrpContext );
+
+    CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
+    return STATUS_SUCCESS;
+}
+
+
+//
+//  Local support routine
+//
+
+VOID
+CdScanForDismountedVcb (
+    IN PIRP_CONTEXT IrpContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine walks through the list of Vcb's looking for any which may
+    now be deleted.  They may have been left on the list because there were
+    outstanding references.
+
+Arguments:
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PVCB Vcb;
+    PLIST_ENTRY Links;
+
+    PAGED_CODE();
+
+    //
+    //  Walk through all of the Vcb's attached to the global data.
+    //
+
+    Links = CdData.VcbQueue.Flink;
+
+    while (Links != &CdData.VcbQueue) {
+
+        Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks );
+
+        //
+        //  Move to the next link now since the current Vcb may be deleted.
+        //
+
+        Links = Links->Flink;
+
+        //
+        //  If dismount is already underway then check if this Vcb can
+        //  go away.
+        //
+
+        if ((Vcb->VcbCondition == VcbDismountInProgress) ||
+            (Vcb->VcbCondition == VcbInvalid) ||
+            ((Vcb->VcbCondition == VcbNotMounted) && (Vcb->VcbReference <= CDFS_RESIDUAL_REFERENCE))) {
+
+            CdCheckForDismount( IrpContext, Vcb, FALSE );
+        }
+    }
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+BOOLEAN
+CdFindPrimaryVd (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PCHAR RawIsoVd,
+    IN ULONG BlockFactor,
+    IN BOOLEAN ReturnOnError,
+    IN BOOLEAN VerifyVolume
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to walk through the volume descriptors looking
+    for a primary volume descriptor.  When/if a primary is found a 32-bit
+    serial number is generated and stored into the Vpb.  We also store the
+    location of the primary volume descriptor in the Vcb.
+
+Arguments:
+
+    Vcb - Pointer to the VCB for the volume.
+
+    RawIsoVd - Pointer to a sector buffer which will contain the primary
+               volume descriptor on exit, if successful.
+
+    BlockFactor - Block factor used by the current device for the TableOfContents.
+
+    ReturnOnError - Indicates that we should raise on I/O errors rather than
+        returning a FALSE value.
+
+    VerifyVolume - Indicates if we were called from the verify path.  We
+        do a few things different in this path.  We don't update the Vcb in
+        the verify path.
+
+Return Value:
+
+    BOOLEAN - TRUE if a valid primary volume descriptor found, FALSE
+              otherwise.
+
+--*/
+
+{
+    NTSTATUS Status;
+    ULONG ThisPass = 1;
+    BOOLEAN FoundVd = FALSE;
+
+    ULONG BaseSector;
+    ULONG SectorOffset;
+
+    PCDROM_TOC CdromToc;
+
+    ULONG VolumeFlags;
+
+    PAGED_CODE();
+
+    //
+    //  If there are no data tracks, don't even bother hunting for descriptors.
+    //
+    //  This explicitly breaks various non-BlueBook compliant CDs that scribble
+    //  an ISO filesystem on media claiming only audio tracks.  Since these
+    //  disks can cause serious problems in some CDROM units, fail fast.  I admit
+    //  that it is possible that someone can still record the descriptors in the
+    //  audio track, record a data track (but fail to record descriptors there)
+    //  and still have the disk work.  As this form of error worked in NT 4.0, and
+    //  since these disks really do exist, I don't want to change them.
+    //
+    //  If we wished to support all such media (we don't), it would be neccesary
+    //  to clear this flag on finding ISO or HSG descriptors below.
+    //
+
+    if (FlagOn(Vcb->VcbState, VCB_STATE_AUDIO_DISK)) {
+
+        return FALSE;
+    }
+    
+    //
+    //  We will make at most two passes through the volume descriptor sequence.
+    //
+    //  On the first pass we will query for the last session.  Using this
+    //  as a starting offset we will attempt to mount the volume.  On any failure
+    //  we will go to the second pass and try without using any multi-session
+    //  information.
+    //
+    //  On the second pass we will start offset from sector zero.
+    //
+
+    while (!FoundVd && (ThisPass <= 2)) {
+
+        //
+        //  If we aren't at pass 1 then we start at sector 0.  Otherwise we
+        //  try to look up the multi-session information.
+        //
+
+        BaseSector = 0;
+
+        if (ThisPass == 1) {
+
+            CdromToc = NULL;
+
+            //
+            //  Check for whether this device supports XA and multi-session.
+            //
+
+            try {
+
+                //
+                //  Allocate a buffer for the last session information.
+                //
+
+                CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
+                                                     sizeof( CDROM_TOC ),
+                                                     TAG_CDROM_TOC );
+
+                RtlZeroMemory( CdromToc, sizeof( CDROM_TOC ));
+
+                //
+                //  Query the last session information from the driver.
+                //
+
+                Status = CdPerformDevIoCtrl( IrpContext,
+                                             IOCTL_CDROM_GET_LAST_SESSION,
+                                             Vcb->TargetDeviceObject,
+                                             CdromToc,
+                                             sizeof( CDROM_TOC ),
+                                             FALSE,
+                                             TRUE,
+                                             NULL );
+
+                //
+                //  Raise an exception if there was an allocation failure.
+                //
+
+                if (Status == STATUS_INSUFFICIENT_RESOURCES) {
+
+                    CdRaiseStatus( IrpContext, Status );
+                }
+
+                //
+                //  We don't handle any errors yet.  We will hit that below
+                //  as we try to scan the disk.  If we have last session information
+                //  then modify the base sector.
+                //
+
+                if (NT_SUCCESS( Status ) &&
+                    (CdromToc->FirstTrack != CdromToc->LastTrack)) {
+
+                    PCHAR Source, Dest;
+                    ULONG Count;
+
+                    Count = 4;
+
+                    //
+                    //  The track address is BigEndian, we need to flip the bytes.
+                    //
+
+                    Source = (PCHAR) &CdromToc->TrackData[0].Address[3];/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+                    Dest = (PCHAR) &BaseSector; /* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+
+                    do {
+
+                        *Dest++ = *Source--;
+
+                    } while (--Count);
+
+                    //
+                    //  Now adjust the base sector by the block factor of the
+                    //  device.
+                    //
+
+                    BaseSector /= BlockFactor;
+
+                //
+                //  Make this look like the second pass since we are only using the
+                //  first session.  No reason to retry on error.
+                //
+
+                } else {
+
+                    ThisPass += 1;
+                }
+
+            } finally {
+
+                if (CdromToc != NULL) { CdFreePool( &CdromToc ); }
+            }
+        }
+
+        //
+        //  Compute the starting sector offset from the start of the session.
+        //
+
+        SectorOffset = FIRST_VD_SECTOR;
+
+        //
+        //  Start by assuming we have neither Hsg or Iso volumes.
+        //
+
+        VolumeFlags = 0;
+
+        //
+        //  Loop until either error encountered, primary volume descriptor is
+        //  found or a terminal volume descriptor is found.
+        //
+
+        while (TRUE) {
+
+            //
+            //  Attempt to read the desired sector. Exit directly if operation
+            //  not completed.
+            //
+            //  If this is pass 1 we will ignore errors in read sectors and just
+            //  go to the next pass.
+            //
+
+            if (!CdReadSectors( IrpContext,
+                                LlBytesFromSectors( BaseSector + SectorOffset ),
+                                SECTOR_SIZE,
+                                (BOOLEAN) ((ThisPass == 1) || ReturnOnError),
+                                RawIsoVd,
+                                Vcb->TargetDeviceObject )) {
+
+                break;
+            }
+
+            //
+            //  Check if either an ISO or HSG volume.
+            //
+
+            if (RtlEqualMemory( CdIsoId,
+                                CdRvdId( RawIsoVd, VCB_STATE_ISO ),
+                                VOL_ID_LEN )) {
+
+                SetFlag( VolumeFlags, VCB_STATE_ISO );
+
+            } else if (RtlEqualMemory( CdHsgId,
+                                       CdRvdId( RawIsoVd, VCB_STATE_HSG ),
+                                       VOL_ID_LEN )) {
+
+                SetFlag( VolumeFlags, VCB_STATE_HSG );
+
+            //
+            //  We have neither so break out of the loop.
+            //
+
+            } else {
+
+                 break;
+            }
+
+            //
+            //  Break out if the version number is incorrect or this is
+            //  a terminator.
+            //
+
+            if ((CdRvdVersion( RawIsoVd, VolumeFlags ) != VERSION_1) ||
+                (CdRvdDescType( RawIsoVd, VolumeFlags ) == VD_TERMINATOR)) {
+
+                break;
+            }
+
+            //
+            //  If this is a primary volume descriptor then our search is over.
+            //
+
+            if (CdRvdDescType( RawIsoVd, VolumeFlags ) == VD_PRIMARY) {
+
+                //
+                //  If we are not in the verify path then initialize the
+                //  fields in the Vcb with basic information from this
+                //  descriptor.
+                //
+
+                if (!VerifyVolume) {
+
+                    //
+                    //  Set the flag for the volume type.
+                    //
+
+                    SetFlag( Vcb->VcbState, VolumeFlags );
+
+                    //
+                    //  Store the base sector and sector offset for the
+                    //  primary volume descriptor.
+                    //
+
+                    Vcb->BaseSector = BaseSector;
+                    Vcb->VdSectorOffset = SectorOffset;
+                    Vcb->PrimaryVdSectorOffset = SectorOffset;
+                }
+
+                FoundVd = TRUE;
+                break;
+            }
+
+            //
+            //  Indicate that we're at the next sector.
+            //
+
+            SectorOffset += 1;
+        }
+
+        ThisPass += 1;
+    }
+
+    return FoundVd;
+}
+
+\f
+//
+//  Local support routine
+//
+
+BOOLEAN
+CdIsRemount (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    OUT PVCB *OldVcb
+    )
+/*++
+
+Routine Description:
+
+    This routine walks through the links of the Vcb chain in the global
+    data structure.  The remount condition is met when the following
+    conditions are all met:
+
+        If the new Vcb is a device only Mvcb and there is a previous
+        device only Mvcb.
+
+        Otherwise following conditions must be matched.
+
+            1 - The 32 serial in the current VPB matches that in a previous
+                VPB.
+
+            2 - The volume label in the Vpb matches that in the previous
+                Vpb.
+
+            3 - The system pointer to the real device object in the current
+                VPB matches that in the same previous VPB.
+
+            4 - Finally the previous Vcb cannot be invalid or have a dismount
+                underway.
+
+    If a VPB is found which matches these conditions, then the address of
+    the VCB for that VPB is returned via the pointer Vcb.
+
+    Skip over the current Vcb.
+
+Arguments:
+
+    Vcb - This is the Vcb we are checking for a remount.
+
+    OldVcb -  A pointer to the address to store the address for the Vcb
+              for the volume if this is a remount.  (This is a pointer to
+              a pointer)
+
+Return Value:
+
+    BOOLEAN - TRUE if this is in fact a remount, FALSE otherwise.
+
+--*/
+
+{
+    PLIST_ENTRY Link;
+
+    PVPB Vpb = Vcb->Vpb;
+    PVPB OldVpb;
+
+    BOOLEAN Remount = FALSE;
+
+    PAGED_CODE();
+
+    //
+    //  Check whether we are looking for a device only Mvcb.
+    //
+
+    for (Link = CdData.VcbQueue.Flink;
+         Link != &CdData.VcbQueue;
+         Link = Link->Flink) {
+
+        *OldVcb = CONTAINING_RECORD( Link, VCB, VcbLinks );
+
+        //
+        //  Skip ourselves.
+        //
+
+        if (Vcb == *OldVcb) { continue; }
+
+        //
+        //  Look at the Vpb and state of the previous Vcb.
+        //
+
+        OldVpb = (*OldVcb)->Vpb;
+
+        if ((OldVpb != Vpb) &&
+            (OldVpb->RealDevice == Vpb->RealDevice) &&
+            ((*OldVcb)->VcbCondition == VcbNotMounted)) {
+
+            //
+            //  If the current disk is a raw disk then it can match a previous music or
+            //  raw disk.
+            //
+
+            if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK)) {
+
+                if (FlagOn( (*OldVcb)->VcbState, VCB_STATE_AUDIO_DISK )) {
+
+                    //
+                    //  If we have both TOC then fail the remount if the lengths
+                    //  are different or they don't match.
+                    //
+
+                    if ((Vcb->TocLength != (*OldVcb)->TocLength) ||
+                        ((Vcb->TocLength != 0) &&
+                         !RtlEqualMemory( Vcb->CdromToc,
+                                          (*OldVcb)->CdromToc,
+                                          Vcb->TocLength ))) {
+
+                        continue;
+                    }
+
+                    Remount = TRUE;
+                    break;
+                }
+
+            //
+            //  The current disk is not a raw disk.  Go ahead and compare
+            //  serial numbers and volume label.
+            //
+
+            } else if ((OldVpb->SerialNumber == Vpb->SerialNumber) &&
+                       (Vpb->VolumeLabelLength == OldVpb->VolumeLabelLength) &&
+                       (RtlEqualMemory( OldVpb->VolumeLabel,
+                                        Vpb->VolumeLabel,
+                                        Vpb->VolumeLabelLength ))) {
+
+                //
+                //  Remember the old mvcb.  Then set the return value to
+                //  TRUE and break.
+                //
+
+                Remount = TRUE;
+                break;
+            }
+        }
+    }
+
+    return Remount;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdFindActiveVolDescriptor (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN OUT PCHAR RawIsoVd,
+    IN BOOLEAN VerifyVolume
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to search for a valid secondary volume descriptor that
+    we will support.  Right now we only support Joliet escape sequences for
+    the secondary descriptor.
+
+    If we don't find the secondary descriptor then we will reread the primary.
+
+    This routine will update the serial number and volume label in the Vpb.
+
+Arguments:
+
+    Vcb - This is the Vcb for the volume being mounted.
+
+    RawIsoVd - Sector buffer used to read the volume descriptors from the disks, but
+               on input should contain the PVD (ISO) in the SECOND 'sector' of the
+               buffer.
+
+    VerifyVolume - indicates we are being called by the verify path, and should
+                   not modify the Vcb fields.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    BOOLEAN FoundSecondaryVd = FALSE;
+    ULONG SectorOffset = FIRST_VD_SECTOR;
+
+    ULONG Length;
+
+    ULONG Index;
+
+    PAGED_CODE();
+
+    //
+    //  We only look for secondary volume descriptors on an Iso disk.
+    //
+
+    if ((FlagOn( Vcb->VcbState, VCB_STATE_ISO) || VerifyVolume) && !CdNoJoliet) {
+
+        //
+        //  Scan the volume descriptors from the beginning looking for a valid
+        //  secondary or a terminator.
+        //
+
+        SectorOffset = FIRST_VD_SECTOR;
+
+        while (TRUE) {
+
+            //
+            //  Read the next sector.  We should never have an error in this
+            //  path.
+            //
+
+            CdReadSectors( IrpContext,
+                           LlBytesFromSectors( Vcb->BaseSector + SectorOffset ),
+                           SECTOR_SIZE,
+                           FALSE,
+                           RawIsoVd,
+                           Vcb->TargetDeviceObject );
+
+            //
+            //  Break out if the version number or standard Id is incorrect.
+            //  Also break out if this is a terminator.
+            //
+
+            if (!RtlEqualMemory( CdIsoId, CdRvdId( RawIsoVd, VCB_STATE_JOLIET ), VOL_ID_LEN ) ||
+                (CdRvdVersion( RawIsoVd, VCB_STATE_JOLIET ) != VERSION_1) ||
+                (CdRvdDescType( RawIsoVd, VCB_STATE_JOLIET ) == VD_TERMINATOR)) {
+
+                break;
+            }
+
+            //
+            //  We have a match if this is a secondary descriptor with a matching
+            //  escape sequence.
+            //
+
+            if ((CdRvdDescType( RawIsoVd, VCB_STATE_JOLIET ) == VD_SECONDARY) &&
+                (RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ),
+                                 CdJolietEscape[0],
+                                 ESC_SEQ_LEN ) ||
+                 RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ),
+                                 CdJolietEscape[1],
+                                 ESC_SEQ_LEN ) ||
+                 RtlEqualMemory( CdRvdEsc( RawIsoVd, VCB_STATE_JOLIET ),
+                                 CdJolietEscape[2],
+                                 ESC_SEQ_LEN ))) {
+
+                if (!VerifyVolume)  {
+                        
+                    //
+                    //  Update the Vcb with the new volume descriptor.
+                    //
+
+                    ClearFlag( Vcb->VcbState, VCB_STATE_ISO );
+                    SetFlag( Vcb->VcbState, VCB_STATE_JOLIET );
+
+                    Vcb->VdSectorOffset = SectorOffset;
+                }
+                
+                FoundSecondaryVd = TRUE;
+                break;
+            }
+
+            //
+            //  Otherwise move on to the next sector.
+            //
+
+            SectorOffset += 1;
+        }
+
+        //
+        //  If we didn't find the secondary then recover the original volume
+        //  descriptor stored in the second half of the RawIsoVd.
+        //
+
+        if (!FoundSecondaryVd) {
+
+            RtlCopyMemory( RawIsoVd,
+                           Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ),
+                           SECTOR_SIZE );
+        }
+    }
+
+    //
+    //  If we're in the verify path,  our work is done,  since we don't want
+    //  to update any Vcb/Vpb values.
+    //
+    
+    if (VerifyVolume)  {
+
+        return;
+    }
+        
+    //
+    //  Compute the serial number and volume label from the volume descriptor.
+    //
+
+    Vcb->Vpb->SerialNumber = CdSerial32( RawIsoVd, SECTOR_SIZE );
+
+    //
+    //  Make sure the CD label will fit in the Vpb.
+    //
+
+    ASSERT( VOLUME_ID_LENGTH * sizeof( WCHAR ) <= MAXIMUM_VOLUME_LABEL_LENGTH );
+
+    //
+    //  If this is not a Unicode label we must convert it to unicode.
+    //
+
+    if (!FlagOn( Vcb->VcbState, VCB_STATE_JOLIET )) {
+
+        //
+        //  Convert the label to unicode.  If we get any error then use a name
+        //  length of zero.
+        //
+
+        Vcb->Vpb->VolumeLabelLength = 0;
+
+        if (NT_SUCCESS( RtlOemToUnicodeN( &Vcb->Vpb->VolumeLabel[0],
+                                          MAXIMUM_VOLUME_LABEL_LENGTH,
+                                          &Length,
+                                          (PCHAR)CdRvdVolId( RawIsoVd, Vcb->VcbState ),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+                                          VOLUME_ID_LENGTH ))) {
+
+            Vcb->Vpb->VolumeLabelLength = (USHORT) Length;
+        }
+
+    //
+    //  We need to convert from big-endian to little endian.
+    //
+
+    } else {
+
+        CdConvertBigToLittleEndian( IrpContext,
+                                    (PCHAR)CdRvdVolId( RawIsoVd, Vcb->VcbState ),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+                                    VOLUME_ID_LENGTH,
+                                    (PCHAR) Vcb->Vpb->VolumeLabel );
+
+        Vcb->Vpb->VolumeLabelLength = VOLUME_ID_LENGTH * sizeof( WCHAR );
+    }
+
+    //
+    //  Strip the trailing spaces or zeroes from the name.
+    //
+
+    Index = Vcb->Vpb->VolumeLabelLength / sizeof( WCHAR );
+
+    while (Index > 0) {
+
+        if ((Vcb->Vpb->VolumeLabel[ Index - 1 ] != L'\0') &&
+            (Vcb->Vpb->VolumeLabel[ Index - 1 ] != L' ')) {
+
+            break;
+        }
+
+        Index -= 1;
+    }
+
+    //
+    //  Now set the final length for the name.
+    //
+
+    Vcb->Vpb->VolumeLabelLength = (USHORT) (Index * sizeof( WCHAR ));
+}
+
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/fspdisp.c b/reactos/drivers/filesystems/cdfs_new/fspdisp.c
new file mode 100755 (executable)
index 0000000..b7c4e80
--- /dev/null
@@ -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)
+
+\f
+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;
+}
+
+
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/lockctrl.c b/reactos/drivers/filesystems/cdfs_new/lockctrl.c
new file mode 100755 (executable)
index 0000000..a986fb3
--- /dev/null
@@ -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
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/namesup.c b/reactos/drivers/filesystems/cdfs_new/namesup.c
new file mode 100755 (executable)
index 0000000..9d687dd
--- /dev/null
@@ -0,0 +1,1044 @@
+/*++
+
+Copyright (c) 1991-2000 Microsoft Corporation
+
+Module Name:
+
+    NameSup.c
+
+Abstract:
+
+    This module implements the Cdfs Name support routines
+
+
+--*/
+
+#include "CdProcs.h"
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (CDFS_BUG_CHECK_NAMESUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdConvertBigToLittleEndian)
+#pragma alloc_text(PAGE, CdConvertNameToCdName)
+#pragma alloc_text(PAGE, CdDissectName)
+#pragma alloc_text(PAGE, CdGenerate8dot3Name)
+#pragma alloc_text(PAGE, CdFullCompareNames)
+#pragma alloc_text(PAGE, CdIs8dot3Name)
+#pragma alloc_text(PAGE, CdIsNameInExpression)
+#pragma alloc_text(PAGE, CdShortNameDirentOffset)
+#pragma alloc_text(PAGE, CdUpcaseName)
+#endif
+
+\f
+VOID
+CdConvertNameToCdName (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PCD_NAME CdName
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to convert a string of bytes into a CdName.
+
+    The full name is already in the CdName structure in the FileName field.
+    We split this into the filename and version strings.
+
+Arguments:
+
+    CdName - Pointer to CdName structure to update.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    ULONG NameLength = 0;
+    PWCHAR CurrentCharacter = CdName->FileName.Buffer;
+
+    PAGED_CODE();
+
+    //
+    //  Look for a separator character.
+    //
+
+    while ((NameLength < CdName->FileName.Length) &&
+           (*CurrentCharacter != L';')) {
+
+        CurrentCharacter += 1;
+        NameLength += 2;
+    }
+
+    //
+    //  If there is at least one more character after a possible separator then it
+    //  and all following characters are part of the version string.
+    //
+
+    CdName->VersionString.Length = 0;
+    if (NameLength + sizeof( WCHAR ) < CdName->FileName.Length) {
+
+        CdName->VersionString.MaximumLength =
+        CdName->VersionString.Length = (USHORT) (CdName->FileName.Length - NameLength - sizeof( WCHAR ));
+        CdName->VersionString.Buffer = Add2Ptr( CdName->FileName.Buffer,
+                                                NameLength + sizeof( WCHAR ),
+                                                PWCHAR );
+    }
+
+    //
+    //  Now update the filename portion of the name.
+    //
+
+    CdName->FileName.Length = (USHORT) NameLength;
+
+    return;
+}
+
+\f
+VOID
+CdConvertBigToLittleEndian (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCHAR BigEndian,
+    IN ULONG ByteCount,
+    OUT PCHAR LittleEndian
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to convert a unicode string in big endian to
+    little endian.  We start by copying all of the source bytes except
+    the first.  This will put the low order bytes in the correct position.
+    We then copy each high order byte in its correct position.
+
+Arguments:
+
+    BigEndian - Pointer to the string of big endian characters.
+
+    ByteCount - Number of unicode characters in this string.
+
+    LittleEndian - Pointer to array to store the little endian characters.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    ULONG RemainingByteCount = ByteCount;
+
+    PCHAR Source = BigEndian;
+    PCHAR Destination = LittleEndian;
+
+    PAGED_CODE();
+
+    //
+    //  If the byte count isn't an even number then the disk is corrupt.
+    //
+
+    if (FlagOn( ByteCount, 1 )) {
+
+        CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
+    }
+
+    //
+    //  Start by copy the low-order bytes into the correct position.  Do
+    //  this by skipping the first byte in the BigEndian string.
+    //
+
+    RtlCopyMemory( Destination,
+                   Source + 1,
+                   RemainingByteCount - 1 );
+
+    //
+    //  Now move the high-order bytes into position.
+    //
+
+    Destination += 1;
+
+    while (RemainingByteCount != 0) {
+
+        *Destination = *Source;
+
+        Source += 2;
+        Destination += 2;
+
+        RemainingByteCount -= 2;
+    }
+
+    return;
+}
+
+\f
+VOID
+CdUpcaseName (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCD_NAME Name,
+    IN OUT PCD_NAME UpcaseName
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to upcase a CdName structure.  We will do both
+    the filename and version strings.
+
+Arguments:
+
+    Name - This is the mixed case version of the name.
+
+    UpcaseName - This is the destination for the upcase operation.
+
+Return Value:
+
+    None.  This routine will raise all errors.
+
+--*/
+
+{
+    NTSTATUS Status;
+    //PVOID NewBuffer; /* ReactOS Change: GCC Uninitialized variable */
+
+    PAGED_CODE();
+
+    //
+    //  If the name structures are different then initialize the different components.
+    //
+
+    if (Name != UpcaseName) {
+
+        //
+        //  Initialize the version string portion of the name.
+        //
+
+        UpcaseName->VersionString.Length = 0;
+
+        if (Name->VersionString.Length != 0) {
+
+            UpcaseName->VersionString.MaximumLength =
+            UpcaseName->VersionString.Length = Name->VersionString.Length;
+
+            //
+            //  Initially set the buffer to point to where we need to insert
+            //  the separator.
+            //
+
+            UpcaseName->VersionString.Buffer = Add2Ptr( UpcaseName->FileName.Buffer,
+                                                        Name->FileName.Length,
+                                                        PWCHAR );
+
+            //
+            //  We are currently pointing to the location to store the separator.
+            //  Store the ';' and then move to the next character to
+            //  copy the data.
+            //
+
+            *(UpcaseName->VersionString.Buffer) = L';';
+
+            UpcaseName->VersionString.Buffer += 1;
+        }
+    }
+
+    //
+    //  Upcase the string using the correct upcase routine.
+    //
+
+    Status = RtlUpcaseUnicodeString( &UpcaseName->FileName,
+                                     &Name->FileName,
+                                     FALSE );
+
+    //
+    //  This should never fail.
+    //
+
+    ASSERT( Status == STATUS_SUCCESS );
+
+    if (Name->VersionString.Length != 0) {
+
+        Status = RtlUpcaseUnicodeString( &UpcaseName->VersionString,
+                                         &Name->VersionString,
+                                         FALSE );
+
+        //
+        //  This should never fail.
+        //
+
+        ASSERT( Status == STATUS_SUCCESS );
+    }
+
+    return;
+}
+
+\f
+VOID
+CdDissectName (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PUNICODE_STRING RemainingName,
+    OUT PUNICODE_STRING FinalName
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to strip off leading components of the name strings.  We search
+    for either the end of the string or separating characters.  The input remaining
+    name strings should have neither a trailing or leading backslash.
+
+Arguments:
+
+    RemainingName - Remaining name.
+
+    FinalName - Location to store next component of name.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    ULONG NameLength;
+    PWCHAR NextWchar;
+
+    PAGED_CODE();
+
+    //
+    //  Find the offset of the next component separators.
+    //
+
+    for (NameLength = 0, NextWchar = RemainingName->Buffer;
+         (NameLength < RemainingName->Length) && (*NextWchar != L'\\');
+         NameLength += sizeof( WCHAR) , NextWchar += 1);
+
+    //
+    //  Adjust all the strings by this amount.
+    //
+
+    FinalName->Buffer = RemainingName->Buffer;
+
+    FinalName->MaximumLength = FinalName->Length = (USHORT) NameLength;
+
+    //
+    //  If this is the last component then set the RemainingName lengths to zero.
+    //
+
+    if (NameLength == RemainingName->Length) {
+
+        RemainingName->Length = 0;
+
+    //
+    //  Otherwise we adjust the string by this amount plus the separating character.
+    //
+
+    } else {
+
+        RemainingName->MaximumLength -= (USHORT) (NameLength + sizeof( WCHAR ));
+        RemainingName->Length -= (USHORT) (NameLength + sizeof( WCHAR ));
+        RemainingName->Buffer = Add2Ptr( RemainingName->Buffer,
+                                         NameLength + sizeof( WCHAR ),
+                                         PWCHAR );
+    }
+
+    return;
+}
+
+\f
+BOOLEAN
+CdIs8dot3Name (
+    IN PIRP_CONTEXT IrpContext,
+    IN UNICODE_STRING FileName
+    )
+
+/*++
+
+Routine Description:
+
+    This routine checks if the name follows the 8.3 name conventions.  We check for
+    the name length and whether the characters are valid.
+
+Arguments:
+
+    FileName - String of bytes containing the name.
+
+Return Value:
+
+    BOOLEAN - TRUE if this name is a legal 8.3 name, FALSE otherwise.
+
+--*/
+
+{
+    CHAR DbcsNameBuffer[ BYTE_COUNT_8_DOT_3 ];
+    STRING DbcsName;
+
+    PWCHAR NextWchar;
+    ULONG Count;
+
+    ULONG DotCount = 0;
+    BOOLEAN LastCharDot = FALSE;
+
+    PAGED_CODE();
+
+    //
+    //  The length must be less than 24 bytes.
+    //
+
+    ASSERT( FileName.Length != 0 );
+    if (FileName.Length > BYTE_COUNT_8_DOT_3) {
+
+        return FALSE;
+    }
+
+    //
+    //  Walk though and check for a space character.
+    //
+
+    NextWchar = FileName.Buffer;
+    Count = 0;
+
+    do {
+
+        //
+        //  No spaces allowed.
+        //
+
+        if (*NextWchar == L' ') { return FALSE; }
+
+        if (*NextWchar == L'.') {
+
+            //
+            //  Not an 8.3 name if more than 1 dot or more than 8 characters
+            //  remaining.  (It is legal for the dot to be in the ninth
+            //  position)
+            //
+
+            if ((DotCount > 0) ||
+                (Count > 8 * sizeof( WCHAR ))) {
+
+                return FALSE;
+            }
+
+            DotCount += 1;
+            LastCharDot = TRUE;
+
+        } else {
+
+            LastCharDot = FALSE;
+        }
+
+        Count += 2;
+        NextWchar += 1;
+
+    } while (Count < FileName.Length);
+
+    //
+    //  Go ahead and truncate the dot if at the end.
+    //
+
+    if (LastCharDot) {
+
+        FileName.Length -= sizeof( WCHAR );
+    }
+
+    //
+    //  Create an Oem name to use to check for a valid short name.
+    //
+
+    DbcsName.MaximumLength = BYTE_COUNT_8_DOT_3;
+    DbcsName.Buffer = DbcsNameBuffer;
+
+    if (!NT_SUCCESS( RtlUnicodeStringToCountedOemString( &DbcsName,
+                                                         &FileName,
+                                                         FALSE ))) {
+
+        return FALSE;
+    }
+
+    //
+    //  We have now initialized the Oem string.  Call the FsRtl package to check for a
+    //  valid FAT name.
+    //
+
+    return FsRtlIsFatDbcsLegal( DbcsName, FALSE, FALSE, FALSE );
+}
+
+\f
+VOID
+CdGenerate8dot3Name (
+    IN PIRP_CONTEXT IrpContext,
+    IN PUNICODE_STRING FileName,
+    IN ULONG DirentOffset,
+    OUT PWCHAR ShortFileName,
+    OUT PUSHORT ShortByteCount
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to generate a short name from the given long name.  We will
+    generate a short name from the given long name.
+
+    We go through the following steps to make this conversion.
+
+        1 - Generate the generic short name.  This will also be in unicode format.
+
+        2 - Build the string representation of the dirent offset.
+
+        3 - Build the biased short name string by combining the generic short name with
+            the dirent offset string.
+
+        4 - Copy the final unicode string back to our caller's buffer.
+
+Arguments:
+
+    FileName - String of bytes containing the name.
+
+    DirentOffset - Offset in the directory for this filename.  We incorporate the offset into
+        the short name by dividing this by 32 and prepending a tilde character to the
+        digit character.  We then append this to the base of the generated short name.
+
+    ShortFileName - Pointer to the buffer to store the short name into.
+
+    ShortByteCount - Address to store the number of bytes in the short name.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    NTSTATUS Status;
+    UNICODE_STRING ShortName;
+    UNICODE_STRING BiasedShortName;
+    WCHAR ShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof( WCHAR ) ];
+    WCHAR BiasedShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof( WCHAR ) ];
+
+    GENERATE_NAME_CONTEXT NameContext;
+
+    ULONG BiasedDirentOffset;
+
+    ULONG MaximumBaseBytes;
+    ULONG BaseNameOffset;
+
+    PWCHAR NextWchar;
+    WCHAR ThisWchar;
+    USHORT Length;
+
+    BOOLEAN FoundTilde = FALSE;
+
+    OEM_STRING OemName;
+    USHORT OemNameOffset = 0;
+    BOOLEAN OverflowBuffer = FALSE;
+
+    PAGED_CODE();
+
+    //
+    //  Initialize the short string to use the input buffer.
+    //
+
+    ShortName.Buffer = ShortNameBuffer;
+    ShortName.MaximumLength = BYTE_COUNT_8_DOT_3;
+
+    //
+    //  Initialize the name context.
+    //
+
+    RtlZeroMemory( &NameContext, sizeof( GENERATE_NAME_CONTEXT ));
+
+    //
+    //  We now have the unicode name for the input string.  Go ahead and generate
+    //  the short name.
+    //
+
+    RtlGenerate8dot3Name( FileName, TRUE, &NameContext, &ShortName );
+
+    //
+    //  We now have the generic short name.  We want incorporate the dirent offset
+    //  into the name in order to reduce the chance of name conflicts.  We will use
+    //  a tilde character followed by a character representation of the dirent offset.
+    //  This will be the hexadecimal representation of the dirent offset in the directory.
+    //  It is actuall this offset divided by 32 since we don't need the full
+    //  granularity.
+    //
+
+    BiasedDirentOffset = DirentOffset >> SHORT_NAME_SHIFT;
+
+    //
+    //  Point to a local buffer to store the offset string.  We start
+    //  at the end of the buffer and work backwards.
+    //
+
+    NextWchar = Add2Ptr( BiasedShortNameBuffer,
+                         BYTE_COUNT_8_DOT_3,
+                         PWCHAR );
+
+    BiasedShortName.MaximumLength = BYTE_COUNT_8_DOT_3;
+
+    //
+    //  Generate an OEM version of the string so that we can check for double
+    //  byte characters.
+    //
+    
+    Status = RtlUnicodeStringToOemString(&OemName, &ShortName, TRUE);
+
+    if (!NT_SUCCESS( Status )) {
+
+        CdRaiseStatus( IrpContext, Status );
+    }
+    
+    Length = 0;
+
+    //
+    //  Now add the characters for the dirent offset.  We need to start
+    //  from the least significant digit and work backwards.
+    //
+
+    do {
+
+        NextWchar -= 1;
+
+        ThisWchar = (WCHAR) (BiasedDirentOffset & 0x0000000f);
+
+        //
+        //  Store in the next character.  Bias against either '0' or 'A'
+        //
+
+        if (ThisWchar <= 9) {
+
+            *NextWchar = ThisWchar + L'0';
+
+        } else {
+
+            *NextWchar = ThisWchar + L'A' - 0xA;
+        }
+
+        Length += sizeof( WCHAR );
+
+        //
+        //  Shift out the low 4 bits of the offset.
+        //
+
+        BiasedDirentOffset >>= 4;
+
+    } while (BiasedDirentOffset != 0);
+
+    //
+    //  Now store in the tilde character.
+    //
+
+    NextWchar -= 1;
+    *NextWchar = L'~';
+    Length += sizeof( WCHAR );
+
+    //
+    //  Set the length of this string.
+    //
+
+    BiasedShortName.Length = Length;
+    BiasedShortName.Buffer = NextWchar;
+
+    //
+    //  Figure out the maximum number of characters we can copy of the base
+    //  name.  We subract the number of characters in the dirent string from 8.
+    //  We will copy this many characters or stop when we reach a '.' character
+    //  or a '~' character in the name.
+    //
+
+    MaximumBaseBytes = 16 - Length;
+
+    BaseNameOffset = 0;
+
+    //
+    //  Keep copying from the base name until we hit a '.', '~'  or the end of
+    //  the short name.
+    //
+
+    NextWchar = ShortFileName;
+    Length = 0;
+
+    while ((BaseNameOffset < ShortName.Length) &&
+           (ShortName.Buffer[BaseNameOffset / 2] != L'.')) {
+
+        //
+        //  Remember if we found a tilde character in the short name,
+        //  so we don't copy it or anything following it.
+        //
+
+        if (ShortName.Buffer[BaseNameOffset / 2] == L'~') {
+
+            FoundTilde = TRUE;
+        }
+
+        //
+        // We need to consider the DBCS code page,  because Unicode characters
+        // may use 2 bytes as DBCS characters.
+        //
+
+        if (FsRtlIsLeadDbcsCharacter(OemName.Buffer[OemNameOffset])) {
+
+            OemNameOffset += 2;
+        }
+        else  {
+        
+            OemNameOffset++;
+        }
+
+        if ((OemNameOffset + (BiasedShortName.Length / sizeof(WCHAR))) > 8)  {
+        
+            OverflowBuffer = TRUE;
+        }
+
+        //
+        //  Only copy the bytes if we still have space for the dirent string.
+        //
+
+        if (!FoundTilde && !OverflowBuffer && (BaseNameOffset < MaximumBaseBytes)) {
+
+            *NextWchar = ShortName.Buffer[BaseNameOffset / 2];
+            Length += sizeof( WCHAR );
+            NextWchar += 1;
+        }
+
+        BaseNameOffset += 2;
+    }
+
+    RtlFreeOemString(&OemName);
+
+    //
+    //  Now copy the dirent string into the biased name buffer.
+    //
+
+    RtlCopyMemory( NextWchar,
+                   BiasedShortName.Buffer,
+                   BiasedShortName.Length );
+
+    Length += BiasedShortName.Length;
+    NextWchar += (BiasedShortName.Length / sizeof( WCHAR ));
+
+    //
+    //  Now copy any remaining bytes over to the biased short name.
+    //
+
+    if (BaseNameOffset != ShortName.Length) {
+
+        RtlCopyMemory( NextWchar,
+                       &ShortName.Buffer[BaseNameOffset / 2],
+                       ShortName.Length - BaseNameOffset );
+
+        Length += (ShortName.Length - (USHORT) BaseNameOffset);
+    }
+
+    //
+    //  The final short name is stored in the user's buffer.
+    //
+
+    *ShortByteCount = Length;
+
+    return;
+}
+
+\f
+BOOLEAN
+CdIsNameInExpression (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCD_NAME CurrentName,
+    IN PCD_NAME SearchExpression,
+    IN ULONG  WildcardFlags,
+    IN BOOLEAN CheckVersion
+    )
+
+/*++
+
+Routine Description:
+
+    This routine will compare two CdName strings.  We assume that if this
+    is to be a case-insensitive search then they are already upcased.
+
+    We compare the filename portions of the name and if they match we
+    compare the version strings if requested.
+
+Arguments:
+
+    CurrentName - Filename from the disk.
+
+    SearchExpression - Filename expression to use for match.
+
+    WildcardFlags - Flags field which indicates which parts of the
+        search expression might have wildcards.  These flags are the
+        same as in the Ccb flags field.
+
+    CheckVersion - Indicates whether we should check both the name and the
+        version strings or just the name.
+
+Return Value:
+
+    BOOLEAN - TRUE if the expressions match, FALSE otherwise.
+
+--*/
+
+{
+    BOOLEAN Match = TRUE;
+    PAGED_CODE();
+
+    //
+    //  If there are wildcards in the expression then we call the
+    //  appropriate FsRtlRoutine.
+    //
+
+    if (FlagOn( WildcardFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD )) {
+
+        Match = FsRtlIsNameInExpression( &SearchExpression->FileName,
+                                         &CurrentName->FileName,
+                                         FALSE,
+                                         NULL );
+
+    //
+    //  Otherwise do a direct memory comparison for the name string.
+    //
+
+    } else {
+
+        if ((CurrentName->FileName.Length != SearchExpression->FileName.Length) ||
+            (!RtlEqualMemory( CurrentName->FileName.Buffer,
+                              SearchExpression->FileName.Buffer,
+                              CurrentName->FileName.Length ))) {
+
+            Match = FALSE;
+        }
+    }
+
+    //
+    //  Check the version numbers if requested by the user and we have a
+    //  match on the name and the version number is present.
+    //
+
+    if (Match && CheckVersion && SearchExpression->VersionString.Length &&
+        !FlagOn( WildcardFlags, CCB_FLAG_ENUM_VERSION_MATCH_ALL )) {
+
+        //
+        //  If there are wildcards in the expression then call the
+        //  appropriate search expression.
+        //
+
+        if (FlagOn( WildcardFlags, CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD )) {
+
+            Match = FsRtlIsNameInExpression( &SearchExpression->VersionString,
+                                             &CurrentName->VersionString,
+                                             FALSE,
+                                             NULL );
+
+        //
+        //  Otherwise do a direct memory comparison for the name string.
+        //
+
+        } else {
+
+            if ((CurrentName->VersionString.Length != SearchExpression->VersionString.Length) ||
+                (!RtlEqualMemory( CurrentName->VersionString.Buffer,
+                                  SearchExpression->VersionString.Buffer,
+                                  CurrentName->VersionString.Length ))) {
+
+                Match = FALSE;
+            }
+        }
+    }
+
+    return Match;
+}
+
+\f
+ULONG
+CdShortNameDirentOffset (
+    IN PIRP_CONTEXT IrpContext,
+    IN PUNICODE_STRING Name
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to examine a name to see if the dirent offset string is contained.
+    This consists of a tilde character followed by the offset represented as a hexadecimal
+    characters.  We don't do any other checks to see if this is a short name.  We
+    catch that later outside this routine.
+
+Arguments:
+
+    Name - This is the CdName to examine.
+
+Return Value:
+
+    ULONG - MAXULONG if there is no valid dirent offset string embedded, otherwise the
+        convert the value to numeric form.
+
+--*/
+
+{
+    ULONG ResultOffset = MAXULONG;
+    ULONG RemainingByteCount = Name->Length;
+
+    BOOLEAN FoundTilde = FALSE;
+
+    PWCHAR NextWchar;
+
+    PAGED_CODE();
+
+    //
+    //  Walk through the name until we either reach the end of the name
+    //  or find a tilde character.
+    //
+
+    for (NextWchar = Name->Buffer;
+         RemainingByteCount != 0;
+         NextWchar += 1, RemainingByteCount -= sizeof( WCHAR )) {
+
+        //
+        //  Check if this is a dot.  Stop constructing any string if
+        //  we found a dot.
+        //
+
+        if (*NextWchar == L'.') {
+
+            break;
+        }
+
+        //
+        //  If we already found a tilde then check this character as a
+        //  valid character.  It must be a digit or A to F.
+        //
+
+        if (FoundTilde) {
+
+            if ((*NextWchar < L'0') ||
+                (*NextWchar > L'F') ||
+                ((*NextWchar > L'9') && (*NextWchar < 'A'))) {
+
+                ResultOffset = MAXULONG;
+                break;
+            }
+
+            //
+            //  Shift the result by 4 bits and add in this new character.
+            //
+
+            ResultOffset <<= 4;
+
+            if (*NextWchar < L'A') {
+
+                ResultOffset += *NextWchar - L'0';
+
+            } else {
+
+                ResultOffset += (*NextWchar - L'A') + 10;
+            }
+
+            continue;
+        }
+
+        //
+        //  If this is a tilde then start building the dirent string.
+        //
+
+        if (*NextWchar == L'~') {
+
+            FoundTilde = TRUE;
+            ResultOffset = 0;
+        }
+    }
+
+    return ResultOffset;
+}
+
+\f
+//
+//  Local support routine
+//
+
+FSRTL_COMPARISON_RESULT
+CdFullCompareNames (
+    IN PIRP_CONTEXT IrpContext,
+    IN PUNICODE_STRING NameA,
+    IN PUNICODE_STRING NameB
+    )
+
+/*++
+
+Routine Description:
+
+    This function compares two names as fast as possible.  Note that since
+    this comparison is case sensitive we can do a direct memory comparison.
+
+Arguments:
+
+    NameA & NameB - The names to compare.
+
+Return Value:
+
+    COMPARISON - returns
+
+        LessThan    if NameA < NameB lexicalgraphically,
+        GreaterThan if NameA > NameB lexicalgraphically,
+        EqualTo     if NameA is equal to NameB
+
+--*/
+
+{
+    SIZE_T i;
+    ULONG MinLength = NameA->Length;
+    FSRTL_COMPARISON_RESULT Result = LessThan;
+
+    PAGED_CODE();
+
+    //
+    //  Figure out the minimum of the two lengths
+    //
+
+    if (NameA->Length > NameB->Length) {
+
+        MinLength = NameB->Length;
+        Result = GreaterThan;
+
+    } else if (NameA->Length == NameB->Length) {
+
+        Result = EqualTo;
+    }
+
+    //
+    //  Loop through looking at all of the characters in both strings
+    //  testing for equalilty, less than, and greater than
+    //
+
+    i = RtlCompareMemory( NameA->Buffer, NameB->Buffer, MinLength );
+
+    if (i < MinLength) {
+
+        //
+        //  We know the offset of the first character which is different.
+        //
+
+        return ((NameA->Buffer[ i / 2 ] < NameB->Buffer[ i / 2 ]) ?
+                 LessThan :
+                 GreaterThan);
+    }
+
+    //
+    //  The names match up to the length of the shorter string.
+    //  The shorter string lexically appears first.
+    //
+
+    return Result;
+}
+
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/nodetype.h b/reactos/drivers/filesystems/cdfs_new/nodetype.h
new file mode 100755 (executable)
index 0000000..6793954
--- /dev/null
@@ -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
+\f
+//
+//  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_
+
diff --git a/reactos/drivers/filesystems/cdfs_new/pathsup.c b/reactos/drivers/filesystems/cdfs_new/pathsup.c
new file mode 100755 (executable)
index 0000000..f9484d2
--- /dev/null
@@ -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
+
+\f
+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 );
+}
+
+\f
+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 );
+}
+
+\f
+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;
+}
+
+\f
+//
+//  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;
+}
+
+\f
+//
+//  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;
+}
+
+\f
+//
+//  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;
+}
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/pnp.c b/reactos/drivers/filesystems/cdfs_new/pnp.c
new file mode 100755 (executable)
index 0000000..48f8dc4
--- /dev/null
@@ -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 );
+}
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/prefxsup.c b/reactos/drivers/filesystems/cdfs_new/prefxsup.c
new file mode 100755 (executable)
index 0000000..c00b98e
--- /dev/null
@@ -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
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+    }
+}
+
+\f
+//
+//  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;
+}
+
+\f
+//
+//  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;
+}
+
+
+
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/read.c b/reactos/drivers/filesystems/cdfs_new/read.c
new file mode 100755 (executable)
index 0000000..9e18fd3
--- /dev/null
@@ -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
+
+\f
+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;
+}
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/resrcsup.c b/reactos/drivers/filesystems/cdfs_new/resrcsup.c
new file mode 100755 (executable)
index 0000000..abfecdc
--- /dev/null
@@ -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
+
+\f
+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;
+}
+
+\f
+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 );
+}
+
+\f
+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 );
+}
+
+\f
+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;
+}
+
+\f
+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();
+}
+
+\f
+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 );
+}
+
+\f
+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);
+}
+
diff --git a/reactos/drivers/filesystems/cdfs_new/strucsup.c b/reactos/drivers/filesystems/cdfs_new/strucsup.c
new file mode 100755 (executable)
index 0000000..0ab42dc
--- /dev/null
@@ -0,0 +1,2766 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+    StrucSup.c
+
+Abstract:
+
+    This module implements the Cdfs in-memory data structure manipulation
+    routines
+
+
+--*/
+
+#include "CdProcs.h"
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (CDFS_BUG_CHECK_STRUCSUP)
+
+//
+//  Local macros
+//
+
+//
+//  PFCB
+//  CdAllocateFcbData (
+//      IN PIRP_CONTEXT IrpContext
+//      );
+//
+//  VOID
+//  CdDeallocateFcbData (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+//  PFCB
+//  CdAllocateFcbIndex (
+//      IN PIRP_CONTEXT IrpContext
+//      );
+//
+//  VOID
+//  CdDeallocateFcbIndex (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+//  PFCB_NONPAGED
+//  CdAllocateFcbNonpaged (
+//      IN PIRP_CONTEXT IrpContext
+//      );
+//
+//  VOID
+//  CdDeallocateFcbNonpaged (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB_NONPAGED FcbNonpaged
+//      );
+//
+//  PCCB
+//  CdAllocateCcb (
+//      IN PIRP_CONTEXT IrpContext
+//      );
+//
+//  VOID
+//  CdDeallocateCcb (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PCCB Ccb
+//      );
+//
+
+#define CdAllocateFcbData(IC) \
+    FsRtlAllocatePoolWithTag( CdPagedPool, SIZEOF_FCB_DATA, TAG_FCB_DATA )
+
+#define CdDeallocateFcbData(IC,F) \
+    CdFreePool( &(F) )
+
+#define CdAllocateFcbIndex(IC) \
+    FsRtlAllocatePoolWithTag( CdPagedPool, SIZEOF_FCB_INDEX, TAG_FCB_INDEX )
+
+#define CdDeallocateFcbIndex(IC,F) \
+    CdFreePool( &(F) )
+
+#define CdAllocateFcbNonpaged(IC) \
+    ExAllocatePoolWithTag( CdNonPagedPool, sizeof( FCB_NONPAGED ), TAG_FCB_NONPAGED )
+
+#define CdDeallocateFcbNonpaged(IC,FNP) \
+    CdFreePool( &(FNP) )
+
+#define CdAllocateCcb(IC) \
+    FsRtlAllocatePoolWithTag( CdPagedPool, sizeof( CCB ), TAG_CCB )
+
+#define CdDeallocateCcb(IC,C) \
+    CdFreePool( &(C) )
+
+//
+//  Local structures
+//
+
+typedef struct _FCB_TABLE_ELEMENT {
+
+    FILE_ID FileId;
+    PFCB Fcb;
+
+} FCB_TABLE_ELEMENT, *PFCB_TABLE_ELEMENT;
+
+//
+//  Local macros
+//
+
+//
+//  VOID
+//  CdInsertFcbTable (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+//  VOID
+//  CdDeleteFcbTable (
+//      IN PIRP_CONTEXT IrpContext,
+//      IN PFCB Fcb
+//      );
+//
+
+
+#define CdInsertFcbTable(IC,F) {                                    \
+    FCB_TABLE_ELEMENT _Key;                                         \
+    _Key.Fcb = (F);                                                 \
+    _Key.FileId = (F)->FileId;                                      \
+    RtlInsertElementGenericTable( &(F)->Vcb->FcbTable,              \
+                                  &_Key,                            \
+                                  sizeof( FCB_TABLE_ELEMENT ),      \
+                                  NULL );                           \
+}
+
+#define CdDeleteFcbTable(IC,F) {                                    \
+    FCB_TABLE_ELEMENT _Key;                                         \
+    _Key.FileId = (F)->FileId;                                      \
+    RtlDeleteElementGenericTable( &(F)->Vcb->FcbTable, &_Key );     \
+}
+
+//
+//  Local support routines
+//
+
+VOID
+CdDeleteFcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb
+    );
+
+PFCB_NONPAGED
+CdCreateFcbNonpaged (
+    IN PIRP_CONTEXT IrpContext
+    );
+
+VOID
+CdDeleteFcbNonpaged (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB_NONPAGED FcbNonpaged
+    );
+
+RTL_GENERIC_COMPARE_RESULTS
+CdFcbTableCompare (
+    IN PRTL_GENERIC_TABLE FcbTable,
+    IN PVOID Fid1,
+    IN PVOID Fid2
+    );
+
+PVOID
+CdAllocateFcbTable (
+    IN PRTL_GENERIC_TABLE FcbTable,
+    IN CLONG ByteSize
+    );
+
+VOID
+CdDeallocateFcbTable (
+    IN PRTL_GENERIC_TABLE FcbTable,
+    IN PVOID Buffer
+    );
+
+ULONG
+CdTocSerial (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCDROM_TOC CdromToc
+    );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdAllocateFcbTable)
+#pragma alloc_text(PAGE, CdCleanupIrpContext)
+#pragma alloc_text(PAGE, CdCreateCcb)
+#pragma alloc_text(PAGE, CdCreateFcb)
+#pragma alloc_text(PAGE, CdCreateFcbNonpaged)
+#pragma alloc_text(PAGE, CdCreateFileLock)
+#pragma alloc_text(PAGE, CdCreateIrpContext)
+#pragma alloc_text(PAGE, CdDeallocateFcbTable)
+#pragma alloc_text(PAGE, CdDeleteCcb)
+#pragma alloc_text(PAGE, CdDeleteFcb)
+#pragma alloc_text(PAGE, CdDeleteFcbNonpaged)
+#pragma alloc_text(PAGE, CdDeleteFileLock)
+#pragma alloc_text(PAGE, CdDeleteVcb)
+#pragma alloc_text(PAGE, CdFcbTableCompare)
+#pragma alloc_text(PAGE, CdGetNextFcb)
+#pragma alloc_text(PAGE, CdInitializeFcbFromFileContext)
+#pragma alloc_text(PAGE, CdInitializeFcbFromPathEntry)
+#pragma alloc_text(PAGE, CdInitializeStackIrpContext)
+#pragma alloc_text(PAGE, CdInitializeVcb)
+#pragma alloc_text(PAGE, CdLookupFcbTable)
+#pragma alloc_text(PAGE, CdProcessToc)
+#pragma alloc_text(PAGE, CdTeardownStructures)
+#pragma alloc_text(PAGE, CdTocSerial)
+#pragma alloc_text(PAGE, CdUpdateVcbFromVolDescriptor)
+#endif
+
+\f
+VOID
+CdInitializeVcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PVCB Vcb,
+    IN PDEVICE_OBJECT TargetDeviceObject,
+    IN PVPB Vpb,
+    IN PCDROM_TOC CdromToc,
+    IN ULONG TocLength,
+    IN ULONG TocTrackCount,
+    IN ULONG TocDiskFlags,
+    IN ULONG BlockFactor,
+    IN ULONG MediaChangeCount
+    )
+
+/*++
+
+Routine Description:
+
+    This routine initializes and inserts a new Vcb record into the in-memory
+    data structure.  The Vcb record "hangs" off the end of the Volume device
+    object and must be allocated by our caller.
+
+Arguments:
+
+    Vcb - Supplies the address of the Vcb record being initialized.
+
+    TargetDeviceObject - Supplies the address of the target device object to
+        associate with the Vcb record.
+
+    Vpb - Supplies the address of the Vpb to associate with the Vcb record.
+
+    CdromToc - Buffer to hold table of contents.  NULL if TOC command not
+        supported.
+
+    TocLength - Byte count length of TOC.  We use this as the TOC length to
+        return on a user query.
+
+    TocTrackCount - Count of tracks in TOC.  Used to create pseudo files for
+        audio disks.
+
+    TocDiskFlags - Flag field to indicate the type of tracks on the disk.
+
+    BlockFactor - Used to decode any multi-session information.
+
+    MediaChangeCount - Initial media change count of the target device
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  We start by first zeroing out all of the VCB, this will guarantee
+    //  that any stale data is wiped clean.
+    //
+
+    RtlZeroMemory( Vcb, sizeof( VCB ));
+
+    //
+    //  Set the proper node type code and node byte size.
+    //
+
+    Vcb->NodeTypeCode = CDFS_NTC_VCB;
+    Vcb->NodeByteSize = sizeof( VCB );
+
+    //
+    //  Initialize the DirNotify structs.  FsRtlNotifyInitializeSync can raise.
+    //
+
+    InitializeListHead( &Vcb->DirNotifyList );
+    FsRtlNotifyInitializeSync( &Vcb->NotifySync );
+    
+    //
+    //  Pick up a VPB right now so we know we can pull this filesystem stack
+    //  off of the storage stack on demand.  This can raise - if it does,  
+    //  uninitialize the notify structures before returning.
+    //
+    
+    try  {
+
+        Vcb->SwapVpb = FsRtlAllocatePoolWithTag( NonPagedPool,
+                                                 sizeof( VPB ),
+                                                 TAG_VPB );
+    }
+    finally {
+
+        if (AbnormalTermination())  {
+        
+            FsRtlNotifyUninitializeSync( &Vcb->NotifySync );
+        }
+    }
+
+    //
+    //  Nothing beyond this point should raise.
+    //
+
+    RtlZeroMemory( Vcb->SwapVpb, sizeof( VPB ) );
+    
+    //
+    //  Initialize the resource variable for the Vcb and files.
+    //
+
+    ExInitializeResourceLite( &Vcb->VcbResource );
+    ExInitializeResourceLite( &Vcb->FileResource );
+    ExInitializeFastMutex( &Vcb->VcbMutex );
+
+    //
+    //  Insert this Vcb record on the CdData.VcbQueue.
+    //
+
+    InsertHeadList( &CdData.VcbQueue, &Vcb->VcbLinks );
+
+    //
+    //  Set the Target Device Object and Vpb fields, referencing the
+    //  Target device for the mount.
+    //
+
+    ObReferenceObject( TargetDeviceObject );
+    Vcb->TargetDeviceObject = TargetDeviceObject;
+    Vcb->Vpb = Vpb;
+
+    //
+    //  Set the removable media flag based on the real device's
+    //  characteristics
+    //
+
+    if (FlagOn( Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA )) {
+
+        SetFlag( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA );
+    }
+
+    //
+    //  Initialize the generic Fcb Table.
+    //
+
+    RtlInitializeGenericTable( &Vcb->FcbTable,
+                               (PRTL_GENERIC_COMPARE_ROUTINE) CdFcbTableCompare,
+                               (PRTL_GENERIC_ALLOCATE_ROUTINE) CdAllocateFcbTable,
+                               (PRTL_GENERIC_FREE_ROUTINE) CdDeallocateFcbTable,
+                               NULL );
+
+    //
+    //  Show that we have a mount in progress.
+    //
+
+    CdUpdateVcbCondition( Vcb, VcbMountInProgress);
+
+    //
+    //  Refererence the Vcb for two reasons.  The first is a reference
+    //  that prevents the Vcb from going away on the last close unless
+    //  dismount has already occurred.  The second is to make sure
+    //  we don't go into the dismount path on any error during mount
+    //  until we get to the Mount cleanup.
+    //
+
+    Vcb->VcbReference = 1 + CDFS_RESIDUAL_REFERENCE;
+
+    //
+    //  Update the TOC information in the Vcb.
+    //
+
+    Vcb->CdromToc = CdromToc;
+    Vcb->TocLength = TocLength;
+    Vcb->TrackCount = TocTrackCount;
+    Vcb->DiskFlags = TocDiskFlags;
+
+    //
+    //  If this disk contains audio tracks only then set the audio flag.
+    //
+
+    if (TocDiskFlags == CDROM_DISK_AUDIO_TRACK) {
+
+        SetFlag( Vcb->VcbState, VCB_STATE_AUDIO_DISK | VCB_STATE_CDXA );
+    }
+
+    //
+    //  Set the block factor.
+    //
+
+    Vcb->BlockFactor = BlockFactor;
+
+    //
+    //  Set the media change count on the device
+    //
+
+    CdUpdateMediaChangeCount( Vcb, MediaChangeCount);
+}
+
+\f
+VOID
+CdUpdateVcbFromVolDescriptor (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PVCB Vcb,
+    IN PCHAR RawIsoVd OPTIONAL
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to perform the final initialization of a Vcb from the
+    volume descriptor on the disk.
+
+Arguments:
+
+    Vcb - Vcb for the volume being mounted.  We have already set the flags for the
+        type of descriptor.
+
+    RawIsoVd - If specified this is the volume descriptor to use to mount the
+        volume.  Not specified for a raw disk.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    //ULONG Shift; /* ReactOS Change: GCC Unused variable */
+    ULONG StartingBlock;
+    ULONG ByteCount;
+
+    LONGLONG FileId = 0;
+
+    PRAW_DIRENT RawDirent;
+    PATH_ENTRY PathEntry;
+    PCD_MCB_ENTRY McbEntry;
+
+    BOOLEAN UnlockVcb = FALSE;
+
+    PAGED_CODE();
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    try {
+
+        //
+        //  Copy the block size and compute the various block masks.
+        //  Block size must not be larger than the sector size.  We will
+        //  use a default of the CD physical sector size if we are not
+        //  on a data-full disc.
+        //
+        //  This must always be set.
+        //
+
+        Vcb->BlockSize = ( ARGUMENT_PRESENT( RawIsoVd ) ?
+                            CdRvdBlkSz( RawIsoVd, Vcb->VcbState ) :
+                            SECTOR_SIZE );
+
+        //
+        //  We no longer accept media where blocksize != sector size.
+        //
+        
+        if (Vcb->BlockSize != SECTOR_SIZE)  {
+
+            CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
+        }
+
+        Vcb->BlocksPerSector = SECTOR_SIZE / Vcb->BlockSize;
+        Vcb->BlockMask = Vcb->BlockSize - 1;
+        Vcb->BlockInverseMask = ~Vcb->BlockMask;
+     
+        Vcb->BlockToSectorShift = 0;
+        Vcb->BlockToByteShift = SECTOR_SHIFT;
+
+        //
+        //  If there is a volume descriptor then do the internal Fcb's and
+        //  other Vcb fields.
+        //
+
+        if (ARGUMENT_PRESENT( RawIsoVd )) {
+
+            //
+            //  Create the path table Fcb and refererence it and the Vcb.
+            //
+
+            CdLockVcb( IrpContext, Vcb );
+            UnlockVcb = TRUE;
+
+            Vcb->PathTableFcb = CdCreateFcb( IrpContext,
+                                             *((PFILE_ID) &FileId),
+                                             CDFS_NTC_FCB_PATH_TABLE,
+                                             NULL );
+
+            CdIncrementReferenceCounts( IrpContext, Vcb->PathTableFcb, 1, 1 );
+            CdUnlockVcb( IrpContext, Vcb );
+            UnlockVcb = FALSE;
+
+            //
+            //  Compute the stream offset and size of this path table.
+            //
+
+            StartingBlock = CdRvdPtLoc( RawIsoVd, Vcb->VcbState );
+
+            ByteCount = CdRvdPtSz( RawIsoVd, Vcb->VcbState );
+
+            Vcb->PathTableFcb->StreamOffset = BytesFromBlocks( Vcb,
+                                                               SectorBlockOffset( Vcb, StartingBlock ));
+
+            Vcb->PathTableFcb->FileSize.QuadPart = (LONGLONG) (Vcb->PathTableFcb->StreamOffset +
+                                                               ByteCount);
+
+            Vcb->PathTableFcb->ValidDataLength.QuadPart = Vcb->PathTableFcb->FileSize.QuadPart;
+
+            Vcb->PathTableFcb->AllocationSize.QuadPart = LlSectorAlign( Vcb->PathTableFcb->FileSize.QuadPart );
+
+            //
+            //  Now add the mapping information.
+            //
+
+            CdLockFcb( IrpContext, Vcb->PathTableFcb );
+
+            CdAddInitialAllocation( IrpContext,
+                                    Vcb->PathTableFcb,
+                                    StartingBlock,
+                                    Vcb->PathTableFcb->AllocationSize.QuadPart );
+
+            CdUnlockFcb( IrpContext, Vcb->PathTableFcb );
+
+            //
+            //  Point to the file resource.
+            //
+
+            Vcb->PathTableFcb->Resource = &Vcb->FileResource;
+
+            //
+            //  Mark the Fcb as initialized and create the stream file for this.
+            //
+
+            SetFlag( Vcb->PathTableFcb->FcbState, FCB_STATE_INITIALIZED );
+
+            CdCreateInternalStream( IrpContext, Vcb, Vcb->PathTableFcb );
+
+            //
+            //  Create the root index and reference it in the Vcb.
+            //
+
+            CdLockVcb( IrpContext, Vcb );
+            UnlockVcb = TRUE;
+            Vcb->RootIndexFcb = CdCreateFcb( IrpContext,
+                                             *((PFILE_ID) &FileId),
+                                             CDFS_NTC_FCB_INDEX,
+                                             NULL );
+
+            CdIncrementReferenceCounts( IrpContext, Vcb->RootIndexFcb, 1, 1 );
+            CdUnlockVcb( IrpContext, Vcb );
+            UnlockVcb = FALSE;
+
+            //
+            //  Create the File id by hand for this Fcb.
+            //
+
+            CdSetFidPathTableOffset( Vcb->RootIndexFcb->FileId, Vcb->PathTableFcb->StreamOffset );
+            CdFidSetDirectory( Vcb->RootIndexFcb->FileId );
+
+            //
+            //  Create a pseudo path table entry so we can call the initialization
+            //  routine for the directory.
+            //
+
+            RawDirent = (PRAW_DIRENT) CdRvdDirent( RawIsoVd, Vcb->VcbState );
+
+            CopyUchar4( &PathEntry.DiskOffset, RawDirent->FileLoc );
+
+            PathEntry.DiskOffset += RawDirent->XarLen;
+            PathEntry.Ordinal = 1;
+            PathEntry.PathTableOffset = Vcb->PathTableFcb->StreamOffset;
+
+            CdInitializeFcbFromPathEntry( IrpContext,
+                                          Vcb->RootIndexFcb,
+                                          NULL,
+                                          &PathEntry );
+
+            //
+            //  Create the stream file for the root directory.
+            //
+
+            CdCreateInternalStream( IrpContext, Vcb, Vcb->RootIndexFcb );
+
+            //
+            //  Now do the volume dasd Fcb.  Create this and reference it in the
+            //  Vcb.
+            //
+
+            CdLockVcb( IrpContext, Vcb );
+            UnlockVcb = TRUE;
+
+            Vcb->VolumeDasdFcb = CdCreateFcb( IrpContext,
+                                              *((PFILE_ID) &FileId),
+                                              CDFS_NTC_FCB_DATA,
+                                              NULL );
+
+            CdIncrementReferenceCounts( IrpContext, Vcb->VolumeDasdFcb, 1, 1 );
+            CdUnlockVcb( IrpContext, Vcb );
+            UnlockVcb = FALSE;
+
+            //
+            //  The file size is the full disk.
+            //
+
+            StartingBlock = CdRvdVolSz( RawIsoVd, Vcb->VcbState );
+
+            Vcb->VolumeDasdFcb->FileSize.QuadPart = LlBytesFromBlocks( Vcb, StartingBlock );
+
+            Vcb->VolumeDasdFcb->AllocationSize.QuadPart =
+            Vcb->VolumeDasdFcb->ValidDataLength.QuadPart = Vcb->VolumeDasdFcb->FileSize.QuadPart;
+
+            //
+            //  Now add the extent representing the volume 'by hand'.
+            //
+
+            CdLockFcb( IrpContext, Vcb->VolumeDasdFcb );
+
+            McbEntry = Vcb->VolumeDasdFcb->Mcb.McbArray;
+
+            McbEntry->FileOffset = 
+            McbEntry->DiskOffset = 0;
+            
+            McbEntry->ByteCount = Vcb->VolumeDasdFcb->AllocationSize.QuadPart;
+            
+            McbEntry->DataBlockByteCount =
+            McbEntry->TotalBlockByteCount = McbEntry->ByteCount;
+            
+            Vcb->VolumeDasdFcb->Mcb.CurrentEntryCount = 1;
+    
+            CdUnlockFcb( IrpContext, Vcb->VolumeDasdFcb );
+
+            //
+            //  Point to the file resource.
+            //
+
+            Vcb->VolumeDasdFcb->Resource = &Vcb->FileResource;
+
+            Vcb->VolumeDasdFcb->FileAttributes = FILE_ATTRIBUTE_READONLY;
+
+            //
+            //  Mark the Fcb as initialized.
+            //
+
+            SetFlag( Vcb->VolumeDasdFcb->FcbState, FCB_STATE_INITIALIZED );
+
+            //
+            //  Check and see if this is an XA disk.
+            //
+
+            if (FlagOn( Vcb->VcbState, VCB_STATE_ISO | VCB_STATE_JOLIET)
+                && RtlEqualMemory( CdXaId,
+                                   Add2Ptr( RawIsoVd, 0x400, PCHAR ),
+                                   8 )) {
+
+                SetFlag( Vcb->VcbState, VCB_STATE_CDXA );
+            }
+
+        //
+        //  If this is a music disk then we want to mock this disk to make it
+        //  look like ISO disk.  We will create a pseudo root directory in
+        //  that case.
+        //
+
+        } else if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
+
+            ULONG RootDirectorySize;
+
+            //
+            //  Create the path table Fcb and refererence it and the Vcb.
+            //
+
+            CdLockVcb( IrpContext, Vcb );
+            UnlockVcb = TRUE;
+
+            Vcb->PathTableFcb = CdCreateFcb( IrpContext,
+                                             *((PFILE_ID) &FileId),
+                                             CDFS_NTC_FCB_PATH_TABLE,
+                                             NULL );
+
+            CdIncrementReferenceCounts( IrpContext, Vcb->PathTableFcb, 1, 1 );
+            CdUnlockVcb( IrpContext, Vcb );
+            UnlockVcb = FALSE;
+
+            //
+            //  We only create a pseudo entry for the root.
+            //
+
+            Vcb->PathTableFcb->FileSize.QuadPart = (LONGLONG) (FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2);
+
+            Vcb->PathTableFcb->ValidDataLength.QuadPart = Vcb->PathTableFcb->FileSize.QuadPart;
+
+            Vcb->PathTableFcb->AllocationSize.QuadPart = LlSectorAlign( Vcb->PathTableFcb->FileSize.QuadPart );
+
+            //
+            //  Point to the file resource.
+            //
+
+            Vcb->PathTableFcb->Resource = &Vcb->FileResource;
+
+            //
+            //  Mark the Fcb as initialized and create the stream file for this.
+            //
+
+            SetFlag( Vcb->PathTableFcb->FcbState, FCB_STATE_INITIALIZED );
+
+            CdCreateInternalStream( IrpContext, Vcb, Vcb->PathTableFcb );
+
+            //
+            //  Create the root index and reference it in the Vcb.
+            //
+
+            CdLockVcb( IrpContext, Vcb );
+            UnlockVcb = TRUE;
+            Vcb->RootIndexFcb = CdCreateFcb( IrpContext,
+                                             *((PFILE_ID) &FileId),
+                                             CDFS_NTC_FCB_INDEX,
+                                             NULL );
+
+            CdIncrementReferenceCounts( IrpContext, Vcb->RootIndexFcb, 1, 1 );
+            CdUnlockVcb( IrpContext, Vcb );
+            UnlockVcb = FALSE;
+
+            //
+            //  Create the File id by hand for this Fcb.
+            //
+
+            CdSetFidPathTableOffset( Vcb->RootIndexFcb->FileId, Vcb->PathTableFcb->StreamOffset );
+            CdFidSetDirectory( Vcb->RootIndexFcb->FileId );
+
+            //
+            //  Create a pseudo path table entry so we can call the initialization
+            //  routine for the directory.
+            //
+
+            RtlZeroMemory( &PathEntry, sizeof( PATH_ENTRY ));
+
+
+            PathEntry.Ordinal = 1;
+            PathEntry.PathTableOffset = Vcb->PathTableFcb->StreamOffset;
+
+            CdInitializeFcbFromPathEntry( IrpContext,
+                                          Vcb->RootIndexFcb,
+                                          NULL,
+                                          &PathEntry );
+
+            //
+            //  Set the sizes by hand for this Fcb.  It should have an entry for each track plus an
+            //  entry for the root and parent.
+            //
+
+            RootDirectorySize = (Vcb->TrackCount + 2) * CdAudioDirentSize;
+            RootDirectorySize = SectorAlign( RootDirectorySize );
+
+            Vcb->RootIndexFcb->AllocationSize.QuadPart =
+            Vcb->RootIndexFcb->ValidDataLength.QuadPart =
+            Vcb->RootIndexFcb->FileSize.QuadPart = RootDirectorySize;
+
+            SetFlag( Vcb->RootIndexFcb->FcbState, FCB_STATE_INITIALIZED );
+
+            //
+            //  Create the stream file for the root directory.
+            //
+
+            CdCreateInternalStream( IrpContext, Vcb, Vcb->RootIndexFcb );
+
+            //
+            //  Now do the volume dasd Fcb.  Create this and reference it in the
+            //  Vcb.
+            //
+
+            CdLockVcb( IrpContext, Vcb );
+            UnlockVcb = TRUE;
+
+            Vcb->VolumeDasdFcb = CdCreateFcb( IrpContext,
+                                              *((PFILE_ID) &FileId),
+                                              CDFS_NTC_FCB_DATA,
+                                              NULL );
+
+            CdIncrementReferenceCounts( IrpContext, Vcb->VolumeDasdFcb, 1, 1 );
+            CdUnlockVcb( IrpContext, Vcb );
+            UnlockVcb = FALSE;
+
+            //
+            //  We won't allow raw reads on this Fcb so leave the size at
+            //  zero.
+            //
+
+            //
+            //  Point to the file resource.
+            //
+
+            Vcb->VolumeDasdFcb->Resource = &Vcb->FileResource;
+
+            Vcb->VolumeDasdFcb->FileAttributes = FILE_ATTRIBUTE_READONLY;
+
+            //
+            //  Mark the Fcb as initialized.
+            //
+
+            SetFlag( Vcb->VolumeDasdFcb->FcbState, FCB_STATE_INITIALIZED );
+
+            //
+            //  We will store a hard-coded name in the Vpb and use the toc as
+            //  the serial number.
+            //
+
+            Vcb->Vpb->VolumeLabelLength = CdAudioLabelLength;
+
+            RtlCopyMemory( Vcb->Vpb->VolumeLabel,
+                           CdAudioLabel,
+                           CdAudioLabelLength );
+
+            //
+            //  Find the serial number for the audio disk.
+            //
+
+            Vcb->Vpb->SerialNumber = CdTocSerial( IrpContext, Vcb->CdromToc );
+
+            //
+            //  Set the ISO bit so we know how to treat the names.
+            //
+
+            SetFlag( Vcb->VcbState, VCB_STATE_ISO );
+        }
+        
+    } finally {
+
+        if (UnlockVcb) { CdUnlockVcb( IrpContext, Vcb ); }
+    }
+}
+
+\f
+VOID
+CdDeleteVcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN OUT PVCB Vcb
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to delete a Vcb which failed mount or has been
+    dismounted.  The dismount code should have already removed all of the
+    open Fcb's.  We do nothing here but clean up other auxilary structures.
+
+Arguments:
+
+    Vcb - Vcb to delete.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    ASSERT_EXCLUSIVE_CDDATA;
+    ASSERT_EXCLUSIVE_VCB( Vcb );
+
+    //
+    //  Chuck the backpocket Vpb we kept just in case.
+    //
+
+    if (Vcb->SwapVpb) {
+
+        CdFreePool( &Vcb->SwapVpb );
+    }
+    
+    //
+    //  If there is a Vpb then we must delete it ourselves.
+    //
+
+    if (Vcb->Vpb != NULL) {
+
+        CdFreePool( &Vcb->Vpb );
+    }
+
+    //
+    //  Dereference our target if we haven't already done so.
+    //
+
+    if (Vcb->TargetDeviceObject != NULL) {
+    
+        ObDereferenceObject( Vcb->TargetDeviceObject );
+    }
+
+    //
+    //  Delete the XA Sector if allocated.
+    //
+
+    if (Vcb->XASector != NULL) {
+
+        CdFreePool( &Vcb->XASector );
+    }
+
+    //
+    //  Remove this entry from the global queue.
+    //
+
+    RemoveEntryList( &Vcb->VcbLinks );
+
+    //
+    //  Delete the Vcb and File resources.
+    //
+
+    ExDeleteResourceLite( &Vcb->VcbResource );
+    ExDeleteResourceLite( &Vcb->FileResource );
+
+    //
+    //  Delete the TOC if present.
+    //
+
+    if (Vcb->CdromToc != NULL) {
+
+        CdFreePool( &Vcb->CdromToc );
+    }
+
+    //
+    //  Uninitialize the notify structures.
+    //
+
+    if (Vcb->NotifySync != NULL) {
+
+        FsRtlNotifyUninitializeSync( &Vcb->NotifySync );
+    }
+
+    //
+    //  Now delete the volume device object.
+    //
+
+    IoDeleteDevice( (PDEVICE_OBJECT) CONTAINING_RECORD( Vcb,
+                                                        VOLUME_DEVICE_OBJECT,
+                                                        Vcb ));
+
+    return;
+}
+
+\f
+PFCB
+CdCreateFcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN FILE_ID FileId,
+    IN NODE_TYPE_CODE NodeTypeCode,
+    OUT PBOOLEAN FcbExisted OPTIONAL
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to find the Fcb for the given FileId.  We will
+    look this up first in the Fcb table and if not found we will create
+    an Fcb.  We don't initialize it or insert it into the FcbTable in this
+    routine.
+
+    This routine is called while the Vcb is locked.
+
+Arguments:
+
+    FileId - This is the Id for the target Fcb.
+
+    NodeTypeCode - Node type for this Fcb if we need to create.
+
+    FcbExisted - If specified, we store whether the Fcb existed.
+
+Return Value:
+
+    PFCB - The Fcb found in the table or created if needed.
+
+--*/
+
+{
+    PFCB NewFcb;
+    BOOLEAN LocalFcbExisted;
+
+    PAGED_CODE();
+
+    //
+    //  Use the local boolean if one was not passed in.
+    //
+
+    if (!ARGUMENT_PRESENT( FcbExisted )) {
+
+        FcbExisted = &LocalFcbExisted;
+    }
+
+    //
+    //  Maybe this is already in the table.
+    //
+
+    NewFcb = CdLookupFcbTable( IrpContext, IrpContext->Vcb, FileId );
+
+    //
+    //  If not then create the Fcb is requested by our caller.
+    //
+
+    if (NewFcb == NULL) {
+
+        //
+        //  Allocate and initialize the structure depending on the
+        //  type code.
+        //
+
+        switch (NodeTypeCode) {
+
+        case CDFS_NTC_FCB_PATH_TABLE:
+        case CDFS_NTC_FCB_INDEX:
+
+            NewFcb = CdAllocateFcbIndex( IrpContext );
+
+            RtlZeroMemory( NewFcb, SIZEOF_FCB_INDEX );
+
+            NewFcb->NodeByteSize = SIZEOF_FCB_INDEX;
+
+            InitializeListHead( &NewFcb->FcbQueue );
+
+            break;
+
+        case CDFS_NTC_FCB_DATA :
+
+            NewFcb = CdAllocateFcbData( IrpContext );
+
+            RtlZeroMemory( NewFcb, SIZEOF_FCB_DATA );
+
+            NewFcb->NodeByteSize = SIZEOF_FCB_DATA;
+
+            break;
+
+        default:
+
+            CdBugCheck( 0, 0, 0 );
+        }
+
+        //
+        //  Now do the common initialization.
+        //
+
+        NewFcb->NodeTypeCode = NodeTypeCode;
+
+        NewFcb->Vcb = IrpContext->Vcb;
+        NewFcb->FileId = FileId;
+
+        CdInitializeMcb( IrpContext, NewFcb );
+
+        //
+        //  Now create the non-paged section object.
+        //
+
+        NewFcb->FcbNonpaged = CdCreateFcbNonpaged( IrpContext );
+
+        //
+        //  Deallocate the Fcb and raise if the allocation failed.
+        //
+
+        if (NewFcb->FcbNonpaged == NULL) {
+
+            CdFreePool( &NewFcb );
+
+            CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
+        }
+
+        *FcbExisted = FALSE;
+
+        //
+        //  Initialize Advanced FCB Header fields
+        //
+
+        ExInitializeFastMutex( &NewFcb->FcbNonpaged->AdvancedFcbHeaderMutex );
+        FsRtlSetupAdvancedHeader( &NewFcb->Header, 
+                                  &NewFcb->FcbNonpaged->AdvancedFcbHeaderMutex );
+    } else {
+
+        *FcbExisted = TRUE;
+    }
+
+    return NewFcb;
+}
+
+\f
+VOID
+CdInitializeFcbFromPathEntry (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PFCB ParentFcb OPTIONAL,
+    IN PPATH_ENTRY PathEntry
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to initialize an Fcb for a directory from
+    the path entry.  Since we only have a starting point for the directory,
+    not the length, we can only speculate on the sizes.
+
+    The general initialization is performed in CdCreateFcb.
+
+Arguments:
+
+    Fcb - Newly created Fcb for this stream.
+
+    ParentFcb - Parent Fcb for this stream.  It may not be present.
+
+    PathEntry - PathEntry for this Fcb in the Path Table.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  Fill in the Index specific fields of the Fcb.
+    //
+
+    Fcb->StreamOffset = BytesFromBlocks( Fcb->Vcb,
+                                         SectorBlockOffset( Fcb->Vcb, PathEntry->DiskOffset ));
+
+    Fcb->Ordinal = PathEntry->Ordinal;
+
+    //
+    //  Initialize the common header in the Fcb.  The node type is already
+    //  present.
+    //
+
+    Fcb->Resource = &Fcb->Vcb->FileResource;
+
+    //
+    //  Always set the sizes to one sector until we read the self-entry.
+    //
+
+    Fcb->AllocationSize.QuadPart =
+    Fcb->FileSize.QuadPart =
+    Fcb->ValidDataLength.QuadPart = SECTOR_SIZE;
+
+    CdAddInitialAllocation( IrpContext,
+                            Fcb,
+                            PathEntry->DiskOffset,
+                            SECTOR_SIZE );
+    //
+    //  State flags for this Fcb.
+    //
+
+    SetFlag( Fcb->FileAttributes,
+             FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY );
+
+    //
+    //  Link into the other in-memory structures and into the Fcb table.
+    //
+
+    if (ParentFcb != NULL) {
+
+        Fcb->ParentFcb = ParentFcb;
+
+        InsertTailList( &ParentFcb->FcbQueue, &Fcb->FcbLinks );
+
+        CdIncrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
+    }
+
+    CdInsertFcbTable( IrpContext, Fcb );
+    SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE );
+
+    return;
+}
+
+\f
+VOID
+CdInitializeFcbFromFileContext (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN PFCB ParentFcb,
+    IN PFILE_ENUM_CONTEXT FileContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to initialize an Fcb for a file from
+    the file context.  We have looked up all of the dirents for this
+    stream and have the full file size.  We will load the all of the allocation
+    for the file into the Mcb now.
+
+    The general initialization is performed in CdCreateFcb.
+
+Arguments:
+
+    Fcb - Newly created Fcb for this stream.
+
+    ParentFcb - Parent Fcb for this stream.
+
+    FileContext - FileContext for the file.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PDIRENT ThisDirent = &FileContext->InitialDirent->Dirent;
+    PCOMPOUND_DIRENT CurrentCompoundDirent;
+
+    LONGLONG CurrentFileOffset;
+    ULONG CurrentMcbEntryOffset;
+
+    PAGED_CODE();
+
+    //
+    //  Use a try-finally to facilitate cleanup.
+    //
+
+    CdLockFcb( IrpContext, Fcb );
+
+    try {
+
+        //
+        //  Initialize the common header in the Fcb.  The node type is already
+        //  present.
+        //
+
+        Fcb->Resource = &IrpContext->Vcb->FileResource;
+
+        //
+        //  Allocation occurs in block-sized units.
+        //
+
+        Fcb->FileSize.QuadPart =
+        Fcb->ValidDataLength.QuadPart = FileContext->FileSize;
+
+        Fcb->AllocationSize.QuadPart = LlBlockAlign( Fcb->Vcb, FileContext->FileSize );
+
+        //
+        //  Set the flags from the dirent.  We always start with the read-only bit.
+        //
+
+        SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_READONLY );
+        if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_HIDDEN )) {
+
+            SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
+        }
+
+        //
+        //  Convert the time to NT time.
+        //
+
+        CdConvertCdTimeToNtTime( IrpContext,
+                                 ThisDirent->CdTime,
+                                 (PLARGE_INTEGER) &Fcb->CreationTime );
+
+        //
+        //  Set the flag indicating the type of extent.
+        //
+
+        if (ThisDirent->ExtentType != Form1Data) {
+
+            if (ThisDirent->ExtentType == Mode2Form2Data) {
+
+                SetFlag( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE );
+
+            } else {
+
+                SetFlag( Fcb->FcbState, FCB_STATE_DA_FILE );
+            }
+
+            Fcb->XAAttributes = ThisDirent->XAAttributes;
+            Fcb->XAFileNumber = ThisDirent->XAFileNumber;
+        }
+
+        //
+        //  Read through all of the dirents for the file until we find the last
+        //  and add the allocation into the Mcb.
+        //
+
+        CurrentCompoundDirent = FileContext->InitialDirent;
+        CurrentFileOffset = 0;
+        CurrentMcbEntryOffset = 0;
+
+        while (TRUE) {
+
+            CdAddAllocationFromDirent( IrpContext,
+                                       Fcb,
+                                       CurrentMcbEntryOffset,
+                                       CurrentFileOffset,
+                                       &CurrentCompoundDirent->Dirent );
+
+            //
+            //  Break out if we are at the last dirent.
+            //
+
+            if (!FlagOn( CurrentCompoundDirent->Dirent.DirentFlags, CD_ATTRIBUTE_MULTI )) {
+
+                break;
+            }
+
+            CurrentFileOffset += CurrentCompoundDirent->Dirent.DataLength;
+            CurrentMcbEntryOffset += 1;
+
+            //
+            //  We better be able to find the next dirent.
+            //
+
+            if (!CdLookupNextDirent( IrpContext,
+                                     ParentFcb,
+                                     &CurrentCompoundDirent->DirContext,
+                                     &FileContext->CurrentDirent->DirContext )) {
+
+                CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
+            }
+
+            CurrentCompoundDirent = FileContext->CurrentDirent;
+
+            CdUpdateDirentFromRawDirent( IrpContext,
+                                         ParentFcb,
+                                         &CurrentCompoundDirent->DirContext,
+                                         &CurrentCompoundDirent->Dirent );
+        }
+
+        //
+        //  Show that the Fcb is initialized.
+        //
+
+        SetFlag( Fcb->FcbState, FCB_STATE_INITIALIZED );
+
+        //
+        //  Link into the other in-memory structures and into the Fcb table.
+        //
+
+        Fcb->ParentFcb = ParentFcb;
+
+        InsertTailList( &ParentFcb->FcbQueue, &Fcb->FcbLinks );
+
+        CdIncrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
+
+        CdInsertFcbTable( IrpContext, Fcb );
+        SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE );
+
+    } finally {
+
+        CdUnlockFcb( IrpContext, Fcb );
+    }
+
+    return;
+}
+
+\f
+PCCB
+CdCreateCcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb,
+    IN ULONG Flags
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to allocate and initialize the Ccb structure.
+
+Arguments:
+
+    Fcb - This is the Fcb for the file being opened.
+
+    Flags - User flags to set in this Ccb.
+
+Return Value:
+
+    PCCB - Pointer to the created Ccb.
+
+--*/
+
+{
+    PCCB NewCcb;
+    PAGED_CODE();
+
+    //
+    //  Allocate and initialize the structure.
+    //
+
+    NewCcb = CdAllocateCcb( IrpContext );
+
+    RtlZeroMemory( NewCcb, sizeof( CCB ));
+
+    //
+    //  Set the proper node type code and node byte size
+    //
+
+    NewCcb->NodeTypeCode = CDFS_NTC_CCB;
+    NewCcb->NodeByteSize = sizeof( CCB );
+
+    //
+    //  Set the initial value for the flags and Fcb
+    //
+
+    NewCcb->Flags = Flags;
+    NewCcb->Fcb = Fcb;
+
+    return NewCcb;
+}
+
+\f
+VOID
+CdDeleteCcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCCB Ccb
+    )
+/*++
+
+Routine Description:
+
+    This routine is called to cleanup and deallocate a Ccb structure.
+
+Arguments:
+
+    Ccb - This is the Ccb to delete.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    if (Ccb->SearchExpression.FileName.Buffer != NULL) {
+
+        CdFreePool( &Ccb->SearchExpression.FileName.Buffer );
+    }
+
+    CdDeallocateCcb( IrpContext, Ccb );
+    return;
+}
+
+\f
+BOOLEAN
+CdCreateFileLock (
+    IN PIRP_CONTEXT IrpContext OPTIONAL,
+    IN PFCB Fcb,
+    IN BOOLEAN RaiseOnError
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called when we want to attach a file lock structure to the
+    given Fcb.  It is possible the file lock is already attached.
+
+    This routine is sometimes called from the fast path and sometimes in the
+    Irp-based path.  We don't want to raise in the fast path, just return FALSE.
+
+Arguments:
+
+    Fcb - This is the Fcb to create the file lock for.
+
+    RaiseOnError - If TRUE, we will raise on an allocation failure.  Otherwise we
+        return FALSE on an allocation failure.
+
+Return Value:
+
+    BOOLEAN - TRUE if the Fcb has a filelock, FALSE otherwise.
+
+--*/
+
+{
+    BOOLEAN Result = TRUE;
+    PFILE_LOCK FileLock;
+
+    PAGED_CODE();
+
+    //
+    //  Lock the Fcb and check if there is really any work to do.
+    //
+
+    CdLockFcb( IrpContext, Fcb );
+
+    if (Fcb->FileLock != NULL) {
+
+        CdUnlockFcb( IrpContext, Fcb );
+        return TRUE;
+    }
+
+    Fcb->FileLock = FileLock =
+        FsRtlAllocateFileLock( NULL, NULL );
+
+    CdUnlockFcb( IrpContext, Fcb );
+
+    //
+    //  Return or raise as appropriate.
+    //
+
+    if (FileLock == NULL) {
+         
+        if (RaiseOnError) {
+
+            ASSERT( ARGUMENT_PRESENT( IrpContext ));
+
+            CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
+        }
+
+        Result = FALSE;
+    }
+
+    return Result;
+}
+
+\f
+PIRP_CONTEXT
+CdCreateIrpContext (
+    IN PIRP Irp,
+    IN BOOLEAN Wait
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to initialize an IrpContext for the current
+    CDFS request.  We allocate the structure and then initialize it from
+    the given Irp.
+
+Arguments:
+
+    Irp - Irp for this request.
+
+    Wait - TRUE if this request is synchronous, FALSE otherwise.
+
+Return Value:
+
+    PIRP_CONTEXT - Allocated IrpContext.
+
+--*/
+
+{
+    PIRP_CONTEXT NewIrpContext = NULL;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    PAGED_CODE();
+
+    //
+    //  The only operations a filesystem device object should ever receive
+    //  are create/teardown of fsdo handles and operations which do not
+    //  occur in the context of fileobjects (i.e., mount).
+    //
+
+    if (IrpSp->DeviceObject == CdData.FileSystemDeviceObject) {
+
+        if (IrpSp->FileObject != NULL &&
+            IrpSp->MajorFunction != IRP_MJ_CREATE &&
+            IrpSp->MajorFunction != IRP_MJ_CLEANUP &&
+            IrpSp->MajorFunction != IRP_MJ_CLOSE) {
+
+            ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST );
+        }
+
+        ASSERT( IrpSp->FileObject != NULL ||
+                
+                (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
+                 IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
+                 IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES) ||
+                
+                (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
+                 IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) ||
+
+                IrpSp->MajorFunction == IRP_MJ_SHUTDOWN );
+    }
+
+    //
+    //  Look in our lookaside list for an IrpContext.
+    //
+
+    if (CdData.IrpContextDepth) {
+
+        CdLockCdData();
+        NewIrpContext = (PIRP_CONTEXT) PopEntryList( &CdData.IrpContextList );
+        if (NewIrpContext != NULL) {
+
+            CdData.IrpContextDepth--;
+        }
+
+        CdUnlockCdData();
+    }
+
+    if (NewIrpContext == NULL) {
+
+        //
+        //  We didn't get it from our private list so allocate it from pool.
+        //
+
+        NewIrpContext = FsRtlAllocatePoolWithTag( NonPagedPool, sizeof( IRP_CONTEXT ), TAG_IRP_CONTEXT );
+    }
+
+    RtlZeroMemory( NewIrpContext, sizeof( IRP_CONTEXT ));
+
+    //
+    //  Set the proper node type code and node byte size
+    //
+
+    NewIrpContext->NodeTypeCode = CDFS_NTC_IRP_CONTEXT;
+    NewIrpContext->NodeByteSize = sizeof( IRP_CONTEXT );
+
+    //
+    //  Set the originating Irp field
+    //
+
+    NewIrpContext->Irp = Irp;
+
+    //
+    //  Copy RealDevice for workque algorithms.  We will update this in the Mount or
+    //  Verify since they have no file objects to use here.
+    //
+
+    if (IrpSp->FileObject != NULL) {
+
+        NewIrpContext->RealDevice = IrpSp->FileObject->DeviceObject;
+    }
+
+    //
+    //  Locate the volume device object and Vcb that we are trying to access.
+    //  This may be our filesystem device object.  In that case don't initialize
+    //  the Vcb field.
+    //
+
+    if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject) {
+
+        NewIrpContext->Vcb =  &((PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject)->Vcb;
+    
+    }
+
+    //
+    //  Major/Minor Function codes
+    //
+
+    NewIrpContext->MajorFunction = IrpSp->MajorFunction;
+    NewIrpContext->MinorFunction = IrpSp->MinorFunction;
+
+    //
+    //  Set the wait parameter
+    //
+
+    if (Wait) {
+
+        SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
+
+    } else {
+
+        SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
+    }
+
+    //
+    //  return and tell the caller
+    //
+
+    return NewIrpContext;
+}
+
+\f
+VOID
+CdCleanupIrpContext (
+    IN PIRP_CONTEXT IrpContext,
+    IN BOOLEAN Post
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to cleanup and possibly deallocate the Irp Context.
+    If the request is being posted or this Irp Context is possibly on the
+    stack then we only cleanup any auxilary structures.
+
+Arguments:
+
+    Post - TRUE if we are posting this request, FALSE if we are deleting
+        or retrying this in the current thread.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  If we aren't doing more processing then deallocate this as appropriate.
+    //
+
+    if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING)) {
+
+        //
+        //  If this context is the top level CDFS context then we need to
+        //  restore the top level thread context.
+        //
+
+        if (IrpContext->ThreadContext != NULL) {
+
+            CdRestoreThreadContext( IrpContext );
+        }
+
+        //
+        //  Deallocate the Io context if allocated.
+        //
+
+        if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
+
+            CdFreeIoContext( IrpContext->IoContext );
+        }
+
+        //
+        //  Deallocate the IrpContext if not from the stack.
+        //
+
+        if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK )) {
+
+            if (CdData.IrpContextDepth < CdData.IrpContextMaxDepth) {
+
+                CdLockCdData();
+
+                PushEntryList( &CdData.IrpContextList, (PSINGLE_LIST_ENTRY) IrpContext );
+                CdData.IrpContextDepth++;
+
+                CdUnlockCdData();
+
+            } else {
+
+                //
+                //  We couldn't add this to our lookaside list so free it to
+                //  pool.
+                //
+
+                CdFreePool( &IrpContext );
+            }
+        }
+
+    //
+    //  Clear the appropriate flags.
+    //
+
+    } else if (Post) {
+
+        //
+        //  If this context is the top level CDFS context then we need to
+        //  restore the top level thread context.
+        //
+
+        if (IrpContext->ThreadContext != NULL) {
+
+            CdRestoreThreadContext( IrpContext );
+        }
+
+        ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_POST );
+
+    } else {
+
+        ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY );
+    }
+
+    return;
+}
+
+\f
+VOID
+CdInitializeStackIrpContext (
+    OUT PIRP_CONTEXT IrpContext,
+    IN PIRP_CONTEXT_LITE IrpContextLite
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to initialize an IrpContext for the current
+    CDFS request.  The IrpContext is on the stack and we need to initialize
+    it for the current request.  The request is a close operation.
+
+Arguments:
+
+    IrpContext - IrpContext to initialize.
+
+    IrpContextLite - Structure containing the details of this request.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    //
+    //  Zero and then initialize the structure.
+    //
+
+    RtlZeroMemory( IrpContext, sizeof( IRP_CONTEXT ));
+
+    //
+    //  Set the proper node type code and node byte size
+    //
+
+    IrpContext->NodeTypeCode = CDFS_NTC_IRP_CONTEXT;
+    IrpContext->NodeByteSize = sizeof( IRP_CONTEXT );
+
+    //
+    //  Note that this is from the stack.
+    //
+
+    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK );
+
+    //
+    //  Copy RealDevice for workque algorithms.
+    //
+
+    IrpContext->RealDevice = IrpContextLite->RealDevice;
+
+    //
+    //  The Vcb is found in the Fcb.
+    //
+
+    IrpContext->Vcb = IrpContextLite->Fcb->Vcb;
+
+    //
+    //  Major/Minor Function codes
+    //
+
+    IrpContext->MajorFunction = IRP_MJ_CLOSE;
+
+    //
+    //  Set the wait parameter
+    //
+
+    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
+
+    return;
+}
+
+\f
+VOID
+CdTeardownStructures (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB StartingFcb,
+    OUT PBOOLEAN RemovedStartingFcb
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is used to walk from some starting point in the Fcb tree towards
+    the root.  It will remove the Fcb and continue walking up the tree until
+    it finds a point where we can't remove an Fcb.
+
+    We look at the following fields in the Fcb to determine whether we can
+    remove this.
+
+        1 - Handle count must be zero.
+        2 - If directory then only the only reference can be for a stream file.
+        3 - Reference count must either be zero or go to zero here.
+
+    We return immediately if we are recursively entering this routine.
+
+Arguments:
+
+    StartingFcb - This is the Fcb node in the tree to begin with.  This Fcb
+        must currently be acquired exclusively.
+
+    RemovedStartingFcb - Address to store whether we removed the starting Fcb.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PVCB Vcb = StartingFcb->Vcb;
+    PFCB CurrentFcb = StartingFcb;
+    BOOLEAN AcquiredCurrentFcb = FALSE;
+    PFCB ParentFcb;
+
+    PAGED_CODE();
+
+    *RemovedStartingFcb = FALSE;
+
+    //
+    //  If this is a recursive call to TearDownStructures we return immediately
+    //  doing no operation.
+    //
+
+    if (FlagOn( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN )) {
+
+        return;
+    }
+
+    SetFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN );
+
+    //
+    //  Use a try-finally to safely clear the top-level field.
+    //
+
+    try {
+
+        //
+        //  Loop until we find an Fcb we can't remove.
+        //
+
+        do {
+
+            //
+            //  See if there is an internal stream we should delete.
+            //  Only do this if it is the last reference on the Fcb.
+            //
+
+            if ((SafeNodeType( CurrentFcb ) != CDFS_NTC_FCB_DATA) &&
+                (CurrentFcb->FcbUserReference == 0) &&
+                (CurrentFcb->FileObject != NULL)) {
+
+                //
+                //  Go ahead and delete the stream file object.
+                //
+
+                CdDeleteInternalStream( IrpContext, CurrentFcb );
+            }
+
+            //
+            //  If the reference count is non-zero then break.
+            //
+
+            if (CurrentFcb->FcbReference != 0) {
+
+                break;
+            }
+
+            //
+            //  It looks like we have a candidate for removal here.  We
+            //  will need to acquire the parent, if present, in order to
+            //  remove this from the parent prefix table.
+            //
+
+            ParentFcb = CurrentFcb->ParentFcb;
+
+            if (ParentFcb != NULL) {
+
+                CdAcquireFcbExclusive( IrpContext, ParentFcb, FALSE );
+            }
+
+            //
+            //  Now lock the vcb.
+            //
+
+            CdLockVcb( IrpContext, Vcb );
+
+            //
+            //  Final check to see if the reference count is still zero.
+            //
+
+            if (CurrentFcb->FcbReference != 0) {
+
+                CdUnlockVcb( IrpContext, Vcb );
+
+                if (ParentFcb != NULL) {
+
+                    CdReleaseFcb( IrpContext, ParentFcb );
+                }
+
+                break;
+            }
+
+            //
+            //  If there is a parent then do the necessary cleanup for the parent.
+            //
+
+            if (ParentFcb != NULL) {
+
+                CdRemovePrefix( IrpContext, CurrentFcb );
+                RemoveEntryList( &CurrentFcb->FcbLinks );
+
+                CdDecrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
+            }
+
+            if (FlagOn( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE )) {
+
+                CdDeleteFcbTable( IrpContext, CurrentFcb );
+                ClearFlag( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE );
+
+            }
+
+            //
+            //  Unlock the Vcb but hold the parent in order to walk up
+            //  the tree.
+            //
+
+            CdUnlockVcb( IrpContext, Vcb );
+            CdDeleteFcb( IrpContext, CurrentFcb );
+
+            //
+            //  Move to the parent Fcb.
+            //
+
+            CurrentFcb = ParentFcb;
+            AcquiredCurrentFcb = TRUE;
+
+        } while (CurrentFcb != NULL);
+
+    } finally {
+
+        //
+        //  Release the current Fcb if we have acquired it.
+        //
+
+        if (AcquiredCurrentFcb && (CurrentFcb != NULL)) {
+
+            CdReleaseFcb( IrpContext, CurrentFcb );
+        }
+
+        //
+        //  Clear the teardown flag.
+        //
+
+        ClearFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN );
+    }
+
+    *RemovedStartingFcb = (CurrentFcb != StartingFcb);
+    return;
+}
+
+\f
+PFCB
+CdLookupFcbTable (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN FILE_ID FileId
+    )
+
+/*++
+
+Routine Description:
+
+    This routine will look through the Fcb table looking for a matching
+    entry.
+
+Arguments:
+
+    Vcb - Vcb for this volume.
+
+    FileId - This is the key value to use for the search.
+
+Return Value:
+
+    PFCB - A pointer to the matching entry or NULL otherwise.
+
+--*/
+
+{
+    FCB_TABLE_ELEMENT Key;
+    PFCB_TABLE_ELEMENT Hit;
+    PFCB ReturnFcb = NULL;
+
+    PAGED_CODE();
+
+    Key.FileId = FileId;
+
+    Hit = (PFCB_TABLE_ELEMENT) RtlLookupElementGenericTable( &Vcb->FcbTable, &Key );
+
+    if (Hit != NULL) {
+
+        ReturnFcb = Hit->Fcb;
+    }
+
+    return ReturnFcb;
+
+    UNREFERENCED_PARAMETER( IrpContext );
+}
+
+\f
+PFCB
+CdGetNextFcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PVCB Vcb,
+    IN PVOID *RestartKey
+    )
+
+/*++
+
+Routine Description:
+
+    This routine will enumerate through all of the Fcb's in the Fcb table.
+
+Arguments:
+
+    Vcb - Vcb for this volume.
+
+    RestartKey - This value is used by the table package to maintain
+        its position in the enumeration.  It is initialized to NULL
+        for the first search.
+
+Return Value:
+
+    PFCB - A pointer to the next fcb or NULL if the enumeration is
+        completed
+
+--*/
+
+{
+    PFCB Fcb;
+
+    PAGED_CODE();
+
+    Fcb = (PFCB) RtlEnumerateGenericTableWithoutSplaying( &Vcb->FcbTable, RestartKey );
+
+    if (Fcb != NULL) {
+
+        Fcb = ((PFCB_TABLE_ELEMENT)(Fcb))->Fcb;
+    }
+
+    return Fcb;
+}
+
+\f
+NTSTATUS
+CdProcessToc (
+    IN PIRP_CONTEXT IrpContext,
+    IN PDEVICE_OBJECT TargetDeviceObject,
+    IN PCDROM_TOC CdromToc,
+    IN OUT PULONG Length,
+    OUT PULONG TrackCount,
+    OUT PULONG DiskFlags
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to verify and process the TOC for this disk.
+    We hide a data track for a CD+ volume.
+
+Arguments:
+
+    TargetDeviceObject - Device object to send TOC request to.
+
+    CdromToc - Pointer to TOC structure.
+
+    Length - On input this is the length of the TOC.  On return is the TOC
+        length we will show to the user.
+
+    TrackCount - This is the count of tracks for the TOC.  We use this
+        when creating a pseudo directory for a music disk.
+
+    DiskFlags - We return flags indicating what we know about this disk.
+
+Return Value:
+
+    NTSTATUS - The result of trying to read the TOC.
+
+--*/
+
+{
+    NTSTATUS Status;
+    IO_STATUS_BLOCK Iosb;
+
+    ULONG CurrentTrack;
+    ULONG LocalTrackCount;
+    ULONG LocalTocLength;
+
+    union {
+
+        UCHAR BigEndian[2];
+        USHORT Length;
+
+    } BiasedTocLength;
+
+    PTRACK_DATA Track;
+
+    PAGED_CODE();
+
+    //
+    //  Go ahead and read the table of contents
+    //
+
+    Status = CdPerformDevIoCtrl( IrpContext,
+                                 IOCTL_CDROM_READ_TOC,
+                                 TargetDeviceObject,
+                                 CdromToc,
+                                 sizeof( CDROM_TOC ),
+                                 FALSE,
+                                 TRUE,
+                                 &Iosb );
+
+    //
+    //  Nothing to process if this request fails.
+    //
+
+    if (Status != STATUS_SUCCESS) {
+
+        return Status;
+    }
+
+    //
+    //  Get the number of tracks and stated size of this structure.
+    //
+
+    CurrentTrack = 0;
+    LocalTrackCount = CdromToc->LastTrack - CdromToc->FirstTrack + 1;
+    LocalTocLength = PtrOffset( CdromToc, &CdromToc->TrackData[LocalTrackCount + 1] );
+
+    //
+    //  Get out if there is an immediate problem with the TOC.
+    //
+
+    if ((LocalTocLength > Iosb.Information) ||
+        (CdromToc->FirstTrack > CdromToc->LastTrack)) {
+
+        Status = STATUS_DISK_CORRUPT_ERROR;
+        return Status;
+    }
+
+    //
+    //  Walk through the individual tracks.  Stop at the first data track after
+    //  any lead-in audio tracks.
+    //
+
+    do {
+
+        //
+        //  Get the next track.
+        //
+
+        Track = &CdromToc->TrackData[CurrentTrack];
+
+        //
+        //  If this is a data track then check if we have only seen audio tracks
+        //  to this point.
+        //
+
+        if (FlagOn( Track->Control, TOC_DATA_TRACK )) {
+
+            //
+            //  If we have only seen audio tracks then assume this is a
+            //  CD+ disk.  Hide the current data track and only return
+            //  the previous audio tracks.  Set the disk type to be mixed
+            //  data/audio.
+            //
+
+            if (FlagOn( *DiskFlags, CDROM_DISK_AUDIO_TRACK ) &&
+                !FlagOn( *DiskFlags, CDROM_DISK_DATA_TRACK )) {
+
+                //
+                //  Remove one track from the TOC.
+                //
+
+                CdromToc->LastTrack -= 1;
+
+                //
+                //  Knock 2.5 minutes off the current track to
+                //  hide the final leadin.
+                //
+
+                Track->Address[1] -= 2;
+                Track->Address[2] += 30;
+
+                if (Track->Address[2] < 60) {
+
+                    Track->Address[1] -= 1;
+
+                } else {
+
+                    Track->Address[2] -= 60;
+                }
+
+                Track->TrackNumber = TOC_LAST_TRACK;
+
+                //
+                //  Set the disk type to mixed data/audio.
+                //
+
+                SetFlag( *DiskFlags, CDROM_DISK_DATA_TRACK );
+
+                break;
+            }
+
+            //
+            //  Set the flag to indicate data tracks present.
+            //
+
+            SetFlag( *DiskFlags, CDROM_DISK_DATA_TRACK );
+
+        //
+        //  If this is a audio track then set the flag indicating audio
+        //  tracks.
+        //
+
+        } else {
+
+            SetFlag( *DiskFlags, CDROM_DISK_AUDIO_TRACK );
+        }
+
+        //
+        //  Set our index for the next track.
+        //
+
+        CurrentTrack += 1;
+
+    } while (CurrentTrack < LocalTrackCount);
+
+    //
+    //  Set the length to point just past the last track we looked at.
+    //
+
+    *TrackCount = CurrentTrack;
+    *Length = PtrOffset( CdromToc, &CdromToc->TrackData[CurrentTrack + 1] );
+    BiasedTocLength.Length = (USHORT) *Length - 2;
+
+    CdromToc->Length[0] = BiasedTocLength.BigEndian[1];
+    CdromToc->Length[1] = BiasedTocLength.BigEndian[0];
+
+    return Status;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdDeleteFcb (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB Fcb
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to cleanup and deallocate an Fcb.  We know there
+    are no references remaining.  We cleanup any auxilary structures and
+    deallocate this Fcb.
+
+Arguments:
+
+    Fcb - This is the Fcb to deallcoate.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PVCB Vcb = NULL;
+    PAGED_CODE();
+
+    //
+    //  Sanity check the counts.
+    //
+
+    ASSERT( Fcb->FcbCleanup == 0 );
+    ASSERT( Fcb->FcbReference == 0 );
+
+    //
+    //  Release any Filter Context structures associated with this FCB
+    //
+
+    FsRtlTeardownPerStreamContexts( &Fcb->Header );
+
+    //
+    //  Start with the common structures.
+    //
+
+    CdUninitializeMcb( IrpContext, Fcb );
+
+    CdDeleteFcbNonpaged( IrpContext, Fcb->FcbNonpaged );
+
+    //
+    //  Check if we need to deallocate the prefix name buffer.
+    //
+
+    if ((Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != (PWCHAR) Fcb->FileNamePrefix.FileNameBuffer) &&
+        (Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != NULL)) {
+
+        CdFreePool( &Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer );
+    }
+
+    //
+    //  Now look at the short name prefix.
+    //
+
+    if (Fcb->ShortNamePrefix != NULL) {
+
+        CdFreePool( &Fcb->ShortNamePrefix );
+    }
+
+    //
+    //  Now do the type specific structures.
+    //
+
+    switch (Fcb->NodeTypeCode) {
+
+    case CDFS_NTC_FCB_PATH_TABLE:
+    case CDFS_NTC_FCB_INDEX:
+
+        ASSERT( Fcb->FileObject == NULL );
+        ASSERT( IsListEmpty( &Fcb->FcbQueue ));
+
+        if (Fcb == Fcb->Vcb->RootIndexFcb) {
+
+            Vcb = Fcb->Vcb;
+            Vcb->RootIndexFcb = NULL;
+
+        } else if (Fcb == Fcb->Vcb->PathTableFcb) {
+
+            Vcb = Fcb->Vcb;
+            Vcb->PathTableFcb = NULL;
+        }
+
+        CdDeallocateFcbIndex( IrpContext, Fcb );
+        break;
+
+    case CDFS_NTC_FCB_DATA :
+
+        if (Fcb->FileLock != NULL) {
+
+            FsRtlFreeFileLock( Fcb->FileLock );
+        }
+
+        FsRtlUninitializeOplock( &Fcb->Oplock );
+
+        if (Fcb == Fcb->Vcb->VolumeDasdFcb) {
+
+            Vcb = Fcb->Vcb;
+            Vcb->VolumeDasdFcb = NULL;
+        }
+
+        CdDeallocateFcbData( IrpContext, Fcb );
+    }
+
+    //
+    //  Decrement the Vcb reference count if this is a system
+    //  Fcb.
+    //
+
+    if (Vcb != NULL) {
+
+        InterlockedDecrement( &Vcb->VcbReference );
+        InterlockedDecrement( &Vcb->VcbUserReference );
+    }
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+PFCB_NONPAGED
+CdCreateFcbNonpaged (
+    IN PIRP_CONTEXT IrpContext
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to create and initialize the non-paged portion
+    of an Fcb.
+
+Arguments:
+
+Return Value:
+
+    PFCB_NONPAGED - Pointer to the created nonpaged Fcb.  NULL if not created.
+
+--*/
+
+{
+    PFCB_NONPAGED FcbNonpaged;
+
+    PAGED_CODE();
+
+    //
+    //  Allocate the non-paged pool and initialize the various
+    //  synchronization objects.
+    //
+
+    FcbNonpaged = CdAllocateFcbNonpaged( IrpContext );
+
+    if (FcbNonpaged != NULL) {
+
+        RtlZeroMemory( FcbNonpaged, sizeof( FCB_NONPAGED ));
+
+        FcbNonpaged->NodeTypeCode = CDFS_NTC_FCB_NONPAGED;
+        FcbNonpaged->NodeByteSize = sizeof( FCB_NONPAGED );
+
+        ExInitializeResourceLite( &FcbNonpaged->FcbResource );
+        ExInitializeFastMutex( &FcbNonpaged->FcbMutex );
+    }
+
+    return FcbNonpaged;
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdDeleteFcbNonpaged (
+    IN PIRP_CONTEXT IrpContext,
+    IN PFCB_NONPAGED FcbNonpaged
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to cleanup the non-paged portion of an Fcb.
+
+Arguments:
+
+    FcbNonpaged - Structure to clean up.
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PAGED_CODE();
+
+    ExDeleteResourceLite( &FcbNonpaged->FcbResource );
+
+    CdDeallocateFcbNonpaged( IrpContext, FcbNonpaged );
+
+    return;
+}
+
+\f
+//
+//  Local support routine
+//
+
+RTL_GENERIC_COMPARE_RESULTS
+CdFcbTableCompare (
+    IN PRTL_GENERIC_TABLE FcbTable,
+    IN PVOID Fid1,
+    IN PVOID Fid2
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is the Cdfs compare routine called by the generic table package.
+    If will compare the two File Id values and return a comparison result.
+
+Arguments:
+
+    FcbTable - This is the table being searched.
+
+    Fid1 - First key value.
+
+    Fid2 - Second key value.
+
+Return Value:
+
+    RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two
+        input structures
+
+--*/
+
+{
+    FILE_ID Id1, Id2;
+    PAGED_CODE();
+
+    Id1 = *((FILE_ID UNALIGNED *) Fid1);
+    Id2 = *((FILE_ID UNALIGNED *) Fid2);
+
+    if (Id1.QuadPart < Id2.QuadPart) {
+
+        return GenericLessThan;
+
+    } else if (Id1.QuadPart > Id2.QuadPart) {
+
+        return GenericGreaterThan;
+
+    } else {
+
+        return GenericEqual;
+    }
+
+    UNREFERENCED_PARAMETER( FcbTable );
+}
+
+\f
+//
+//  Local support routine
+//
+
+PVOID
+CdAllocateFcbTable (
+    IN PRTL_GENERIC_TABLE FcbTable,
+    IN CLONG ByteSize
+    )
+
+/*++
+
+Routine Description:
+
+    This is a generic table support routine to allocate memory
+
+Arguments:
+
+    FcbTable - Supplies the generic table being used
+
+    ByteSize - Supplies the number of bytes to allocate
+
+Return Value:
+
+    PVOID - Returns a pointer to the allocated data
+
+--*/
+
+{
+    PAGED_CODE();
+
+    return( FsRtlAllocatePoolWithTag( CdPagedPool, ByteSize, TAG_FCB_TABLE ));
+}
+
+\f
+//
+//  Local support routine
+//
+
+VOID
+CdDeallocateFcbTable (
+    IN PRTL_GENERIC_TABLE FcbTable,
+    IN PVOID Buffer
+    )
+
+/*++
+
+Routine Description:
+
+    This is a generic table support routine that deallocates memory
+
+Arguments:
+
+    FcbTable - Supplies the generic table being used
+
+    Buffer - Supplies the buffer being deallocated
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+    PAGED_CODE();
+
+    CdFreePool( &Buffer );
+
+    UNREFERENCED_PARAMETER( FcbTable );
+}
+
+\f
+//
+//  Local support routine
+//
+
+ULONG
+CdTocSerial (
+    IN PIRP_CONTEXT IrpContext,
+    IN PCDROM_TOC CdromToc
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called to generate a serial number for an audio disk.
+    The number is based on the starting positions of the tracks.
+    The following algorithm is used.
+
+    If the number of tracks is <= 2 then initialize the serial number to the
+    leadout block number.
+
+    Then add the starting address of each track (use 0x00mmssff format).
+
+Arguments:
+
+    CdromToc - Valid table of contents to use for track information.
+
+Return Value:
+
+    ULONG - 32 bit serial number based on TOC.
+
+--*/
+
+{
+    ULONG SerialNumber = 0;
+    PTRACK_DATA ThisTrack;
+    PTRACK_DATA LastTrack;
+
+    PAGED_CODE();
+
+    //
+    //  Check if there are two tracks or fewer.
+    //
+
+    LastTrack = &CdromToc->TrackData[ CdromToc->LastTrack - CdromToc->FirstTrack + 1];
+    ThisTrack = &CdromToc->TrackData[0];
+
+    if (CdromToc->LastTrack - CdromToc->FirstTrack <= 1) {
+
+        SerialNumber = (((LastTrack->Address[1] * 60) + LastTrack->Address[2]) * 75) + LastTrack->Address[3];
+
+        SerialNumber -= (((ThisTrack->Address[1] * 60) + ThisTrack->Address[2]) * 75) + ThisTrack->Address[3];
+    }
+
+    //
+    //  Now find the starting offset of each track and add to the serial number.
+    //
+
+    while (ThisTrack != LastTrack) {
+
+        SerialNumber += (ThisTrack->Address[1] << 16);
+        SerialNumber += (ThisTrack->Address[2] << 8);
+        SerialNumber += ThisTrack->Address[3];
+        ThisTrack += 1;
+    }
+
+    return SerialNumber;
+}
+
+
diff --git a/reactos/drivers/filesystems/cdfs_new/verfysup.c b/reactos/drivers/filesystems/cdfs_new/verfysup.c
new file mode 100755 (executable)
index 0000000..612c867
--- /dev/null
@@ -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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
diff --git a/reactos/drivers/filesystems/cdfs_new/volinfo.c b/reactos/drivers/filesystems/cdfs_new/volinfo.c
new file mode 100755 (executable)
index 0000000..e592f98
--- /dev/null
@@ -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
+
+\f
+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;
+}
+
+\f
+//
+//  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;
+}
+
+\f
+//
+//  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;
+}
+
+\f
+//
+//  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;
+}
+
+\f
+//
+//  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;
+}
+
diff --git a/reactos/drivers/filesystems/cdfs_new/wdk_wnet_to_ros.diff b/reactos/drivers/filesystems/cdfs_new/wdk_wnet_to_ros.diff
new file mode 100644 (file)
index 0000000..49e7a3a
--- /dev/null
@@ -0,0 +1,1073 @@
+Index: drivers/filesystems/cdfs_new/deviosup.c
+===================================================================
+--- drivers/filesystems/cdfs_new/deviosup.c    (revision 34615)
++++ drivers/filesystems/cdfs_new/deviosup.c    (working copy)
+@@ -165,6 +165,7 @@
+     );
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdMultiSyncCompletionRoutine (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+@@ -172,6 +173,7 @@
+     );
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdMultiAsyncCompletionRoutine (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+@@ -179,6 +181,7 @@
+     );
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdSingleSyncCompletionRoutine (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+@@ -186,6 +189,7 @@
+     );
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdSingleAsyncCompletionRoutine (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+@@ -2943,6 +2947,7 @@
+ //
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdMultiSyncCompletionRoutine (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+@@ -3029,6 +3034,7 @@
+ //
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdMultiAsyncCompletionRoutine (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+@@ -3066,7 +3072,8 @@
+ {
+     PCD_IO_CONTEXT IoContext = Context;
+-    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
++    /* ReactOS Change: GCC Unused Variable */
++    //PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+     AssertVerifyDeviceIrp( Irp );
+     
+@@ -3148,6 +3155,7 @@
+ //
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdSingleSyncCompletionRoutine (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+@@ -3207,6 +3215,7 @@
+ //
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdSingleAsyncCompletionRoutine (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp,
+@@ -3267,7 +3276,7 @@
+     //  and finally, free the context record.
+     //
+-    CdFreeIoContext( (PCD_IO_CONTEXT) Context );
++    CdFreeIoContext(  Context ); /* ReactOS Change: GCC "error: invalid lvalue in unary '&'" */
+     return STATUS_SUCCESS;
+     UNREFERENCED_PARAMETER( DeviceObject );
+Index: drivers/filesystems/cdfs_new/dirctrl.c
+===================================================================
+--- drivers/filesystems/cdfs_new/dirctrl.c     (revision 34615)
++++ drivers/filesystems/cdfs_new/dirctrl.c     (working copy)
+@@ -209,7 +209,7 @@
+     ULONG BaseLength;
+-    PFILE_BOTH_DIR_INFORMATION DirInfo;
++    PFILE_BOTH_DIR_INFORMATION DirInfo = NULL; /* ReactOS Change: GCC Uninit var */
+     PFILE_NAMES_INFORMATION NamesInfo;
+     PFILE_ID_FULL_DIR_INFORMATION IdFullDirInfo;
+     PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo;
+@@ -579,6 +579,9 @@
+                     NamesInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
+     
+                     break;
++
++                /* ReactOS Change: GCC "enumeration value not handled in switch" */
++                default: break;
+                 }
+                 //
+Index: drivers/filesystems/cdfs_new/create.c
+===================================================================
+--- drivers/filesystems/cdfs_new/create.c      (revision 34615)
++++ drivers/filesystems/cdfs_new/create.c      (working copy)
+@@ -2106,7 +2106,7 @@
+     PFCB NextFcb;
+     PFCB ParentFcb = NULL;
+-    NTSTATUS Status;
++    NTSTATUS Status = STATUS_SUCCESS; /* ReactOS Change: GCC uninitialized variable */
+     PAGED_CODE();
+@@ -2757,8 +2757,8 @@
+                 OplockStatus = FsRtlCheckOplock( &Fcb->Oplock,
+                                                  IrpContext->Irp,
+                                                  IrpContext,
+-                                                 CdOplockComplete,
+-                                                 CdPrePostIrp );
++                                                 (PVOID)CdOplockComplete,   /* ReactOS Change: GCC "assignment from incompatible pointer type" */
++                                                 (PVOID)CdPrePostIrp );   /* ReactOS Change: GCC "assignment from incompatible pointer type" */
+                 if (OplockStatus == STATUS_PENDING) {
+@@ -2789,8 +2789,8 @@
+             OplockStatus = FsRtlCheckOplock( &Fcb->Oplock,
+                                              IrpContext->Irp,
+                                              IrpContext,
+-                                             CdOplockComplete,
+-                                             CdPrePostIrp );
++                                             (PVOID)CdOplockComplete,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
++                                             (PVOID)CdPrePostIrp );/* ReactOS Change: GCC "assignment from incompatible pointer type" */
+             if (OplockStatus == STATUS_PENDING) {
+Index: drivers/filesystems/cdfs_new/devctrl.c
+===================================================================
+--- drivers/filesystems/cdfs_new/devctrl.c     (revision 34615)
++++ drivers/filesystems/cdfs_new/devctrl.c     (working copy)
+@@ -64,7 +64,7 @@
+     PIO_STACK_LOCATION IrpSp;
+     PIO_STACK_LOCATION NextIrpSp;
+-    PVOID TargetBuffer = NULL;
++//    PVOID TargetBuffer = NULL; /* ReactOS Change: GCC unused variable */
+     PAGED_CODE();
+Index: drivers/filesystems/cdfs_new/close.c
+===================================================================
+--- drivers/filesystems/cdfs_new/close.c       (revision 34615)
++++ drivers/filesystems/cdfs_new/close.c       (working copy)
+@@ -77,6 +77,7 @@
+     );
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdCloseWorker (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PVOID Context
+@@ -136,9 +137,9 @@
+     //
+     //  Continue processing until there are no more closes to process.
+     //
++    /* ReactOS Change: "GCC suggest parentheses around assignment used as truth value" */
++    while ((IrpContext = CdRemoveClose( Vcb ))) {
+-    while (IrpContext = CdRemoveClose( Vcb )) {
+-
+         //
+         //  If we don't have an IrpContext then use the one on the stack.
+         //  Initialize it for this request.
+@@ -165,7 +166,7 @@
+             //  Free the IrpContextLite.
+             //
+-            CdFreeIrpContextLite( (PIRP_CONTEXT_LITE) IrpContext );
++            CdFreeIrpContextLite( IrpContext ); /* ReactOS Change: GCC "error: invalid lvalue in unary '&'" */
+             //
+             //  Remember we have the IrpContext from the stack.
+@@ -662,6 +663,7 @@
+ }
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdCloseWorker (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PVOID Context
+Index: drivers/filesystems/cdfs_new/dirsup.c
+===================================================================
+--- drivers/filesystems/cdfs_new/dirsup.c      (revision 34615)
++++ drivers/filesystems/cdfs_new/dirsup.c      (working copy)
+@@ -465,7 +465,7 @@
+     //  Save a pointer to the time stamps.
+     //
+-    Dirent->CdTime = RawDirent->RecordTime;
++    Dirent->CdTime = (PCHAR)RawDirent->RecordTime; /* ReactOS change: GCC "pointer targets in assignment differ in signedness" */
+     //
+     //  Copy the dirent flags.
+@@ -501,7 +501,7 @@
+     }
+     Dirent->FileNameLen = RawDirent->FileIdLen;
+-    Dirent->FileName = RawDirent->FileId;
++    Dirent->FileName = (PCHAR)RawDirent->FileId; /* ReactOS change: GCC "pointer targets in assignment differ in signedness" */
+     //
+     //  If there are any remaining bytes at the end of the dirent then
+@@ -1457,7 +1457,7 @@
+ --*/
+ {
+-    XA_EXTENT_TYPE ExtentType;
++    XA_EXTENT_TYPE ExtentType = 0; /* ReactOS Change: GCC Uninit var */
+     PCOMPOUND_DIRENT CurrentCompoundDirent;
+     PDIRENT CurrentDirent;
+Index: drivers/filesystems/cdfs_new/read.c
+===================================================================
+--- drivers/filesystems/cdfs_new/read.c        (revision 34615)
++++ drivers/filesystems/cdfs_new/read.c        (working copy)
+@@ -79,7 +79,7 @@
+ --*/
+ {
+-    NTSTATUS Status;
++    NTSTATUS Status = STATUS_SUCCESS; /* ReactOS Change: GCC Uninit var */
+     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+     TYPE_OF_OPEN TypeOfOpen;
+@@ -225,8 +225,8 @@
+             Status = FsRtlCheckOplock( &Fcb->Oplock,
+                                        Irp,
+                                        IrpContext,
+-                                       CdOplockComplete,
+-                                       CdPrePostIrp );
++                                       (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
+Index: drivers/filesystems/cdfs_new/volinfo.c
+===================================================================
+--- drivers/filesystems/cdfs_new/volinfo.c     (revision 34615)
++++ drivers/filesystems/cdfs_new/volinfo.c     (working copy)
+@@ -166,8 +166,11 @@
+             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
+         //
+Index: drivers/filesystems/cdfs_new/cdfs.rbuild
+===================================================================
+--- drivers/filesystems/cdfs_new/cdfs.rbuild   (revision 34615)
++++ drivers/filesystems/cdfs_new/cdfs.rbuild   (working copy)
+@@ -1,8 +1,8 @@
+ <?xml version="1.0"?>
+ <!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+-<module name="cdfs_new" type="kernelmodedriver" installbase="system32/drivers" installname="cdfs_new.sys">
++<module name="cdfs" type="kernelmodedriver" installbase="system32/drivers" installname="cdfs.sys">
+       <bootstrap installbase="$(CDOUTPUT)" />
+-      <include base="cdfs_new">.</include>
++      <include base="cdfs">.</include>
+       <library>ntoskrnl</library>
+       <library>hal</library>
+     <file>allocsup.c</file>
+@@ -32,6 +32,5 @@
+     <file>volinfo.c</file>
+     <file>workque.c</file>
+       <file>cdfs.rc</file>
+-    <compilerflag>-fms-extensions</compilerflag>
+       <pch>cdprocs.h</pch>
+ </module>
+Index: drivers/filesystems/cdfs_new/cddata.c
+===================================================================
+--- drivers/filesystems/cdfs_new/cddata.c      (revision 34615)
++++ drivers/filesystems/cdfs_new/cddata.c      (working copy)
+@@ -417,7 +417,6 @@
+     return Status;
+ }
+-
+ #ifdef CD_SANITY
+ VOID
+@@ -481,7 +480,6 @@
+ #endif
+-
+ LONG
+ CdExceptionFilter (
+     IN PIRP_CONTEXT IrpContext,
+@@ -1006,6 +1004,7 @@
\f
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastIoCheckIfPossible (
+     IN PFILE_OBJECT FileObject,
+     IN PLARGE_INTEGER FileOffset,
+Index: drivers/filesystems/cdfs_new/allocsup.c
+===================================================================
+--- drivers/filesystems/cdfs_new/allocsup.c    (revision 34615)
++++ drivers/filesystems/cdfs_new/allocsup.c    (working copy)
+@@ -128,7 +128,7 @@
+ {
+     BOOLEAN FirstPass = TRUE;
+     ULONG McbEntryOffset;
+-    PFCB ParentFcb;
++    PFCB ParentFcb = NULL; /* ReactOS Change: GCC uninitialized variable bug */
+     BOOLEAN CleanupParent = FALSE;
+     BOOLEAN UnlockFcb = FALSE;
+Index: drivers/filesystems/cdfs_new/verfysup.c
+===================================================================
+--- drivers/filesystems/cdfs_new/verfysup.c    (revision 34615)
++++ drivers/filesystems/cdfs_new/verfysup.c    (working copy)
+@@ -431,7 +431,7 @@
+     ULONG MediaChangeCount = 0;
+     BOOLEAN ForceVerify = FALSE;
+     BOOLEAN DevMarkedForVerify;
+-    KIRQL SavedIrql;
++    //KIRQL SavedIrql; /* ReactOS Change: GCC Unused variable */
+     PAGED_CODE();
+@@ -581,6 +581,9 @@
+         CdRaiseStatus( IrpContext, STATUS_FILE_INVALID );
+         break;
++        
++    /* ReactOS Change: GCC "enumeration value not handled in switch" */
++    default: break;
+     }
+ }
+@@ -613,7 +616,7 @@
+ --*/
+ {
+-    NTSTATUS Status = STATUS_SUCCESS;
++    //NTSTATUS Status = STATUS_SUCCESS; /* ReactOS Change: GCC Unused variable */
+     PVCB Vcb = Fcb->Vcb;
+     PDEVICE_OBJECT RealDevice = Vcb->Vpb->RealDevice;
+     PIRP Irp;
+Index: drivers/filesystems/cdfs_new/filobsup.c
+===================================================================
+--- drivers/filesystems/cdfs_new/filobsup.c    (revision 34615)
++++ drivers/filesystems/cdfs_new/filobsup.c    (working copy)
+@@ -105,7 +105,7 @@
+     FileObject->FsContext = Fcb;
+     FileObject->FsContext2 = Ccb;
+-    SetFlag( ((ULONG_PTR) FileObject->FsContext2), TypeOfOpen );
++    SetFlag( (*(PULONG_PTR)&FileObject->FsContext2), TypeOfOpen ); /* ReactOS Change: GCC "invalid lvalue in assignment" */
+     //
+     //  Set the Vpb field in the file object.
+@@ -176,7 +176,7 @@
+         *Fcb = FileObject->FsContext;
+         *Ccb = FileObject->FsContext2;
+-        ClearFlag( (ULONG_PTR) *Ccb, TYPE_OF_OPEN_MASK );
++        ClearFlag( (*(PULONG_PTR)Ccb), TYPE_OF_OPEN_MASK ); /* ReactOS Change: GCC "invalid lvalue in assignment" */
+     }
+     //
+Index: drivers/filesystems/cdfs_new/pathsup.c
+===================================================================
+--- drivers/filesystems/cdfs_new/pathsup.c     (revision 34615)
++++ drivers/filesystems/cdfs_new/pathsup.c     (working copy)
+@@ -764,7 +764,7 @@
+     PathEntry->PathEntryLength = WordAlign( PathEntry->PathEntryLength );
+-    PathEntry->DirName = RawPathEntry->DirId;
++    PathEntry->DirName = (PCHAR)RawPathEntry->DirId; /* ReactOS Change: GCC "assignment makes pointer from integer without a cast" */
+     return TRUE;
+ }
+Index: drivers/filesystems/cdfs_new/cdprocs.h
+===================================================================
+--- drivers/filesystems/cdfs_new/cdprocs.h     (revision 34615)
++++ drivers/filesystems/cdfs_new/cdprocs.h     (working copy)
+@@ -44,28 +44,30 @@
+ //  Here are the different pool tags.
+ //
+-#define TAG_CCB                 'ccdC'      //  Ccb
+-#define TAG_CDROM_TOC           'ctdC'      //  TOC
+-#define TAG_DIRENT_NAME         'nddC'      //  CdName in dirent
+-#define TAG_ENUM_EXPRESSION     'eedC'      //  Search expression for enumeration
+-#define TAG_FCB_DATA            'dfdC'      //  Data Fcb
+-#define TAG_FCB_INDEX           'ifdC'      //  Index Fcb
+-#define TAG_FCB_NONPAGED        'nfdC'      //  Nonpaged Fcb
+-#define TAG_FCB_TABLE           'tfdC'      //  Fcb Table entry
+-#define TAG_FILE_NAME           'nFdC'      //  Filename buffer
+-#define TAG_GEN_SHORT_NAME      'sgdC'      //  Generated short name
+-#define TAG_IO_BUFFER           'fbdC'      //  Temporary IO buffer
+-#define TAG_IO_CONTEXT          'oidC'      //  Io context for async reads
+-#define TAG_IRP_CONTEXT         'cidC'      //  Irp Context
+-#define TAG_IRP_CONTEXT_LITE    'lidC'      //  Irp Context lite
+-#define TAG_MCB_ARRAY           'amdC'      //  Mcb array
+-#define TAG_PATH_ENTRY_NAME     'nPdC'      //  CdName in path entry
+-#define TAG_PREFIX_ENTRY        'epdC'      //  Prefix Entry
+-#define TAG_PREFIX_NAME         'npdC'      //  Prefix Entry name
+-#define TAG_SPANNING_PATH_TABLE 'psdC'      //  Buffer for spanning path table
+-#define TAG_UPCASE_NAME         'nudC'      //  Buffer for upcased name
+-#define TAG_VOL_DESC            'dvdC'      //  Buffer for volume descriptor
+-#define TAG_VPB                 'pvdC'      //  Vpb allocated in filesystem
++/* ReactOS Change: GCC doesn't understand this, use TAG macro */
++#include <reactos/helper.h>
++#define TAG_CCB                 TAG('c','c','d','C')      //  Ccb
++#define TAG_CDROM_TOC           TAG('c','t','d','C')      //  TOC
++#define TAG_DIRENT_NAME         TAG('n','d','d','C')      //  CdName in dirent
++#define TAG_ENUM_EXPRESSION     TAG('e','e','d','C')      //  Search expression for enumeration
++#define TAG_FCB_DATA            TAG('d','f','d','C')      //  Data Fcb
++#define TAG_FCB_INDEX           TAG('i','f','d','C')      //  Index Fcb
++#define TAG_FCB_NONPAGED        TAG('n','f','d','C')      //  Nonpaged Fcb
++#define TAG_FCB_TABLE           TAG('t','f','d','C')      //  Fcb Table entry
++#define TAG_FILE_NAME           TAG('n','F','d','C')      //  Filename buffer
++#define TAG_GEN_SHORT_NAME      TAG('s','g','d','C')      //  Generated short name
++#define TAG_IO_BUFFER           TAG('f','b','d','C')      //  Temporary IO buffer
++#define TAG_IO_CONTEXT          TAG('o','i','d','C')      //  Io context for async reads
++#define TAG_IRP_CONTEXT         TAG('c','i','d','C')      //  Irp Context
++#define TAG_IRP_CONTEXT_LITE    TAG('l','i','d','C')      //  Irp Context lite
++#define TAG_MCB_ARRAY           TAG('a','m','d','C')      //  Mcb array
++#define TAG_PATH_ENTRY_NAME     TAG('n','P','d','C')      //  CdName in path entry
++#define TAG_PREFIX_ENTRY        TAG('e','p','d','C')      //  Prefix Entry
++#define TAG_PREFIX_NAME         TAG('n','p','d','C')      //  Prefix Entry name
++#define TAG_SPANNING_PATH_TABLE TAG('p','s','d','C')      //  Buffer for spanning path table
++#define TAG_UPCASE_NAME         TAG('n','u','d','C')      //  Buffer for upcased name
++#define TAG_VOL_DESC            TAG('d','v','d','C')      //  Buffer for volume descriptor
++#define TAG_VPB                 TAG('p','v','d','C')      //  Vpb allocated in filesystem
+ //
+ //  Tag all of our allocations if tagging is turned on
+@@ -902,33 +904,39 @@
+ }
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdNoopAcquire (
+     IN PVOID Fcb,
+     IN BOOLEAN Wait
+     );
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdNoopRelease (
+     IN PVOID Fcb
+     );
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdAcquireForCache (
+     IN PFCB Fcb,
+     IN BOOLEAN Wait
+     );
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdReleaseFromCache (
+     IN PFCB Fcb
+     );
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdAcquireForCreateSection (
+     IN PFILE_OBJECT FileObject
+     );
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdReleaseForCreateSection (
+     IN PFILE_OBJECT FileObject
+     );
+@@ -1184,8 +1192,8 @@
+ //  Verification support routines.  Contained in verfysup.c
+ //
+-
+-INLINE
++/* ReactOS Change: "LD multiple definition of `_CdOperationIsDasdOpen'" */
++static inline
+ BOOLEAN
+ CdOperationIsDasdOpen(
+     IN PIRP_CONTEXT IrpContext
+@@ -1272,12 +1280,14 @@
+     );
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdPrePostIrp (
+     IN PIRP_CONTEXT IrpContext,
+     IN PIRP Irp
+     );
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdOplockComplete (
+     IN PIRP_CONTEXT IrpContext,
+     IN PIRP Irp
+@@ -1293,7 +1303,9 @@
+ //  otherwise
+ //
+-//#ifndef BooleanFlagOn
++/* ReactOS Change: GCC doesn't understand the comment style */
++/*
++ //#ifndef BooleanFlagOn
+ //#define BooleanFlagOn(F,SF) (    \
+ //    (BOOLEAN)(((F) & (SF)) != 0) \
+ //)
+@@ -1310,6 +1322,7 @@
+ //    (Flags) &= ~(SingleFlag);         \
+ //}
+ //#endif
++*/
+ //
+ //      CAST
+@@ -1598,6 +1611,7 @@
+ //
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastQueryBasicInfo (
+     IN PFILE_OBJECT FileObject,
+     IN BOOLEAN Wait,
+@@ -1607,6 +1621,7 @@
+     );
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastQueryStdInfo (
+     IN PFILE_OBJECT FileObject,
+     IN BOOLEAN Wait,
+@@ -1616,6 +1631,7 @@
+     );
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastLock (
+     IN PFILE_OBJECT FileObject,
+     IN PLARGE_INTEGER FileOffset,
+@@ -1629,6 +1645,7 @@
+     );
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastUnlockSingle (
+     IN PFILE_OBJECT FileObject,
+     IN PLARGE_INTEGER FileOffset,
+@@ -1640,6 +1657,7 @@
+     );
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastUnlockAll (
+     IN PFILE_OBJECT FileObject,
+     PEPROCESS ProcessId,
+@@ -1648,6 +1666,7 @@
+     );
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastUnlockAllByKey (
+     IN PFILE_OBJECT FileObject,
+     PVOID ProcessId,
+@@ -1657,6 +1676,7 @@
+     );
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastIoCheckIfPossible (
+     IN PFILE_OBJECT FileObject,
+     IN PLARGE_INTEGER FileOffset,
+@@ -1669,6 +1689,7 @@
+     );
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastQueryNetworkInfo (
+     IN PFILE_OBJECT FileObject,
+     IN BOOLEAN Wait,
+@@ -1862,17 +1883,26 @@
+ //
+ //      #define try_return(S)  { S; goto try_exit; }
+ //
++/* ReactOS Change: Remove SEH */
++#define try
++#define leave goto exitLabel;
++#define finally  if (0) goto exitLabel; exitLabel:
++#define except(x) while (0)
++#define GetExceptionCode() 0
++#define AbnormalTermination() 0
+-#define try_return(S) { S; goto try_exit; }
+-#define try_leave(S) { S; leave; }
++#define try_return(S) { goto try_exit; }
++#define try_leave(S) { leave; }
++
+ //
+ //  Encapsulate safe pool freeing
+ //
++/* ReactOS Change: GCC "passing argument 1 of CdFreePool from incompatible pointer type" */
++#define CdFreePool(x) _CdFreePool((PVOID*)(x))
+-INLINE
+-VOID
+-CdFreePool(
++/* ReactOS Change: "LD multiple definition of `_CdOperationIsDasdOpen'" */
++static inline void _CdFreePool(
+     IN PVOID *Pool
+     )
+ {
+Index: drivers/filesystems/cdfs_new/resrcsup.c
+===================================================================
+--- drivers/filesystems/cdfs_new/resrcsup.c    (revision 34615)
++++ drivers/filesystems/cdfs_new/resrcsup.c    (working copy)
+@@ -123,6 +123,7 @@
\f
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdAcquireForCache (
+     IN PFCB Fcb,
+     IN BOOLEAN Wait
+@@ -159,6 +160,7 @@
\f
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdReleaseFromCache (
+     IN PFCB Fcb
+     )
+@@ -193,6 +195,7 @@
\f
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdNoopAcquire (
+     IN PVOID Fcb,
+     IN BOOLEAN Wait
+@@ -224,6 +227,7 @@
\f
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdNoopRelease (
+     IN PVOID Fcb
+     )
+@@ -251,6 +255,7 @@
\f
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdAcquireForCreateSection (
+     IN PFILE_OBJECT FileObject
+     )
+@@ -298,6 +303,7 @@
\f
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdReleaseForCreateSection (
+     IN PFILE_OBJECT FileObject
+     )
+Index: drivers/filesystems/cdfs_new/namesup.c
+===================================================================
+--- drivers/filesystems/cdfs_new/namesup.c     (revision 34615)
++++ drivers/filesystems/cdfs_new/namesup.c     (working copy)
+@@ -206,7 +206,7 @@
+ {
+     NTSTATUS Status;
+-    PVOID NewBuffer;
++    //PVOID NewBuffer; /* ReactOS Change: GCC Uninitialized variable */
+     PAGED_CODE();
+Index: drivers/filesystems/cdfs_new/cdinit.c
+===================================================================
+--- drivers/filesystems/cdfs_new/cdinit.c      (revision 34615)
++++ drivers/filesystems/cdfs_new/cdinit.c      (working copy)
+@@ -22,12 +22,14 @@
+ #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
+     );
+@@ -39,6 +41,7 @@
+     );
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdShutdown (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp
+@@ -57,6 +60,7 @@
+ //
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ DriverEntry(
+     IN PDRIVER_OBJECT DriverObject,
+     IN PUNICODE_STRING RegistryPath
+@@ -169,6 +173,7 @@
+ }
+ NTSTATUS
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdShutdown (
+     IN PDEVICE_OBJECT DeviceObject,
+     IN PIRP Irp
+@@ -200,6 +205,7 @@
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdUnload(
+     IN PDRIVER_OBJECT DriverObject
+     )
+@@ -310,10 +316,10 @@
+     //  Initialize the cache manager callback routines
+     //
+-    CdData.CacheManagerCallbacks.AcquireForLazyWrite  = &CdAcquireForCache;
+-    CdData.CacheManagerCallbacks.ReleaseFromLazyWrite = &CdReleaseFromCache;
+-    CdData.CacheManagerCallbacks.AcquireForReadAhead  = &CdAcquireForCache;
+-    CdData.CacheManagerCallbacks.ReleaseFromReadAhead = &CdReleaseFromCache;
++    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;
+Index: drivers/filesystems/cdfs_new/cdstruc.h
+===================================================================
+--- drivers/filesystems/cdfs_new/cdstruc.h     (revision 34615)
++++ drivers/filesystems/cdfs_new/cdstruc.h     (working copy)
+@@ -504,8 +504,8 @@
+     //
+     ULONG VcbCleanup;
+-    ULONG VcbReference;
+-    ULONG VcbUserReference;
++    LONG VcbReference; /* ReactOS Change: GCC 'pointer targets in passing argument 1 of 'InterlockedXxx' differ in signedness */
++    LONG VcbUserReference; /* ReactOS Change: GCC 'pointer targets in passing argument 1 of 'InterlockedXxx' differ in signedness */
+     //
+     //  Fcb for the Volume Dasd file, root directory and the Path Table.
+@@ -655,7 +655,7 @@
+     //  executed later.
+     //
+-    ULONG PostedRequestCount;
++    LONG PostedRequestCount; /* ReactOS Change: GCC "pointer targets in passing argument 1 of 'InterlockedDecrement' differ in signedness" */
+     //
+     //  The following field indicates the number of IRP's waiting
+@@ -878,7 +878,7 @@
+     //
+     ULONG FcbCleanup;
+-    ULONG FcbReference;
++    LONG FcbReference; /* ReactOS Change: GCC 'pointer targets in passing argument 1 of 'InterlockedXxx' differ in signedness */
+     ULONG FcbUserReference;
+     //
+Index: drivers/filesystems/cdfs_new/lockctrl.c
+===================================================================
+--- drivers/filesystems/cdfs_new/lockctrl.c    (revision 34615)
++++ drivers/filesystems/cdfs_new/lockctrl.c    (working copy)
+@@ -89,7 +89,7 @@
+     Status = FsRtlCheckOplock( &Fcb->Oplock,
+                                Irp,
+                                IrpContext,
+-                               CdOplockComplete,
++                               (PVOID)CdOplockComplete,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
+                                NULL );
+     //
+@@ -138,6 +138,7 @@
\f
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastLock (
+     IN PFILE_OBJECT FileObject,
+     IN PLARGE_INTEGER FileOffset,
+@@ -246,8 +247,8 @@
+         //
+         //  Now call the FsRtl routine to perform the lock request.
+         //
+-
+-        if (Results = FsRtlFastLock( Fcb->FileLock,
++        /* ReactOS Change: GCC "suggest parentheses around assignment used as truth value" */
++        if ((Results = FsRtlFastLock( Fcb->FileLock,
+                                      FileObject,
+                                      FileOffset,
+                                      Length,
+@@ -257,7 +258,7 @@
+                                      ExclusiveLock,
+                                      IoStatus,
+                                      NULL,
+-                                     FALSE )) {
++                                     FALSE ))) {
+             //
+             //  Set the flag indicating if Fast I/O is questionable.  We
+@@ -284,6 +285,7 @@
\f
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastUnlockSingle (
+     IN PFILE_OBJECT FileObject,
+     IN PLARGE_INTEGER FileOffset,
+@@ -424,6 +426,7 @@
\f
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastUnlockAll (
+     IN PFILE_OBJECT FileObject,
+     PEPROCESS ProcessId,
+@@ -546,6 +549,7 @@
\f
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastUnlockAllByKey (
+     IN PFILE_OBJECT FileObject,
+     PVOID ProcessId,
+Index: drivers/filesystems/cdfs_new/cleanup.c
+===================================================================
+--- drivers/filesystems/cdfs_new/cleanup.c     (revision 34615)
++++ drivers/filesystems/cdfs_new/cleanup.c     (working copy)
+@@ -159,7 +159,7 @@
+     //  Use a try-finally to facilitate cleanup.
+     //
+-    try {
++    //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.
+@@ -279,7 +279,7 @@
+         IoRemoveShareAccess( FileObject, &Fcb->ShareAccess );
+-    } finally {
++    //} 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 );
+         
+@@ -287,7 +287,7 @@
+             
+             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
+Index: drivers/filesystems/cdfs_new/strucsup.c
+===================================================================
+--- drivers/filesystems/cdfs_new/strucsup.c    (revision 34615)
++++ drivers/filesystems/cdfs_new/strucsup.c    (working copy)
+@@ -438,7 +438,7 @@
+ --*/
+ {
+-    ULONG Shift;
++    //ULONG Shift; /* ReactOS Change: GCC Unused variable */
+     ULONG StartingBlock;
+     ULONG ByteCount;
+Index: drivers/filesystems/cdfs_new/fileinfo.c
+===================================================================
+--- drivers/filesystems/cdfs_new/fileinfo.c    (revision 34615)
++++ drivers/filesystems/cdfs_new/fileinfo.c    (working copy)
+@@ -460,6 +460,7 @@
\f
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastQueryBasicInfo (
+     IN PFILE_OBJECT FileObject,
+     IN BOOLEAN Wait,
+@@ -577,6 +578,7 @@
\f
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastQueryStdInfo (
+     IN PFILE_OBJECT FileObject,
+     IN BOOLEAN Wait,
+@@ -704,6 +706,7 @@
\f
+ BOOLEAN
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdFastQueryNetworkInfo (
+     IN PFILE_OBJECT FileObject,
+     IN BOOLEAN Wait,
+Index: drivers/filesystems/cdfs_new/nodetype.h
+===================================================================
+--- drivers/filesystems/cdfs_new/nodetype.h    (revision 34615)
++++ drivers/filesystems/cdfs_new/nodetype.h    (working copy)
+@@ -97,6 +97,8 @@
+ #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_
+Index: drivers/filesystems/cdfs_new/fsctrl.c
+===================================================================
+--- drivers/filesystems/cdfs_new/fsctrl.c      (revision 34615)
++++ drivers/filesystems/cdfs_new/fsctrl.c      (working copy)
+@@ -82,7 +82,8 @@
+     IN PIRP_CONTEXT IrpContext,
+     IN PIRP Irp
+     );
+-
++    
++NTSTATUS /* ReactOS Change: Function did not have a type??? */
+ CdIsVolumeDirty (
+     IN PIRP_CONTEXT IrpContext,
+     IN PIRP Irp
+@@ -918,7 +919,7 @@
+         if (CdIsRemount( IrpContext, Vcb, &OldVcb )) {
+-            KIRQL SavedIrql;
++            //KIRQL SavedIrql; /* ReactOS Change: GCC Unused variable */
+             ASSERT( NULL != OldVcb->SwapVpb );
+@@ -1374,7 +1375,7 @@
+                         //  Compute the length of the volume name
+                         //
+-                        AnsiLabel.Buffer = CdRvdVolId( RawIsoVd, Vcb->VcbState );
++                        AnsiLabel.Buffer = (PCHAR)CdRvdVolId( RawIsoVd, Vcb->VcbState ); /* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+                         AnsiLabel.MaximumLength = AnsiLabel.Length = VOLUME_ID_LENGTH;
+                         UnicodeLabel.MaximumLength = VOLUME_ID_LENGTH * sizeof( WCHAR );
+@@ -1401,7 +1402,7 @@
+                     } else {
+                         CdConvertBigToLittleEndian( IrpContext,
+-                                                    CdRvdVolId( RawIsoVd, Vcb->VcbState ),
++                                                    (PCHAR)CdRvdVolId( RawIsoVd, Vcb->VcbState ),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+                                                     VOLUME_ID_LENGTH,
+                                                     (PCHAR) VolumeLabel );
+@@ -2005,7 +2006,7 @@
+ //
+ //  Local support routine
+ //
+-
++NTSTATUS /* ReactOS Change: Function did not have a type??? */
+ CdIsVolumeDirty (
+     IN PIRP_CONTEXT IrpContext,
+     IN PIRP Irp
+@@ -2294,9 +2295,9 @@
+     Status = ObReferenceObjectByHandle( Handle,
+                                         0,
+-                                        *IoFileObjectType,
++                                        IoFileObjectType, /* ReactOS Change: GCC/LD Incompatibily with exported kernel data */
+                                         KernelMode,
+-                                        &FileToMarkBad,
++                                        (PVOID*)&FileToMarkBad, /* ReactOS Change: GCC "passing argument 5 of 'ObReferenceObjectByHandle' from incompatible pointer type" */
+                                         NULL );
+     if (!NT_SUCCESS(Status)) {
+@@ -2642,8 +2643,8 @@
+                     //  The track address is BigEndian, we need to flip the bytes.
+                     //
+-                    Source = (PUCHAR) &CdromToc->TrackData[0].Address[3];
+-                    Dest = (PUCHAR) &BaseSector;
++                    Source = (PCHAR) &CdromToc->TrackData[0].Address[3];/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
++                    Dest = (PCHAR) &BaseSector; /* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+                     do {
+@@ -3118,7 +3119,7 @@
+         if (NT_SUCCESS( RtlOemToUnicodeN( &Vcb->Vpb->VolumeLabel[0],
+                                           MAXIMUM_VOLUME_LABEL_LENGTH,
+                                           &Length,
+-                                          CdRvdVolId( RawIsoVd, Vcb->VcbState ),
++                                          (PCHAR)CdRvdVolId( RawIsoVd, Vcb->VcbState ),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+                                           VOLUME_ID_LENGTH ))) {
+             Vcb->Vpb->VolumeLabelLength = (USHORT) Length;
+@@ -3131,7 +3132,7 @@
+     } else {
+         CdConvertBigToLittleEndian( IrpContext,
+-                                    CdRvdVolId( RawIsoVd, Vcb->VcbState ),
++                                    (PCHAR)CdRvdVolId( RawIsoVd, Vcb->VcbState ),/* ReactOS Change: GCC "pointer targets in assignment differ in signedness" */
+                                     VOLUME_ID_LENGTH,
+                                     (PCHAR) Vcb->Vpb->VolumeLabel );
+Index: drivers/filesystems/cdfs_new/workque.c
+===================================================================
+--- drivers/filesystems/cdfs_new/workque.c     (revision 34615)
++++ drivers/filesystems/cdfs_new/workque.c     (working copy)
+@@ -97,6 +97,7 @@
\f
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdPrePostIrp (
+     IN PIRP_CONTEXT IrpContext,
+     IN PIRP Irp
+@@ -209,6 +210,7 @@
\f
+ VOID
++NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+ CdOplockComplete (
+     IN PIRP_CONTEXT IrpContext,
+     IN PIRP Irp
+@@ -386,7 +388,7 @@
+     //
+     ExInitializeWorkItem( &IrpContext->WorkQueueItem,
+-                          CdFspDispatch,
++                          (PVOID)CdFspDispatch,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
+                           IrpContext );
+     ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
diff --git a/reactos/drivers/filesystems/cdfs_new/workque.c b/reactos/drivers/filesystems/cdfs_new/workque.c
new file mode 100755 (executable)
index 0000000..8abc28d
--- /dev/null
@@ -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
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+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;
+}
+
+\f
+//
+//  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;
+}
+
+
+