/*++

Copyright (c) 1989-2000 Microsoft Corporation

Module Name:

    FatStruc.h

Abstract:

    This module defines the data structures that make up the major internal
    part of the Fat file system.

// @@BEGIN_DDKSPLIT

Author:

    Gary Kimura     [GaryKi]    28-Dec-1989

Revision History:

// @@END_DDKSPLIT

--*/

#ifndef _FATSTRUC_
#define _FATSTRUC_

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


//
//  The FAT_DATA record is the top record in the Fat file system in-memory
//  data structure.  This structure must be allocated from non-paged pool.
//

typedef struct _FAT_DATA {

    //
    //  The type and size of this record (must be FAT_NTC_DATA_HEADER)
    //

    NODE_TYPE_CODE NodeTypeCode;
    NODE_BYTE_SIZE NodeByteSize;


    PVOID LazyWriteThread;


    //
    //  A queue of all the devices that are mounted by the file system.
    //

    LIST_ENTRY VcbQueue;

    //
    //  A pointer to the Driver object we were initialized with
    //

    PDRIVER_OBJECT DriverObject;

    //
    //  A pointer to the filesystem device objects we created.
    //

    PVOID DiskFileSystemDeviceObject;
    PVOID CdromFileSystemDeviceObject;

    //
    //  A resource variable to control access to the global Fat data record
    //

    ERESOURCE Resource;

    //
    //  A pointer to our EPROCESS struct, which is a required input to the
    //  Cache Management subsystem.
    //

    PEPROCESS OurProcess;

    //
    //  The following tells us if we should use Chicago extensions.
    //

    BOOLEAN ChicagoMode:1;

    //
    //  The following field tells us if we are running on a Fujitsu
    //  FMR Series. These machines supports extra formats on the
    //  FAT file system.
    //

    BOOLEAN FujitsuFMR:1;

    //
    //  Inidicates that FspClose is currently processing closes.
    //

    BOOLEAN AsyncCloseActive:1;

    //
    //  The following BOOLEAN says shutdown has started on FAT.  It
    //  instructs FspClose to not keep the Vcb resources anymore.
    //

    BOOLEAN ShutdownStarted:1;

    //
    //  The following flag tells us if we are going to generate LFNs
    //  for valid 8.3 names with extended characters.
    //

    BOOLEAN CodePageInvariant:1;

    //
    //  The following flags tell us if we are in an aggresive push to lower
    //  the size of the deferred close queues.
    //

    BOOLEAN HighAsync:1;
    BOOLEAN HighDelayed:1;

    //
    //  The following list entry is used for performing closes that can't
    //  be done in the context of the original caller.
    //

    ULONG AsyncCloseCount;
    LIST_ENTRY AsyncCloseList;

    //
    //  The following two fields record if we are delaying a close.
    //

    ULONG DelayedCloseCount;
    LIST_ENTRY DelayedCloseList;

    //
    //  This is the ExWorkerItem that does both kinds of deferred closes.
    //

    PIO_WORKITEM FatCloseItem;

    //
    //  This spinlock protects several rapid-fire operations. NOTE: this is
    //  pretty horrible style.
    //

    KSPIN_LOCK GeneralSpinLock;

    //
    //  Cache manager call back structures, which must be passed on each call
    //  to CcInitializeCacheMap.
    //

    CACHE_MANAGER_CALLBACKS CacheManagerCallbacks;
    CACHE_MANAGER_CALLBACKS CacheManagerNoOpCallbacks;

} FAT_DATA;
typedef FAT_DATA *PFAT_DATA;

//
// An array of these structures will keep

typedef struct _FAT_WINDOW {
    
    ULONG FirstCluster;       // The first cluster in this window.
    ULONG LastCluster;        // The last cluster in this window.
    ULONG ClustersFree;       // The number of clusters free in this window.

} FAT_WINDOW;
typedef FAT_WINDOW *PFAT_WINDOW;


//
//  The Vcb (Volume control Block) record corresponds to every volume mounted
//  by the file system.  They are ordered in a queue off of FatData.VcbQueue.
//  This structure must be allocated from non-paged pool
//

typedef enum _VCB_CONDITION {
    VcbGood = 1,
    VcbNotMounted,
    VcbBad
} VCB_CONDITION;

