/*++

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


    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.

// @@BEGIN_DDKSPLIT

Author:

    Brian Andrew    [BrianAn]   01-July-1995

Revision History:

// @@END_DDKSPLIT

--*/

#ifndef _CDSTRUC_
#define _CDSTRUC_

typedef PVOID PBCB;     //**** Bcb's are now part of the cache module

#define BYTE_COUNT_EMBEDDED_NAME        (32)


//
//  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;


//
//  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;


//
//  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)


//
//  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;


//
//  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;
    ULONG VcbReference;
    ULONG VcbUserReference;

    //
    //  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)


//
//  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.
    //

    ULONG PostedRequestCount;

    //
    //  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;


//
//  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;
    ULONG FcbReference;
    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 ))


//
//  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)


//
//  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;

    //
    //  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                 \
)


//
//  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;


//
//  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;


//
//  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;


//
//  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)


//
//  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)


//
//  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;


//
//  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;


//
//  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)


//
//  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;


//
//  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)


//
//  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;

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