1606 lines
43 KiB
C
1606 lines
43 KiB
C
|
/*++
|
|||
|
|
|||
|
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_
|
|||
|
|