typedef struct _VCB {

    //
    //  This is a common head for the FAT volume file
    //

    FSRTL_ADVANCED_FCB_HEADER VolumeFileHeader;

    //
    //  The links for the device queue off of FatData.VcbQueue
    //

    LIST_ENTRY VcbLinks;

    //
    //  A pointer the device object passed in by the I/O system on a mount
    //  This is the target device object that the file system talks to when it
    //  needs to do any I/O (e.g., the disk stripper device object).
    //
    //

    PDEVICE_OBJECT TargetDeviceObject;

    //
    //  A pointer to the VPB for the volume passed in by the I/O system on
    //  a mount.
    //

    PVPB Vpb;

    //
    //  The internal state of the device.  This is a collection of fsd device
    //  state flags.
    //

    ULONG VcbState;
    VCB_CONDITION VcbCondition;

    //
    //  A pointer to the root DCB for this volume
    //

    struct _FCB *RootDcb;

    //
    //  If the FAT has so many entries that the free cluster bitmap would
    //  be too large, we split the FAT into buckets, and only one bucket's
    //  worth of bits are kept in the bitmap.
    //

    ULONG NumberOfWindows;
    PFAT_WINDOW Windows;
    PFAT_WINDOW CurrentWindow;

    //
    //  A count of the number of file objects that have opened the volume
    //  for direct access, and their share access state.
    //

    CLONG DirectAccessOpenCount;
    SHARE_ACCESS ShareAccess;

    //
    //  A count of the number of file objects that have any file/directory
    //  opened on this volume, not including direct access.  And also the
    //  count of the number of file objects that have a file opened for
    //  only read access (i.e., they cannot be modifying the disk).
    //

    CLONG OpenFileCount;
    CLONG ReadOnlyCount;

    //
    //  The bios parameter block field contains
    //  an unpacked copy of the bpb for the volume, it is initialized
    //  during mount time and can be read by everyone else after that.
    //

    BIOS_PARAMETER_BLOCK Bpb;

    PUCHAR First0x24BytesOfBootSector;

    //
    //  The following structure contains information useful to the
    //  allocation support routines.  Many of them are computed from
    //  elements of the Bpb, but are too involved to recompute every time
    //  they are needed.
    //

    struct {

        LBO RootDirectoryLbo;       // Lbo of beginning of root directory
        LBO FileAreaLbo;            // Lbo of beginning of file area
        ULONG RootDirectorySize;    // size of root directory in bytes

        ULONG NumberOfClusters;     // total number of clusters on the volume
        ULONG NumberOfFreeClusters; // number of free clusters on the volume

        UCHAR FatIndexBitSize;      // indicates if 12, 16, or 32 bit fat table

        UCHAR LogOfBytesPerSector;  // Log(Bios->BytesPerSector)
        UCHAR LogOfBytesPerCluster; // Log(Bios->SectorsPerCluster)

    } AllocationSupport;

    //
    //  The following Mcb is used to keep track of dirty sectors in the Fat.
    //  Runs of holes denote clean sectors while runs of LBO == VBO denote
    //  dirty sectors.  The VBOs are that of the volume file, starting at
    //  0.  The granuality of dirt is one sectors, and additions are only
    //  made in sector chunks to prevent problems with several simultaneous
    //  updaters.
    //

    LARGE_MCB DirtyFatMcb;

    //
    //  The FreeClusterBitMap keeps track of all the clusters in the fat.
    //  A 1 means occupied while a 0 means free.  It allows quick location
    //  of contiguous runs of free clusters.  It is initialized on mount
    //  or verify.
    //

    RTL_BITMAP FreeClusterBitMap;

    //
    //  The following fast mutex controls access to the free cluster bit map
    //  and the buckets.
    //

    FAST_MUTEX FreeClusterBitMapMutex;

    //
    //  A resource variable to control access to the volume specific data
    //  structures
    //

    ERESOURCE Resource;

    //
    //  A resource to make sure no one changes the volume bitmap while
    //  you're using it.  Only for volumes with NumberOfWindows > 1.
    //

    ERESOURCE ChangeBitMapResource;


    //
    //  The following field points to the file object used to do I/O to
    //  the virtual volume file.  The virtual volume file maps sectors
    //  0 through the end of fat and is of a fixed size (determined during
    //  mount)
    //

    PFILE_OBJECT VirtualVolumeFile;

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

    //
    //  The following fields is a hint cluster index used by the file system
    //  when allocating a new cluster.
    //

    ULONG ClusterHint;

    //
    //  This field contains the "DeviceObject" that this volume is
    //  currently mounted on.  Note Vcb->Vpb->RealDevice is constant.
    //

    PDEVICE_OBJECT CurrentDevice;

    //
    //  This is a pointer to the file object and the Fcb which represent the ea data.
    //

    PFILE_OBJECT VirtualEaFile;
    struct _FCB *EaFcb;

    //
    //  The following field is a pointer to the file object that has the
    //  volume locked. if the VcbState has the locked flag set.
    //

    PFILE_OBJECT FileObjectWithVcbLocked;

    //
    //  The following is the head of a list of notify Irps.
    //

    LIST_ENTRY DirNotifyList;

    //
    //  The following is used to synchronize the dir notify list.
    //

    PNOTIFY_SYNC NotifySync;

    //
    //  The following fast mutex is used to synchronize directory stream
    //  file object creation.
    //

    FAST_MUTEX DirectoryFileCreationMutex;

    //
    //  This field holds the thread address of the current (or most recent
    //  depending on VcbState) thread doing a verify operation on this volume.
    //

    PKTHREAD VerifyThread;

    //
    //  The following two structures are used for CleanVolume callbacks.
    //

    KDPC CleanVolumeDpc;
    KTIMER CleanVolumeTimer;

    //
    //  This field records the last time FatMarkVolumeDirty was called, and
    //  avoids excessive calls to push the CleanVolume forward in time.
    //

    LARGE_INTEGER LastFatMarkVolumeDirtyCall;

    //
    //  The following fields holds a pointer to a struct which is used to
    //  hold performance counters.
    //

    struct _FILE_SYSTEM_STATISTICS *Statistics;

    //
    //  The property tunneling cache for this volume
    //

    TUNNEL Tunnel;

    //
    //  The media change count is returned by IOCTL_CHECK_VERIFY and
    //  is used to verify that no user-mode app has swallowed a media change
    //  notification.  This is only meaningful for removable media.
    //

    ULONG ChangeCount;

    //
    //  Preallocated VPB for swapout, so we are not forced to consider
    //  must succeed pool.
    //

    PVPB SwapVpb;

    //
    //  Per volume threading of the close queues.
    //

    LIST_ENTRY AsyncCloseList;
    LIST_ENTRY DelayedCloseList;

    //
    //  Fast mutex used by the ADVANCED FCB HEADER in this structure
    //

    FAST_MUTEX AdvancedFcbHeaderMutex;

} VCB;
typedef VCB *PVCB;

