/*++ 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; // // Forward reference some circular referenced structures. // typedef struct _VCB VCB; typedef VCB *PVCB; typedef struct _FCB FCB; typedef FCB *PFCB; // // 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 { // // 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; // // 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; // // This is the close context associated with the Virtual Volume File. // PCLOSE_CONTEXT CloseContext; // // How many close contexts were preallocated on this Vcb // #if DBG ULONG CloseContextCount; #endif } 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) #define VCB_STATE_VPB_NOT_ON_DEVICE (0x00020000) // // 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) 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_