#define VCB_STATE_FLAG_LOCKED              (0x00000001)
#define VCB_STATE_FLAG_REMOVABLE_MEDIA     (0x00000002)
#define VCB_STATE_FLAG_VOLUME_DIRTY        (0x00000004)
#define VCB_STATE_FLAG_MOUNTED_DIRTY       (0x00000010)
#define VCB_STATE_FLAG_SHUTDOWN            (0x00000040)
#define VCB_STATE_FLAG_CLOSE_IN_PROGRESS   (0x00000080)
#define VCB_STATE_FLAG_DELETED_FCB         (0x00000100)
#define VCB_STATE_FLAG_CREATE_IN_PROGRESS  (0x00000200)
#define VCB_STATE_FLAG_BOOT_OR_PAGING_FILE (0x00000800)
#define VCB_STATE_FLAG_DEFERRED_FLUSH      (0x00001000)
#define VCB_STATE_FLAG_ASYNC_CLOSE_ACTIVE  (0x00002000)
#define VCB_STATE_FLAG_WRITE_PROTECTED     (0x00004000)
#define VCB_STATE_FLAG_REMOVAL_PREVENTED   (0x00008000)
#define VCB_STATE_FLAG_VOLUME_DISMOUNTED   (0x00010000)

//
//  N.B - VOLUME_DISMOUNTED is an indication that FSCTL_DISMOUNT volume was
//  executed on a volume. It does not replace VcbCondition as an indication
//  that the volume is invalid/unrecoverable.
//

//
//  Define the file system statistics struct.  Vcb->Statistics points to an
//  array of these (one per processor) and they must be 64 byte aligned to
//  prevent cache line tearing.
//

typedef struct _FILE_SYSTEM_STATISTICS {

        //
        //  This contains the actual data.
        //

        FILESYSTEM_STATISTICS Common;
        FAT_STATISTICS Fat;

        //
        //  Pad this structure to a multiple of 64 bytes.
        //

        UCHAR Pad[64-(sizeof(FILESYSTEM_STATISTICS)+sizeof(FAT_STATISTICS))%64];

} FILE_SYSTEM_STATISTICS;

typedef FILE_SYSTEM_STATISTICS *PFILE_SYSTEM_STATISTICS;


//
//  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 a common head for the FAT volume file
    //

    FSRTL_COMMON_FCB_HEADER VolumeFileHeader;

    //
    //  This is the file system specific volume control block.
    //

    VCB Vcb;

} VOLUME_DEVICE_OBJECT;

typedef VOLUME_DEVICE_OBJECT *PVOLUME_DEVICE_OBJECT;


//
//  This is the structure used to contains the short name for a file
//

typedef struct _FILE_NAME_NODE {

    //
    //  This points back to the Fcb for this file.
    //

    struct _FCB *Fcb;

    //
    //  This is the name of this node.
    //

    union {

        OEM_STRING Oem;

        UNICODE_STRING Unicode;

    } Name;

    //
    //  Marker so we can figure out what kind of name we opened up in
    //  Fcb searches
    //

    BOOLEAN FileNameDos;

    //
    //  And the links.  Our parent Dcb has a pointer to the root entry.
    //

    RTL_SPLAY_LINKS Links;

} FILE_NAME_NODE;
typedef FILE_NAME_NODE *PFILE_NAME_NODE;

//
//  This structure contains fields which must be in non-paged pool.
//

typedef struct _NON_PAGED_FCB {

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

    //
    //  This context is non-zero only if the file currently has asynchronous
    //  non-cached valid data length extending writes.  It allows
    //  synchronization between pending writes and other operations.
    //

    ULONG OutstandingAsyncWrites;

    //
    //  This event is set when OutstandingAsyncWrites transitions to zero.
    //

    PKEVENT OutstandingAsyncEvent;

    //
    //  This is the mutex that is inserted into the FCB_ADVANCED_HEADER
    //  FastMutex field
    //

    FAST_MUTEX AdvancedFcbHeaderMutex;

} NON_PAGED_FCB;

typedef NON_PAGED_FCB *PNON_PAGED_FCB;

//
//  The Fcb/Dcb record corresponds to every open file and directory, and to
//  every directory on an opened path.  They are ordered in two queues, one
//  queue contains every Fcb/Dcb record off of FatData.FcbQueue, the other
//  queue contains only device specific records off of Vcb.VcbSpecificFcbQueue
//

typedef enum _FCB_CONDITION {
    FcbGood = 1,
    FcbBad,
    FcbNeedsToBeVerified
} FCB_CONDITION;

typedef struct _FCB {

    //
    //  The following field is used for fast I/O
    //
    //  The following comments refer to the use of the AllocationSize field
    //  of the FsRtl-defined header to the nonpaged Fcb.
    //
    //  For a directory when we create a Dcb we will not immediately
    //  initialize the cache map, instead we will postpone it until our first
    //  call to FatReadDirectoryFile or FatPrepareWriteDirectoryFile.
    //  At that time we will search the Fat to find out the current allocation
    //  size (by calling FatLookupFileAllocationSize) and then initialize the
    //  cache map to this allocation size.
    //
    //  For a file when we create an Fcb we will not immediately initialize
    //  the cache map, instead we will postpone it until we need it and
    //  then we determine the allocation size from either searching the
    //  fat to determine the real file allocation, or from the allocation
    //  that we've just allocated if we're creating a file.
    //
    //  A value of -1 indicates that we do not know what the current allocation
    //  size really is, and need to examine the fat to find it.  A value
    //  of than -1 is the real file/directory allocation size.
    //
    //  Whenever we need to extend the allocation size we call
    //  FatAddFileAllocation which (if we're really extending the allocation)
    //  will modify the Fat, Mcb, and update this field.  The caller
    //  of FatAddFileAllocation is then responsible for altering the Cache
    //  map size.
    //
    //  We are now using the ADVANCED fcb header to support filter contexts
    //  at the stream level
    //

    FSRTL_ADVANCED_FCB_HEADER Header;

    //
    //  This structure contains fields which must be in non-paged pool.
    //

    PNON_PAGED_FCB NonPaged;

    //
    //  The head of the fat alloaction chain.  FirstClusterOfFile == 0
    //  means that the file has no current allocation.
    //

    ULONG FirstClusterOfFile;

    //
    //  The links for the queue of all fcbs for a specific dcb off of
    //  Dcb.ParentDcbQueue.  For the root directory this queue is empty
    //  For a non-existent fcb this queue is off of the non existent
    //  fcb queue entry in the vcb.
    //

    LIST_ENTRY ParentDcbLinks;

    //
    //  A pointer to the Dcb that is the parent directory containing
    //  this fcb.  If this record itself is the root dcb then this field
    //  is null.
    //

    struct _FCB *ParentDcb;

    //
    //  A pointer to the Vcb containing this Fcb
    //

    PVCB Vcb;

    //
    //  The internal state of the Fcb.  This is a collection Fcb state flags.
    //  Also the shared access for each time this file/directory is opened.
    //

    ULONG FcbState;
    FCB_CONDITION FcbCondition;
    SHARE_ACCESS ShareAccess;

#ifdef SYSCACHE_COMPILE

    //
    //  For syscache we keep a bitmask that tells us if we have dispatched IO for
    //  the page aligned chunks of the stream.
    //

    PULONG WriteMask;
    ULONG WriteMaskData;

#endif

    //
    //  A count of the number of file objects that have been opened for
    //  this file/directory, but not yet been cleaned up yet.  This count
    //  is only used for data file objects, not for the Acl or Ea stream
    //  file objects.  This count gets decremented in FatCommonCleanup,
    //  while the OpenCount below gets decremented in FatCommonClose.
    //

    CLONG UncleanCount;

    //
    //  A count of the number of file objects that have opened
    //  this file/directory.  For files & directories the FsContext of the
    //  file object points to this record.
    //

    CLONG OpenCount;

    //
    //  A count of how many of "UncleanCount" handles were opened for
    //  non-cached I/O.
    //

    CLONG NonCachedUncleanCount;

    //
    //  The following field is used to locate the dirent for this fcb/dcb.
    //  All directory are opened as mapped files so the only additional
    //  information we need to locate this dirent (beside its parent directory)
    //  is the byte offset for the dirent.  Note that for the root dcb
    //  this field is not used.
    //

    VBO DirentOffsetWithinDirectory;

    //
    //  The following field is filled in when there is an Lfn associated
    //  with this file.  It is the STARTING offset of the Lfn.
    //

    VBO LfnOffsetWithinDirectory;

    //
    //  Thess entries is kept in ssync with the dirent.  It allows a more
    //  accurate verify capability and speeds up FatFastQueryBasicInfo().
    //

    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;

    //
    //  Valid data to disk
    //

    ULONG ValidDataToDisk;

    //
    //  The following field contains the retrieval mapping structure
    //  for the file/directory.  Note that for the Root Dcb this
    //  structure is set at mount time.  Also note that in this
    //  implementation of Fat the Mcb really maps VBOs to LBOs and not
    //  VBNs to LBNs.
    //

    LARGE_MCB Mcb;

    //
    //  The following union is cased off of the node type code for the fcb.
    //  There is a seperate case for the directory versus file fcbs.
    //

    union {

        //
        //  A Directory Control Block (Dcb)
        //

        struct {

            //
            //  A queue of all the fcbs/dcbs that are opened under this
            //  Dcb.
            //

            LIST_ENTRY ParentDcbQueue;

            //
            //  The following field points to the file object used to do I/O to
            //  the directory file for this dcb.  The directory file maps the
            //  sectors for the directory.  This field is initialized by
            //  CreateRootDcb but is left null by CreateDcb.  It isn't
            //  until we try to read/write the directory file that we
            //  create the stream file object for non root dcbs.
            //

            ULONG DirectoryFileOpenCount;
            PFILE_OBJECT DirectoryFile;

            //
            //  If the UnusedDirentVbo is != 0xffffffff, then the dirent at this
            //  offset is guarenteed to unused.  A value of 0xffffffff means
            //  it has yet to be initialized.  Note that a value beyond the
            //  end of allocation means that there an unused dirent, but we
            //  will have to allocate another cluster to use it.
            //
            //  DeletedDirentHint contains lowest possible VBO of a deleted
            //  dirent (assuming as above that it is not 0xffffffff).
            //

            VBO UnusedDirentVbo;
            VBO DeletedDirentHint;

            //
            //  The following two entries links together all the Fcbs
            //  opened under this Dcb sorted in a splay tree by name.
            //
            //  I'd like to go into why we have (and must have) two separate
            //  splay trees within the current fastfat architecture.  I will
            //  provide some insight into what would have to change if we
            //  wanted to have a single UNICODE tree.
            //
            //  What makes FAT unique is that both Oem and Unicode names sit
            //  side by side on disk.  Several unique UNICODE names coming
            //  into fastfat can match a single OEM on-disk name, and there
            //  is really no way to enumerate all the possible UNICODE
            //  source strings that can map to a given OEM name.  This argues
            //  for converting the incomming UNICODE name into OEM, and then
            //  running through an OEM splay tree of the open files.  This
            //  works well when there are only OEM names on disk.
            //
            //  The UNICODE name on disk can be VERY different from the short
            //  name in the DIRENT and not even representable in the OEM code
            //  page.  Even if it were representable in OEM, it is possible
            //  that a case varient of the original UNICODE name would match
            //  a different OEM name, causing us to miss the Fcb in the
            //  prefix lookup phase.  In these cases, we must put UNICODE
            //  name in the splay to guarentee that we find any case varient
            //  of the input UNICODE name.  See the routine description of
            //  FatConstructNamesInFcb() for a detailed analysis of how we
            //  detect this case.
            //
            //  The fundamental limitation we are imposing here is that if
            //  an Fcb exists for an open file, we MUST find it during the
            //  prefix stage.  This is a basic premise of the create path
            //  in fastfat.  In fact if we later find it gravelling through
            //  the disk (but not the splay tree), we will bug check if we
            //  try to add a duplicate entry to the splay tree (not to
            //  mention having two Fcbs).  If we had some mechanism to deal
            //  with cases (and they would be rare) that we don't find the
            //  entry in the splay tree, but the Fcb is actually in there,
            //  then we could go to a single UNICODE splay tree.  While
            //  this uses more pool for the splay tree, and makes string
            //  compares maybe take a bit as longer, it would eliminate the
            //  need for any NLS conversion during the prefix phase, so it
            //  might really be a net win.
            //
            //  The current scheme was optimized for non-extended names
            //  (i.e. US names).  As soon as you start using extended
            //  characters, then it is clearly a win as many code paths
            //  become active that would otherwise not be needed if we
            //  only had a single UNICODE splay tree.
            //
            //  We may think about changing this someday.
            //

            PRTL_SPLAY_LINKS RootOemNode;
            PRTL_SPLAY_LINKS RootUnicodeNode;

            //
            //  The following field keeps track of free dirents, i.e.,
            //  dirents that are either unallocated for deleted.
            //

            RTL_BITMAP FreeDirentBitmap;

            //
            //  Since the FCB specific part of this union is larger, use
            //  the slack here for an initial bitmap buffer.  Currently
            //  there is enough space here for an 8K cluster.
            //

            ULONG FreeDirentBitmapBuffer[1];

        } Dcb;

        //
        //  A File Control Block (Fcb)
        //

        struct {

            //
            //  The following field is used by the filelock module
            //  to maintain current byte range locking information.
            //

            FILE_LOCK FileLock;

            //
            //  The following field is used by the oplock module
            //  to maintain current oplock information.
            //

            OPLOCK Oplock;

            //
            //  This pointer is used to detect writes that eminated in the
            //  cache manager's lazywriter.  It prevents lazy writer threads,
            //  who already have the Fcb shared, from trying to acquire it
            //  exclusive, and thus causing a deadlock.
            //

            PVOID LazyWriteThread;

        } Fcb;

    } Specific;

    //
    //  The following field is used to verify that the Ea's for a file
    //  have not changed between calls to query for Ea's.  It is compared
    //  with a similar field in a Ccb.
    //
    //  IMPORTANT!! **** DO NOT MOVE THIS FIELD ****
    //
    //              The slack space in the union above is computed from
    //              the field offset of the EaModificationCount.
    //

    ULONG EaModificationCount;

    //
    //  The following field is the fully qualified file name for this FCB/DCB
    //  starting from the root of the volume, and last file name in the
    //  fully qualified name.
    //

    FILE_NAME_NODE ShortName;

    //
    //  The following field is only filled in if it is needed with the user's
    //  opened path
    //

    UNICODE_STRING FullFileName;

    USHORT FinalNameLength;

    //
    //  To make life simpler we also keep in the Fcb/Dcb a current copy of
    //  the fat attribute byte for the file/directory.  This field must
    //  also be updated when we create the Fcb, modify the File, or verify
    //  the Fcb
    //

    UCHAR DirentFatFlags;

    //
    //  The case preserved long filename
    //

    UNICODE_STRING ExactCaseLongName;

    //
    //  If the UNICODE Lfn is fully expressible in the system Oem code
    //  page, then we will store it in a prefix table, otherwise we will
    //  store the last UNICODE name in the Fcb.  In both cases the name
    //  has been upcased.
    //
    //  Note that we may need neither of these fields if an LFN was strict
    //  8.3 or differed only in case.  Indeed if there wasn't an LFN, we
    //  don't need them at all.
    //

    union {

        //
        //  This first field is present if FCB_STATE_HAS_OEM_LONG_NAME
        //  is set in the FcbState.
        //

        FILE_NAME_NODE Oem;

        //
        //  This first field is present if FCB_STATE_HAS_UNICODE_LONG_NAME
        //  is set in the FcbState.
        //

        FILE_NAME_NODE Unicode;

    } LongName;

    //
    //  Defragmentation / ReallocateOnWrite synchronization object.  This
    //  is filled in by FatMoveFile() and affects the read and write paths.
    //

    PKEVENT MoveFileEvent;

} FCB, *PFCB;

#ifndef BUILDING_FSKDEXT
//
//  DCB clashes with a type defined outside the filesystems,  in headers
//  pulled in by FSKD.  We don't need this typedef for fskd anyway....
//
typedef FCB DCB;
typedef DCB *PDCB;
#endif


//
//  Here are the Fcb state fields.
//

#define FCB_STATE_DELETE_ON_CLOSE        (0x00000001)
#define FCB_STATE_TRUNCATE_ON_CLOSE      (0x00000002)
#define FCB_STATE_PAGING_FILE            (0x00000004)
#define FCB_STATE_FORCE_MISS_IN_PROGRESS (0x00000008)
#define FCB_STATE_FLUSH_FAT              (0x00000010)
#define FCB_STATE_TEMPORARY              (0x00000020)
#define FCB_STATE_SYSTEM_FILE            (0x00000080)
#define FCB_STATE_NAMES_IN_SPLAY_TREE    (0x00000100)
#define FCB_STATE_HAS_OEM_LONG_NAME      (0x00000200)
#define FCB_STATE_HAS_UNICODE_LONG_NAME  (0x00000400)
#define FCB_STATE_DELAY_CLOSE            (0x00000800)

//
//  Copies of the dirent's FAT_DIRENT_NT_BYTE_* flags for
//  preserving case of the short name of a file
//

#define FCB_STATE_8_LOWER_CASE           (0x00001000)
#define FCB_STATE_3_LOWER_CASE           (0x00002000)

//
//  This is the slack allocation in the Dcb part of the UNION above
//

#define DCB_UNION_SLACK_SPACE ((ULONG)                       \
    (FIELD_OFFSET(DCB, EaModificationCount) -                \
     FIELD_OFFSET(DCB, Specific.Dcb.FreeDirentBitmapBuffer)) \
)

//
//  This is the special (64bit) allocation size that indicates the
//  real size must be retrieved from disk.  Define it here so we
//  avoid excessive magic numbering around the driver.
//

#define FCB_LOOKUP_ALLOCATIONSIZE_HINT   ((LONGLONG) -1)


//
//  The Ccb record is allocated for every file object.  Note that this
//  record is exactly 0x34 long on x86 so that it will fit into a 0x40
//  piece of pool.  Please carefully consider modifications.
//
//  Define the Flags field.
//

#define CCB_FLAG_MATCH_ALL               (0x0001)
#define CCB_FLAG_SKIP_SHORT_NAME_COMPARE (0x0002)

//
//  This tells us whether we allocated buffers to hold search templates.
//

#define CCB_FLAG_FREE_OEM_BEST_FIT       (0x0004)
#define CCB_FLAG_FREE_UNICODE            (0x0008)

//
//  These flags prevents cleanup from updating the modify time, etc.
//

#define CCB_FLAG_USER_SET_LAST_WRITE     (0x0010)
#define CCB_FLAG_USER_SET_LAST_ACCESS    (0x0020)
#define CCB_FLAG_USER_SET_CREATION       (0x0040)

//
//  This bit says the file object associated with this Ccb was opened for
//  read only access.
//

#define CCB_FLAG_READ_ONLY               (0x0080)

//
//  These flags, are used is DASD handles in read and write.
//

#define CCB_FLAG_DASD_FLUSH_DONE         (0x0100)
#define CCB_FLAG_DASD_PURGE_DONE         (0x0200)

//
//  This flag keeps track of a handle that was opened for
//  DELETE_ON_CLOSE.
//

#define CCB_FLAG_DELETE_ON_CLOSE         (0x0400)

//
//  This flag keeps track of which side of the name pair on the file
//  associated with the handle was opened
//

#define CCB_FLAG_OPENED_BY_SHORTNAME     (0x0800)

//
//  This flag indicates that the query template has not been upcased
// (i.e., query should be case-insensitive)
//

#define CCB_FLAG_QUERY_TEMPLATE_MIXED    (0x1000)

//
//  This flag indicates that reads and writes via this DASD handle
//  are allowed to start or extend past the end of file.
//

#define CCB_FLAG_ALLOW_EXTENDED_DASD_IO  (0x2000)

//
//  This flag indicates we want to match volume labels in directory
//  searches (important for the root dir defrag).
//

#define CCB_FLAG_MATCH_VOLUME_ID         (0x4000)

//
//  This flag indicates the ccb has been converted over into a
//  close context for asynchronous/delayed closing of the handle.
//

#define CCB_FLAG_CLOSE_CONTEXT           (0x8000)

//
//  This flag indicates that when the handle is closed, we want
//  a physical dismount to occur.
//

#define CCB_FLAG_COMPLETE_DISMOUNT       (0x10000)

//
//  This flag indicates the handle may not call priveleged
//  FSCTL which modify the volume.
//

#define CCB_FLAG_MANAGE_VOLUME_ACCESS    (0x20000)

//
//  This structure is used to keep track of information needed to do a
//  deferred close.  It is now embedded in a CCB so we don't have to
//  allocate one in the close path (with mustsucceed).
//

typedef struct _CLOSE_CONTEXT {

    //
    //  Two sets of links, one for the global list and one for closes
    //  on a particular volume.
    //
    
    LIST_ENTRY GlobalLinks;
    LIST_ENTRY VcbLinks;

    PVCB Vcb;
    PFCB Fcb;
    enum _TYPE_OF_OPEN TypeOfOpen;
    BOOLEAN Free;

} CLOSE_CONTEXT;

typedef CLOSE_CONTEXT *PCLOSE_CONTEXT;

typedef struct _CCB {

    //
    //  Type and size of this record (must be FAT_NTC_CCB)
    //

    NODE_TYPE_CODE NodeTypeCode;
    NODE_BYTE_SIZE NodeByteSize;

    //
    //  Define a 24bit wide field for Flags, but a UCHAR for Wild Cards Present
    //  since it is used so often.  Line these up on byte boundaries for grins.
    //

    ULONG Flags:24;
    BOOLEAN ContainsWildCards;

    //
    //  Overlay a close context on the data of the CCB.  The remaining
    //  fields are not useful during close, and we would like to avoid
    //  paying extra pool for it.
    //

    union {
        
        struct {

            //
            //  Save the offset to start search from.
            //

            VBO OffsetToStartSearchFrom;

            //
            //  The query template is used to filter directory query requests.
            //  It originally is set to null and on the first call the NtQueryDirectory
            //  it is set to the input filename or "*" if the name is not supplied.
            //  All subsquent queries then use this template.
            //
            //  The Oem structure are unions because if the name is wild we store
            //  the arbitrary length string, while if the name is constant we store
            //  8.3 representation for fast comparison.
            //

            union {

                //
                //  If the template contains a wild card use this.
                //

                OEM_STRING Wild;

                //
                //  If the name is constant, use this part.
                //

                FAT8DOT3 Constant;

            } OemQueryTemplate;

            UNICODE_STRING UnicodeQueryTemplate;

            //
            //  The field is compared with the similar field in the Fcb to determine
            //  if the Ea's for a file have been modified.
            //

            ULONG EaModificationCount;

            //
            //  The following field is used as an offset into the Eas for a
            //  particular file.  This will be the offset for the next
            //  Ea to return.  A value of 0xffffffff indicates that the
            //  Ea's are exhausted.
            //

            ULONG OffsetOfNextEaToReturn;

        };

        CLOSE_CONTEXT CloseContext;
    };
    
} CCB;
typedef CCB *PCCB;

//
//  The Irp Context record is allocated for every orginating Irp.  It is
//  created by the Fsd dispatch routines, and deallocated by the FatComplete
//  request routine.  It contains a structure called of type REPINNED_BCBS
//  which is used to retain pinned bcbs needed to handle abnormal termination
//  unwinding.
//

#define REPINNED_BCBS_ARRAY_SIZE         (4)

typedef struct _REPINNED_BCBS {

    //
    //  A pointer to the next structure contains additional repinned bcbs
    //

    struct _REPINNED_BCBS *Next;

    //
    //  A fixed size array of pinned bcbs.  Whenever a new bcb is added to
    //  the repinned bcb structure it is added to this array.  If the
    //  array is already full then another repinned bcb structure is allocated
    //  and pointed to with Next.
    //

    PBCB Bcb[ REPINNED_BCBS_ARRAY_SIZE ];

} REPINNED_BCBS;
typedef REPINNED_BCBS *PREPINNED_BCBS;

typedef struct _IRP_CONTEXT {

    //
    //  Type and size of this record (must be FAT_NTC_IRP_CONTEXT)
    //

    NODE_TYPE_CODE NodeTypeCode;
    NODE_BYTE_SIZE NodeByteSize;

    //
    //  This structure is used for posting to the Ex worker threads.
    //

    WORK_QUEUE_ITEM WorkQueueItem;

    //
    //  A pointer to the originating Irp.
    //

    PIRP OriginatingIrp;

    //
    //  Originating Device (required for workque algorithms)
    //

    PDEVICE_OBJECT RealDevice;

    //
    //  Originating Vcb (required for exception handling)
    //  On mounts, this will be set before any exceptions
    //  indicating corruption can be thrown.
    //

    PVCB Vcb;

    //
    //  Major and minor function codes copied from the Irp
    //

    UCHAR MajorFunction;
    UCHAR MinorFunction;

    //
    //  The following fields indicate if we can wait/block for a resource
    //  or I/O, if we are to do everything write through, and if this
    //  entry into the Fsd is a recursive call.
    //

    UCHAR PinCount;

    ULONG Flags;

    //
    //  The following field contains the NTSTATUS value used when we are
    //  unwinding due to an exception
    //

    NTSTATUS ExceptionStatus;

    //
    //  The following context block is used for non-cached Io
    //

    struct _FAT_IO_CONTEXT *FatIoContext;

    //
    //  For a abnormal termination unwinding this field contains the Bcbs
    //  that are kept pinned until the Irp is completed.
    //

    REPINNED_BCBS Repinned;

} IRP_CONTEXT;
typedef IRP_CONTEXT *PIRP_CONTEXT;

#define IRP_CONTEXT_FLAG_DISABLE_DIRTY              (0x00000001)
#define IRP_CONTEXT_FLAG_WAIT                       (0x00000002)
#define IRP_CONTEXT_FLAG_WRITE_THROUGH              (0x00000004)
#define IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH      (0x00000008)
#define IRP_CONTEXT_FLAG_RECURSIVE_CALL             (0x00000010)
#define IRP_CONTEXT_FLAG_DISABLE_POPUPS             (0x00000020)
#define IRP_CONTEXT_FLAG_DEFERRED_WRITE             (0x00000040)
#define IRP_CONTEXT_FLAG_VERIFY_READ                (0x00000080)
#define IRP_CONTEXT_STACK_IO_CONTEXT                (0x00000100)
#define IRP_CONTEXT_FLAG_IN_FSP                     (0x00000200)
#define IRP_CONTEXT_FLAG_USER_IO                    (0x00000400)       // for performance counters
#define IRP_CONTEXT_FLAG_DISABLE_RAISE              (0x00000800)
#define IRP_CONTEXT_FLAG_PARENT_BY_CHILD (0x80000000)


//
//  Context structure for non-cached I/O calls.  Most of these fields
//  are actually only required for the Read/Write Multiple 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 _FAT_IO_CONTEXT {

    //
    //  These two field are used for multiple run Io
    //

    LONG IrpCount;
    PIRP MasterIrp;

    //
    //  MDL to describe partial sector zeroing
    //

    PMDL ZeroMdl;

    union {

        //
        //  This element handles the asychronous non-cached Io
        //

        struct {
            PERESOURCE Resource;
            PERESOURCE Resource2;
            ERESOURCE_THREAD ResourceThreadId;
            ULONG RequestedByteCount;
            PFILE_OBJECT FileObject;
            PNON_PAGED_FCB NonPagedFcb;
        } Async;

        //
        //  and this element the sycnrhonous non-cached Io
        //

        KEVENT SyncEvent;

    } Wait;

} FAT_IO_CONTEXT;

typedef FAT_IO_CONTEXT *PFAT_IO_CONTEXT;

//
//  An array of these structures is passed to FatMultipleAsync describing
//  a set of runs to execute in parallel.
//

typedef struct _IO_RUNS {

    LBO Lbo;
    VBO Vbo;
    ULONG Offset;
    ULONG ByteCount;
    PIRP SavedIrp;

} IO_RUN;

typedef IO_RUN *PIO_RUN;

//
//  This structure is used by FatDeleteDirent to preserve the first cluster
//  and file size info for undelete utilities.
//

typedef struct _DELETE_CONTEXT {

    ULONG FileSize;
    ULONG FirstClusterOfFile;

} DELETE_CONTEXT;

typedef DELETE_CONTEXT *PDELETE_CONTEXT;

//
//  This record is used with to set a flush to go off one second after the
//  first write on slow devices with a physical indication of activity, like
//  a floppy.  This is an attempt to keep the red light on.
//

typedef struct _DEFERRED_FLUSH_CONTEXT {

    KDPC Dpc;
    KTIMER Timer;
    WORK_QUEUE_ITEM Item;

    PFILE_OBJECT File;

} DEFERRED_FLUSH_CONTEXT;

typedef DEFERRED_FLUSH_CONTEXT *PDEFERRED_FLUSH_CONTEXT;

//
//  This structure is used for the FatMarkVolumeClean callbacks.
//

typedef struct _CLEAN_AND_DIRTY_VOLUME_PACKET {

    WORK_QUEUE_ITEM Item;
    PIRP Irp;
    PVCB Vcb;
    PKEVENT Event;
} CLEAN_AND_DIRTY_VOLUME_PACKET, *PCLEAN_AND_DIRTY_VOLUME_PACKET;

//
//  This structure is used when a page fault is running out of stack.
//

typedef struct _PAGING_FILE_OVERFLOW_PACKET {
    PIRP Irp;
    PFCB Fcb;
} PAGING_FILE_OVERFLOW_PACKET, *PPAGING_FILE_OVERFLOW_PACKET;

//
//  This structure is used to access the EaFile.
//

#define EA_BCB_ARRAY_SIZE                   8

typedef struct _EA_RANGE {

    PCHAR Data;
    ULONG StartingVbo;
    ULONG Length;
    USHORT BcbChainLength;
    BOOLEAN AuxilaryBuffer;
    PBCB *BcbChain;
    PBCB BcbArray[EA_BCB_ARRAY_SIZE];

} EA_RANGE, *PEA_RANGE;

#define EA_RANGE_HEADER_SIZE        (FIELD_OFFSET( EA_RANGE, BcbArray ))

//
//  These symbols are used by the upcase/downcase routines.
//

#define WIDE_LATIN_CAPITAL_A    (0xff21)
#define WIDE_LATIN_CAPITAL_Z    (0xff3a)
#define WIDE_LATIN_SMALL_A      (0xff41)
#define WIDE_LATIN_SMALL_Z      (0xff5a)

//
//  These values are returned by FatInterpretClusterType.
//

typedef enum _CLUSTER_TYPE {
    FatClusterAvailable,
    FatClusterReserved,
    FatClusterBad,
    FatClusterLast,
    FatClusterNext
} CLUSTER_TYPE;


#endif // _FATSTRUC_

