You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1771 lines
48 KiB
1771 lines
48 KiB
/*++
|
|
|
|
Copyright (c) 1989-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
CdStruc.h
|
|
|
|
Abstract:
|
|
|
|
This module defines the data structures that make up the major internal
|
|
part of the Cdfs file system.
|
|
|
|
In-Memory structures:
|
|
|
|
The global data structures with the CdDataRecord. It contains a pointer
|
|
to a File System Device object and a queue of Vcb's. There is a Vcb for
|
|
every currently or previously mounted volumes. We may be in the process
|
|
of tearing down the Vcb's which have been dismounted. The Vcb's are
|
|
allocated as an extension to a volume device object.
|
|
|
|
+--------+
|
|
| CdData | +--------+
|
|
| | --> |FilSysDo|
|
|
| | | |
|
|
| | <+ +--------+
|
|
+--------+ |
|
|
|
|
|
| +--------+ +--------+
|
|
| |VolDo | |VolDo |
|
|
| | | | |
|
|
| +--------+ +--------+
|
|
+> |Vcb | <-> |Vcb | <-> ...
|
|
| | | |
|
|
+--------+ +--------+
|
|
|
|
|
|
Each Vcb contains a table of all the Fcbs for the volume indexed by
|
|
their FileId. Each Vcb contains a pointer to the root directory of
|
|
the volume. Each directory Fcb contains a queue of child Fcb's for
|
|
its children. There can also be detached subtrees due to open operations
|
|
by Id where the Fcb's are not connected to the root.
|
|
|
|
The following diagram shows the root structure.
|
|
|
|
+--------+ +--------+
|
|
| Vcb |---->| Fcb |-----------------------------------------------+
|
|
| | | Table |--------------------------------------------+ | |
|
|
| |--+ | |-----------------------------------------+ | | |
|
|
+--------+ | +--------+ | | |
|
|
| | | | | | |
|
|
| | | +--------------------+ | | |
|
|
| V +---------+ | | | |
|
|
| +--------+ | | | | |
|
|
| |RootFcb | V V | | |
|
|
+->| | +--------+ +--------+ | | |
|
|
| |-->|Child | |Child | | | |
|
|
+--------+ | Fcb |<-->| Fcb |<--> ... | | |
|
|
| | | | | | |
|
|
+--------+ +--------+ | | |
|
|
| | |
|
|
(Freestanding sub-tree) | | |
|
|
+--------+ | | |
|
|
|OpenById|<-----------------------------------------+ | |
|
|
| Dir | +--------+ | |
|
|
| |--->|OpenById|<------------------------------+ |
|
|
+--------+ | Child | +--------+ |
|
|
| Dir |--->|OpenById|<-------------------+
|
|
+--------+ | Child |
|
|
| File |
|
|
+--------+
|
|
|
|
Attached to each Directory Fcb is a prefix table containing the names
|
|
of children of this directory for which there is an Fcb. Not all Fcb's
|
|
will necessarily have an entry in this table.
|
|
|
|
+--------+ +--------+
|
|
| Dir | | Prefix |
|
|
| Fcb |----->| Table |--------------------+
|
|
| | | |-------+ |
|
|
+--------+ +--------+ | |
|
|
| | | |
|
|
| | | |
|
|
| V V V
|
|
| +--------+ +--------+ +--------+ +--------+
|
|
| | Fcb | | Fcb | | Fcb | | Fcb |
|
|
+---------->| |<-->| |<-->| |<-->| |
|
|
| | | | | | | |
|
|
+--------+ +--------+ +--------+ +--------+
|
|
|
|
|
|
Each file object open on a CDROM volume contains two context pointers. The
|
|
first will point back to the Fcb for the file object. The second, if present,
|
|
points to a Ccb (ContextControlBlock) which contains the per-handle information.
|
|
This includes the state of any directory enumeration.
|
|
|
|
+--------+ +--------+ +--------+
|
|
| Fcb |<------| File | | Ccb |
|
|
| | | Object|--->| |
|
|
| | | | | |
|
|
+--------+ +--------+ +--------+
|
|
^ ^
|
|
| | +--------+ +--------+
|
|
| | | File | | Ccb |
|
|
| +---------| Object|--->| |
|
|
| | | | |
|
|
| +--------+ +--------+
|
|
|
|
|
| +--------+
|
|
| |Stream |
|
|
+--------------| File |
|
|
| Object|
|
|
+--------+
|
|
|
|
|
|
Synchronization:
|
|
|
|
1. A resource in the CdData synchronizes access to the Vcb queue. This
|
|
is used during mount/verify/dismount operations.
|
|
|
|
2. A resource in the Vcb is used to synchronize access to Vcb for
|
|
open/close operations. Typically acquired shared, it
|
|
is acquired exclusively to lock out these operations.
|
|
|
|
3. A second resource in the Vcb is used to synchronize all file operations.
|
|
Typically acquired shared, it is acquired exclusively to lock
|
|
out all file operations. Acquiring both Vcb resources will lock
|
|
the entire volume.
|
|
|
|
4. A resource in the nonpaged Fcb will synchronize open/close operations
|
|
on an Fcb.
|
|
|
|
5. A fast mutex in the Vcb will protect access to the Fcb table and
|
|
the open counts in the Vcb. It is also used to modify the reference
|
|
counts in all Fcbs. This mutex cannot be acquired
|
|
exclusely and is an end resource.
|
|
|
|
6. A fast mutex in the Fcb will synchronize access to all Fcb fields
|
|
which aren't synchronized in some other way. A thread may acquire
|
|
mutexes for multiple Fcb's as long as it works it way toward the
|
|
root of the tree. This mutex can also be acquired recursively.
|
|
|
|
7. Normal locking order is CdData/Vcb/Fcb starting at any point in this
|
|
chain. The Vcb is required prior to acquiring resources for multiple
|
|
files. Shared ownership of the Vcb is sufficient in this case.
|
|
|
|
8. Normal locking order when acquiring multiple Fcb's is from some
|
|
starting Fcb and walking towards the root of tree. Create typically
|
|
walks down the tree. In this case we will attempt to acquire the
|
|
next node optimistically and if that fails we will reference
|
|
the current node in the tree, release it and acquire the next node.
|
|
At that point it will be safe to reacquire the parent node.
|
|
|
|
9. Locking order for the Fcb (via the fast mutex) will be from leaf of
|
|
tree back towards the root. No other resource may be acquired
|
|
after locking the Vcb (other than in-page reads).
|
|
|
|
10. Cleanup operations only lock the Vcb and Fcb long enough to change the
|
|
critical counts and share access fields. No reason to synchronize
|
|
otherwise. None of the structures can go away from beneath us
|
|
in this case.
|
|
|
|
// @@BEGIN_DDKSPLIT
|
|
|
|
Author:
|
|
|
|
Brian Andrew [BrianAn] 01-July-1995
|
|
|
|
Revision History:
|
|
|
|
// @@END_DDKSPLIT
|
|
|
|
--*/
|
|
|
|
#ifndef _CDSTRUC_
|
|
#define _CDSTRUC_
|
|
|
|
typedef PVOID PBCB; //**** Bcb's are now part of the cache module
|
|
|
|
#define BYTE_COUNT_EMBEDDED_NAME (32)
|
|
|
|
|
|
//
|
|
// The CD_MCB is used to store the mapping of logical file offset to
|
|
// logical disk offset. NOTE - This package only deals with the
|
|
// logical 2048 sectors. Translating to 'raw' sectors happens in
|
|
// software. We will embed a single MCB_ENTRY in the Fcb since this
|
|
// will be the typical case.
|
|
//
|
|
|
|
typedef struct _CD_MCB {
|
|
|
|
//
|
|
// Size and current count of the Mcb entries.
|
|
//
|
|
|
|
ULONG MaximumEntryCount;
|
|
ULONG CurrentEntryCount;
|
|
|
|
//
|
|
// Pointer to the start of the Mcb entries.
|
|
//
|
|
|
|
struct _CD_MCB_ENTRY *McbArray;
|
|
|
|
} CD_MCB;
|
|
typedef CD_MCB *PCD_MCB;
|
|
|
|
typedef struct _CD_MCB_ENTRY {
|
|
|
|
//
|
|
// Starting offset and number of bytes described by this entry.
|
|
// The Byte count is rounded to a logical block boundary if this is
|
|
// the last block.
|
|
//
|
|
|
|
LONGLONG DiskOffset;
|
|
LONGLONG ByteCount;
|
|
|
|
//
|
|
// Starting offset in the file of mapping described by this dirent.
|
|
//
|
|
|
|
LONGLONG FileOffset;
|
|
|
|
//
|
|
// Data length and block length. Data length is the length of each
|
|
// data block. Total length is the length of each data block and
|
|
// the skip size.
|
|
//
|
|
|
|
LONGLONG DataBlockByteCount;
|
|
LONGLONG TotalBlockByteCount;
|
|
|
|
} CD_MCB_ENTRY;
|
|
typedef CD_MCB_ENTRY *PCD_MCB_ENTRY;
|
|
|
|
|
|
//
|
|
// Cd name structure. The following structure is used to represent the
|
|
// full Cdrom name. This name can be stored in either Unicode or ANSI
|
|
// format.
|
|
//
|
|
|
|
typedef struct _CD_NAME {
|
|
|
|
//
|
|
// String containing name without the version number.
|
|
// The maximum length field for filename indicates the
|
|
// size of the buffer allocated for the two parts of the name.
|
|
//
|
|
|
|
UNICODE_STRING FileName;
|
|
|
|
//
|
|
// String containging the version number.
|
|
//
|
|
|
|
UNICODE_STRING VersionString;
|
|
|
|
} CD_NAME;
|
|
typedef CD_NAME *PCD_NAME;
|
|
|
|
//
|
|
// Following is the splay link structure for the prefix lookup.
|
|
// The names can be in either Unicode string or Ansi string format.
|
|
//
|
|
|
|
typedef struct _NAME_LINK {
|
|
|
|
RTL_SPLAY_LINKS Links;
|
|
UNICODE_STRING FileName;
|
|
|
|
} NAME_LINK;
|
|
typedef NAME_LINK *PNAME_LINK;
|
|
|
|
|
|
//
|
|
// Prefix entry. There is one of these for each name in the prefix table.
|
|
// An Fcb will have one of these embedded for the long name and an optional
|
|
// pointer to the short name entry.
|
|
//
|
|
|
|
typedef struct _PREFIX_ENTRY {
|
|
|
|
//
|
|
// Pointer to the Fcb for this entry.
|
|
//
|
|
|
|
struct _FCB *Fcb;
|
|
|
|
//
|
|
// Flags field. Used to indicate if the name is in the prefix table.
|
|
//
|
|
|
|
ULONG PrefixFlags;
|
|
|
|
//
|
|
// Exact case name match.
|
|
//
|
|
|
|
NAME_LINK ExactCaseName;
|
|
|
|
//
|
|
// Case-insensitive name link.
|
|
//
|
|
|
|
NAME_LINK IgnoreCaseName;
|
|
|
|
WCHAR FileNameBuffer[ BYTE_COUNT_EMBEDDED_NAME ];
|
|
|
|
} PREFIX_ENTRY;
|
|
typedef PREFIX_ENTRY *PPREFIX_ENTRY;
|
|
|
|
#define PREFIX_FLAG_EXACT_CASE_IN_TREE (0x00000001)
|
|
#define PREFIX_FLAG_IGNORE_CASE_IN_TREE (0x00000002)
|
|
|
|
|
|
//
|
|
// The CD_DATA record is the top record in the CDROM file system in-memory
|
|
// data structure. This structure must be allocated from non-paged pool.
|
|
//
|
|
|
|
typedef struct _CD_DATA {
|
|
|
|
//
|
|
// The type and size of this record (must be CDFS_NTC_DATA_HEADER)
|
|
//
|
|
|
|
NODE_TYPE_CODE NodeTypeCode;
|
|
NODE_BYTE_SIZE NodeByteSize;
|
|
|
|
//
|
|
// A pointer to the Driver object we were initialized with
|
|
//
|
|
|
|
PDRIVER_OBJECT DriverObject;
|
|
|
|
//
|
|
// Vcb queue.
|
|
//
|
|
|
|
LIST_ENTRY VcbQueue;
|
|
|
|
//
|
|
// The following fields are used to allocate IRP context structures
|
|
// using a lookaside list, and other fixed sized structures from a
|
|
// small cache. We use the CdData mutex to protext these structures.
|
|
//
|
|
|
|
ULONG IrpContextDepth;
|
|
ULONG IrpContextMaxDepth;
|
|
SINGLE_LIST_ENTRY IrpContextList;
|
|
|
|
//
|
|
// Filesystem device object for CDFS.
|
|
//
|
|
|
|
PDEVICE_OBJECT FileSystemDeviceObject;
|
|
|
|
//
|
|
// Following are used to manage the async and delayed close queue.
|
|
//
|
|
// FspCloseActive - Indicates whether there is a thread processing the
|
|
// two close queues.
|
|
// ReduceDelayedClose - Indicates that we have hit the upper threshold
|
|
// for the delayed close queue and need to reduce it to lower threshold.
|
|
//
|
|
// AsyncCloseQueue - Queue of IrpContext waiting for async close operation.
|
|
// AsyncCloseCount - Number of entries on the async close queue.
|
|
//
|
|
// DelayedCloseQueue - Queue of IrpContextLite waiting for delayed close
|
|
// operation.
|
|
// MaxDelayedCloseCount - Trigger delay close work at this threshold.
|
|
// MinDelayedCloseCount - Turn off delay close work at this threshold.
|
|
// DelayedCloseCount - Number of entries on the delayted close queue.
|
|
//
|
|
// CloseItem - Workqueue item used to start FspClose thread.
|
|
//
|
|
|
|
LIST_ENTRY AsyncCloseQueue;
|
|
ULONG AsyncCloseCount;
|
|
BOOLEAN FspCloseActive;
|
|
BOOLEAN ReduceDelayedClose;
|
|
USHORT PadUshort;
|
|
|
|
//
|
|
// The following fields describe the deferred close file objects.
|
|
//
|
|
|
|
LIST_ENTRY DelayedCloseQueue;
|
|
ULONG DelayedCloseCount;
|
|
ULONG MaxDelayedCloseCount;
|
|
ULONG MinDelayedCloseCount;
|
|
|
|
//
|
|
// Fast mutex used to lock the fields of this structure.
|
|
//
|
|
|
|
PVOID CdDataLockThread;
|
|
FAST_MUTEX CdDataMutex;
|
|
|
|
//
|
|
// A resource variable to control access to the global CDFS data record
|
|
//
|
|
|
|
ERESOURCE DataResource;
|
|
|
|
//
|
|
// Cache manager call back structure, which must be passed on each call
|
|
// to CcInitializeCacheMap.
|
|
//
|
|
|
|
CACHE_MANAGER_CALLBACKS CacheManagerCallbacks;
|
|
CACHE_MANAGER_CALLBACKS CacheManagerVolumeCallbacks;
|
|
|
|
//
|
|
// This is the ExWorkerItem that does both kinds of deferred closes.
|
|
//
|
|
|
|
PIO_WORKITEM CloseItem;
|
|
|
|
} CD_DATA;
|
|
typedef CD_DATA *PCD_DATA;
|
|
|
|
|
|
//
|
|
// The Vcb (Volume control block) record corresponds to every
|
|
// volume mounted by the file system. They are ordered in a queue off
|
|
// of CdData.VcbQueue.
|
|
//
|
|
// The Vcb will be in several conditions during its lifespan.
|
|
//
|
|
// NotMounted - Disk is not currently mounted (i.e. removed
|
|
// from system) but cleanup and close operations are
|
|
// supported.
|
|
//
|
|
// MountInProgress - State of the Vcb from the time it is
|
|
// created until it is successfully mounted or the mount
|
|
// fails.
|
|
//
|
|
// Mounted - Volume is currently in the mounted state.
|
|
//
|
|
// Invalid - User has invalidated the volume. Only legal operations
|
|
// are cleanup and close.
|
|
//
|
|
// DismountInProgress - We have begun the process of tearing down the
|
|
// Vcb. It can be deleted when all the references to it
|
|
// have gone away.
|
|
//
|
|
|
|
typedef enum _VCB_CONDITION {
|
|
|
|
VcbNotMounted = 0,
|
|
VcbMountInProgress,
|
|
VcbMounted,
|
|
VcbInvalid,
|
|
VcbDismountInProgress
|
|
|
|
} VCB_CONDITION;
|
|
|
|
typedef struct _VCB {
|
|
|
|
//
|
|
// The type and size of this record (must be CDFS_NTC_VCB)
|
|
//
|
|
|
|
NODE_TYPE_CODE NodeTypeCode;
|
|
NODE_BYTE_SIZE NodeByteSize;
|
|
|
|
//
|
|
// Vpb for this volume.
|
|
//
|
|
|
|
PVPB Vpb;
|
|
|
|
//
|
|
// Device object for the driver below us.
|
|
//
|
|
|
|
PDEVICE_OBJECT TargetDeviceObject;
|
|
|
|
//
|
|
// File object used to lock the volume.
|
|
//
|
|
|
|
PFILE_OBJECT VolumeLockFileObject;
|
|
|
|
//
|
|
// Link into queue of Vcb's in the CdData structure. We will create a union with
|
|
// a LONGLONG to force the Vcb to be quad-aligned.
|
|
//
|
|
|
|
union {
|
|
|
|
LIST_ENTRY VcbLinks;
|
|
LONGLONG Alignment;
|
|
};
|
|
|
|
//
|
|
// State flags and condition for the Vcb.
|
|
//
|
|
|
|
ULONG VcbState;
|
|
VCB_CONDITION VcbCondition;
|
|
|
|
//
|
|
// Various counts for this Vcb.
|
|
//
|
|
// VcbCleanup - Open handles left on this system.
|
|
// VcbReference - Number of reasons this Vcb is still present.
|
|
// VcbUserReference - Number of user file objects still present.
|
|
//
|
|
|
|
ULONG VcbCleanup;
|
|
ULONG VcbReference;
|
|
ULONG VcbUserReference;
|
|
|
|
//
|
|
// Fcb for the Volume Dasd file, root directory and the Path Table.
|
|
//
|
|
|
|
struct _FCB *VolumeDasdFcb;
|
|
struct _FCB *RootIndexFcb;
|
|
struct _FCB *PathTableFcb;
|
|
|
|
//
|
|
// Location of current session and offset of volume descriptors.
|
|
//
|
|
|
|
ULONG BaseSector;
|
|
ULONG VdSectorOffset;
|
|
ULONG PrimaryVdSectorOffset;
|
|
|
|
//
|
|
// Following is a sector from the last non-cached read of an XA file.
|
|
// Also the cooked offset on the disk.
|
|
//
|
|
|
|
PVOID XASector;
|
|
LONGLONG XADiskOffset;
|
|
|
|
//
|
|
// Vcb resource. This is used to synchronize open/cleanup/close operations.
|
|
//
|
|
|
|
ERESOURCE VcbResource;
|
|
|
|
//
|
|
// File resource. This is used to synchronize all file operations except
|
|
// open/cleanup/close.
|
|
//
|
|
|
|
ERESOURCE FileResource;
|
|
|
|
//
|
|
// Vcb fast mutex. This is used to synchronize the fields in the Vcb
|
|
// when modified when the Vcb is not held exclusively. Included here
|
|
// are the count fields and Fcb table.
|
|
//
|
|
// We also use this to synchronize changes to the Fcb reference field.
|
|
//
|
|
|
|
FAST_MUTEX VcbMutex;
|
|
PVOID VcbLockThread;
|
|
|
|
//
|
|
// The following is used to synchronize the dir notify package.
|
|
//
|
|
|
|
PNOTIFY_SYNC NotifySync;
|
|
|
|
//
|
|
// The following is the head of a list of notify Irps.
|
|
//
|
|
|
|
LIST_ENTRY DirNotifyList;
|
|
|
|
//
|
|
// Logical block size for this volume as well constant values
|
|
// associated with the block size.
|
|
//
|
|
|
|
ULONG BlockSize;
|
|
ULONG BlockToSectorShift;
|
|
ULONG BlockToByteShift;
|
|
ULONG BlocksPerSector;
|
|
ULONG BlockMask;
|
|
ULONG BlockInverseMask;
|
|
|
|
//
|
|
// Fcb table. Synchronized with the Vcb fast mutex.
|
|
//
|
|
|
|
RTL_GENERIC_TABLE FcbTable;
|
|
|
|
//
|
|
// Volume TOC. Cache this information for quick lookup.
|
|
//
|
|
|
|
PCDROM_TOC CdromToc;
|
|
ULONG TocLength;
|
|
ULONG TrackCount;
|
|
ULONG DiskFlags;
|
|
|
|
//
|
|
// Block factor to determine last session information.
|
|
//
|
|
|
|
ULONG BlockFactor;
|
|
|
|
//
|
|
// Media change count from device driver for bulletproof detection
|
|
// of media movement
|
|
//
|
|
|
|
ULONG MediaChangeCount;
|
|
|
|
//
|
|
// For raw reads, CDFS must obey the port maximum transfer restrictions.
|
|
//
|
|
|
|
ULONG MaximumTransferRawSectors;
|
|
ULONG MaximumPhysicalPages;
|
|
|
|
//
|
|
// Preallocated VPB for swapout, so we are not forced to consider
|
|
// must succeed pool.
|
|
//
|
|
|
|
PVPB SwapVpb;
|
|
|
|
} VCB;
|
|
typedef VCB *PVCB;
|
|
|
|
#define VCB_STATE_HSG (0x00000001)
|
|
#define VCB_STATE_ISO (0x00000002)
|
|
#define VCB_STATE_JOLIET (0x00000004)
|
|
#define VCB_STATE_LOCKED (0x00000010)
|
|
#define VCB_STATE_REMOVABLE_MEDIA (0x00000020)
|
|
#define VCB_STATE_CDXA (0x00000040)
|
|
#define VCB_STATE_AUDIO_DISK (0x00000080)
|
|
#define VCB_STATE_NOTIFY_REMOUNT (0x00000100)
|
|
#define VCB_STATE_VPB_NOT_ON_DEVICE (0x00000200)
|
|
|
|
|
|
//
|
|
// The Volume Device Object is an I/O system device object with a
|
|
// workqueue and an VCB record appended to the end. There are multiple
|
|
// of these records, one for every mounted volume, and are created during
|
|
// a volume mount operation. The work queue is for handling an overload
|
|
// of work requests to the volume.
|
|
//
|
|
|
|
typedef struct _VOLUME_DEVICE_OBJECT {
|
|
|
|
DEVICE_OBJECT DeviceObject;
|
|
|
|
//
|
|
// The following field tells how many requests for this volume have
|
|
// either been enqueued to ExWorker threads or are currently being
|
|
// serviced by ExWorker threads. If the number goes above
|
|
// a certain threshold, put the request on the overflow queue to be
|
|
// executed later.
|
|
//
|
|
|
|
ULONG PostedRequestCount;
|
|
|
|
//
|
|
// The following field indicates the number of IRP's waiting
|
|
// to be serviced in the overflow queue.
|
|
//
|
|
|
|
ULONG OverflowQueueCount;
|
|
|
|
//
|
|
// The following field contains the queue header of the overflow queue.
|
|
// The Overflow queue is a list of IRP's linked via the IRP's ListEntry
|
|
// field.
|
|
//
|
|
|
|
LIST_ENTRY OverflowQueue;
|
|
|
|
//
|
|
// The following spinlock protects access to all the above fields.
|
|
//
|
|
|
|
KSPIN_LOCK OverflowQueueSpinLock;
|
|
|
|
//
|
|
// This is the file system specific volume control block.
|
|
//
|
|
|
|
VCB Vcb;
|
|
|
|
} VOLUME_DEVICE_OBJECT;
|
|
typedef VOLUME_DEVICE_OBJECT *PVOLUME_DEVICE_OBJECT;
|
|
|
|
|
|
//
|
|
// The following two structures are the separate union structures for
|
|
// data and index Fcb's. The path table is actually the same structure
|
|
// as the index Fcb since it uses the first few fields.
|
|
//
|
|
|
|
typedef enum _FCB_CONDITION {
|
|
FcbGood = 1,
|
|
FcbBad,
|
|
FcbNeedsToBeVerified
|
|
} FCB_CONDITION;
|
|
|
|
typedef struct _FCB_DATA {
|
|
|
|
//
|
|
// The following field is used by the oplock module
|
|
// to maintain current oplock information.
|
|
//
|
|
|
|
OPLOCK Oplock;
|
|
|
|
//
|
|
// The following field is used by the filelock module
|
|
// to maintain current byte range locking information.
|
|
// A file lock is allocated as needed.
|
|
//
|
|
|
|
PFILE_LOCK FileLock;
|
|
|
|
} FCB_DATA;
|
|
typedef FCB_DATA *PFCB_DATA;
|
|
|
|
typedef struct _FCB_INDEX {
|
|
|
|
//
|
|
// Internal stream file.
|
|
//
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
//
|
|
// Offset of first entry in stream. This is for case where directory
|
|
// or path table does not begin on a sector boundary. This value is
|
|
// added to all offset values to determine the real offset.
|
|
//
|
|
|
|
ULONG StreamOffset;
|
|
|
|
//
|
|
// List of child fcbs.
|
|
//
|
|
|
|
LIST_ENTRY FcbQueue;
|
|
|
|
//
|
|
// Ordinal number for this directory. Combine this with the path table offset
|
|
// in the FileId and you have a starting point in the path table.
|
|
//
|
|
|
|
ULONG Ordinal;
|
|
|
|
//
|
|
// Children path table start. This is the offset in the path table
|
|
// for the first child of the directory. A value of zero indicates
|
|
// that we haven't found the first child yet. If there are no child
|
|
// directories we will position at a point in the path table so that
|
|
// subsequent searches will fail quickly.
|
|
//
|
|
|
|
ULONG ChildPathTableOffset;
|
|
ULONG ChildOrdinal;
|
|
|
|
//
|
|
// Root of splay trees for exact and ignore case prefix trees.
|
|
//
|
|
|
|
PRTL_SPLAY_LINKS ExactCaseRoot;
|
|
PRTL_SPLAY_LINKS IgnoreCaseRoot;
|
|
|
|
} FCB_INDEX;
|
|
typedef FCB_INDEX *PFCB_INDEX;
|
|
|
|
typedef struct _FCB_NONPAGED {
|
|
|
|
//
|
|
// Type and size of this record must be CDFS_NTC_FCB_NONPAGED
|
|
//
|
|
|
|
NODE_TYPE_CODE NodeTypeCode;
|
|
NODE_BYTE_SIZE NodeByteSize;
|
|
|
|
//
|
|
// The following field contains a record of special pointers used by
|
|
// MM and Cache to manipluate section objects. Note that the values
|
|
// are set outside of the file system. However the file system on an
|
|
// open/create will set the file object's SectionObject field to
|
|
// point to this field
|
|
//
|
|
|
|
SECTION_OBJECT_POINTERS SegmentObject;
|
|
|
|
//
|
|
// This is the resource structure for this Fcb.
|
|
//
|
|
|
|
ERESOURCE FcbResource;
|
|
|
|
//
|
|
// This is the FastMutex for this Fcb.
|
|
//
|
|
|
|
FAST_MUTEX FcbMutex;
|
|
|
|
//
|
|
// This is the mutex that is inserted into the FCB_ADVANCED_HEADER
|
|
// FastMutex field
|
|
//
|
|
|
|
FAST_MUTEX AdvancedFcbHeaderMutex;
|
|
|
|
} FCB_NONPAGED;
|
|
typedef FCB_NONPAGED *PFCB_NONPAGED;
|
|
|
|
//
|
|
// The Fcb/Dcb record corresponds to every open file and directory, and to
|
|
// every directory on an opened path.
|
|
//
|
|
|
|
typedef struct _FCB {
|
|
|
|
//
|
|
// The following field is used for fast I/O. It contains the node
|
|
// type code and size, indicates if fast I/O is possible, contains
|
|
// allocation, file, and valid data size, a resource, and call back
|
|
// pointers for FastIoRead and FastMdlRead.
|
|
//
|
|
//
|
|
// Node type codes for the Fcb must be one of the following.
|
|
//
|
|
// CDFS_NTC_FCB_PATH_TABLE
|
|
// CDFS_NTC_FCB_INDEX
|
|
// CDFS_NTC_FCB_DATA
|
|
//
|
|
|
|
//
|
|
// Common Fsrtl Header. The named header is for the fieldoff.c output. We
|
|
// use the unnamed header internally.
|
|
//
|
|
|
|
union{
|
|
|
|
FSRTL_ADVANCED_FCB_HEADER Header;
|
|
FSRTL_ADVANCED_FCB_HEADER;
|
|
};
|
|
|
|
//
|
|
// Vcb for this Fcb.
|
|
//
|
|
|
|
PVCB Vcb;
|
|
|
|
//
|
|
// Parent Fcb for this Fcb. This may be NULL if this file was opened
|
|
// by ID, also for the root Fcb.
|
|
//
|
|
|
|
struct _FCB *ParentFcb;
|
|
|
|
//
|
|
// Links to the queue of Fcb's in the parent.
|
|
//
|
|
|
|
LIST_ENTRY FcbLinks;
|
|
|
|
//
|
|
// FileId for this file.
|
|
//
|
|
|
|
FILE_ID FileId;
|
|
|
|
//
|
|
// Counts on this Fcb. Cleanup count represents the number of open handles
|
|
// on this Fcb. Reference count represents the number of reasons this Fcb
|
|
// is still present. It includes file objects, children Fcb and anyone
|
|
// who wants to prevent this Fcb from going away. Cleanup count is synchronized
|
|
// with the FcbResource. The reference count is synchronized with the
|
|
// VcbMutex.
|
|
//
|
|
|
|
ULONG FcbCleanup;
|
|
ULONG FcbReference;
|
|
ULONG FcbUserReference;
|
|
|
|
//
|
|
// State flags for this Fcb.
|
|
//
|
|
|
|
ULONG FcbState;
|
|
|
|
//
|
|
// NT style attributes for the Fcb.
|
|
//
|
|
|
|
ULONG FileAttributes;
|
|
|
|
//
|
|
// CDXA attributes for this file.
|
|
//
|
|
|
|
USHORT XAAttributes;
|
|
|
|
//
|
|
// File number from the system use area.
|
|
//
|
|
|
|
UCHAR XAFileNumber;
|
|
|
|
//
|
|
// This is the thread and count for the thread which has locked this
|
|
// Fcb.
|
|
//
|
|
|
|
PVOID FcbLockThread;
|
|
ULONG FcbLockCount;
|
|
|
|
//
|
|
// Pointer to the Fcb non-paged structures.
|
|
//
|
|
|
|
PFCB_NONPAGED FcbNonpaged;
|
|
|
|
//
|
|
// Share access structure.
|
|
//
|
|
|
|
SHARE_ACCESS ShareAccess;
|
|
|
|
//
|
|
// Mcb for the on disk mapping and a single map entry.
|
|
//
|
|
|
|
CD_MCB_ENTRY McbEntry;
|
|
CD_MCB Mcb;
|
|
|
|
//
|
|
// Embed the prefix entry for the longname. Store an optional pointer
|
|
// to a prefix structure for the short name.
|
|
//
|
|
|
|
PPREFIX_ENTRY ShortNamePrefix;
|
|
PREFIX_ENTRY FileNamePrefix;
|
|
|
|
//
|
|
// Time stamp for this file.
|
|
//
|
|
|
|
LONGLONG CreationTime;
|
|
|
|
union{
|
|
|
|
ULONG FcbType;
|
|
FCB_DATA;
|
|
FCB_INDEX;
|
|
};
|
|
|
|
} FCB;
|
|
typedef FCB *PFCB;
|
|
|
|
#define FCB_STATE_INITIALIZED (0x00000001)
|
|
#define FCB_STATE_IN_FCB_TABLE (0x00000002)
|
|
#define FCB_STATE_MODE2FORM2_FILE (0x00000004)
|
|
#define FCB_STATE_MODE2_FILE (0x00000008)
|
|
#define FCB_STATE_DA_FILE (0x00000010)
|
|
|
|
//
|
|
// These file types are read as raw 2352 byte sectors
|
|
//
|
|
|
|
#define FCB_STATE_RAWSECTOR_MASK ( FCB_STATE_MODE2FORM2_FILE | \
|
|
FCB_STATE_MODE2_FILE | \
|
|
FCB_STATE_DA_FILE )
|
|
|
|
#define SIZEOF_FCB_DATA \
|
|
(FIELD_OFFSET( FCB, FcbType ) + sizeof( FCB_DATA ))
|
|
|
|
#define SIZEOF_FCB_INDEX \
|
|
(FIELD_OFFSET( FCB, FcbType ) + sizeof( FCB_INDEX ))
|
|
|
|
|
|
//
|
|
// The Ccb record is allocated for every file object
|
|
//
|
|
|
|
typedef struct _CCB {
|
|
|
|
//
|
|
// Type and size of this record (must be CDFS_NTC_CCB)
|
|
//
|
|
|
|
NODE_TYPE_CODE NodeTypeCode;
|
|
NODE_BYTE_SIZE NodeByteSize;
|
|
|
|
//
|
|
// Flags. Indicates flags to apply for the current open.
|
|
//
|
|
|
|
ULONG Flags;
|
|
|
|
//
|
|
// Fcb for the file being opened.
|
|
//
|
|
|
|
PFCB Fcb;
|
|
|
|
//
|
|
// We store state information in the Ccb for a directory
|
|
// enumeration on this handle.
|
|
//
|
|
|
|
//
|
|
// Offset in the directory stream to base the next enumeration.
|
|
//
|
|
|
|
ULONG CurrentDirentOffset;
|
|
CD_NAME SearchExpression;
|
|
|
|
} CCB;
|
|
typedef CCB *PCCB;
|
|
|
|
#define CCB_FLAG_OPEN_BY_ID (0x00000001)
|
|
#define CCB_FLAG_OPEN_RELATIVE_BY_ID (0x00000002)
|
|
#define CCB_FLAG_IGNORE_CASE (0x00000004)
|
|
#define CCB_FLAG_OPEN_WITH_VERSION (0x00000008)
|
|
#define CCB_FLAG_DISMOUNT_ON_CLOSE (0x00000010)
|
|
|
|
//
|
|
// Following flags refer to index enumeration.
|
|
//
|
|
|
|
#define CCB_FLAG_ENUM_NAME_EXP_HAS_WILD (0x00010000)
|
|
#define CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD (0x00020000)
|
|
#define CCB_FLAG_ENUM_MATCH_ALL (0x00040000)
|
|
#define CCB_FLAG_ENUM_VERSION_MATCH_ALL (0x00080000)
|
|
#define CCB_FLAG_ENUM_RETURN_NEXT (0x00100000)
|
|
#define CCB_FLAG_ENUM_INITIALIZED (0x00200000)
|
|
#define CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY (0x00400000)
|
|
|
|
|
|
//
|
|
// The Irp Context record is allocated for every orginating Irp. It is
|
|
// created by the Fsd dispatch routines, and deallocated by the CdComplete
|
|
// request routine
|
|
//
|
|
|
|
typedef struct _IRP_CONTEXT {
|
|
|
|
//
|
|
// Type and size of this record (must be CDFS_NTC_IRP_CONTEXT)
|
|
//
|
|
|
|
NODE_TYPE_CODE NodeTypeCode;
|
|
NODE_BYTE_SIZE NodeByteSize;
|
|
|
|
//
|
|
// Originating Irp for the request.
|
|
//
|
|
|
|
PIRP Irp;
|
|
|
|
//
|
|
// Vcb for this operation. When this is NULL it means we were called
|
|
// with our filesystem device object instead of a volume device object.
|
|
// (Mount will fill this in once the Vcb is created)
|
|
//
|
|
|
|
PVCB Vcb;
|
|
|
|
//
|
|
// Exception encountered during the request. Any error raised explicitly by
|
|
// the file system will be stored here. Any other error raised by the system
|
|
// is stored here after normalizing it.
|
|
//
|
|
|
|
NTSTATUS ExceptionStatus;
|
|
ULONG RaisedAtLineFile;
|
|
|
|
//
|
|
// Flags for this request.
|
|
//
|
|
|
|
ULONG Flags;
|
|
|
|
//
|
|
// Real device object. This represents the physical device closest to the media.
|
|
//
|
|
|
|
PDEVICE_OBJECT RealDevice;
|
|
|
|
//
|
|
// Io context for a read request.
|
|
// Address of Fcb for teardown oplock in create case.
|
|
//
|
|
|
|
union {
|
|
|
|
struct _CD_IO_CONTEXT *IoContext;
|
|
PFCB *TeardownFcb;
|
|
};
|
|
|
|
//
|
|
// Top level irp context for this thread.
|
|
//
|
|
|
|
struct _IRP_CONTEXT *TopLevel;
|
|
|
|
//
|
|
// Major and minor function codes.
|
|
//
|
|
|
|
UCHAR MajorFunction;
|
|
UCHAR MinorFunction;
|
|
|
|
//
|
|
// Pointer to the top-level context if this IrpContext is responsible
|
|
// for cleaning it up.
|
|
//
|
|
|
|
struct _THREAD_CONTEXT *ThreadContext;
|
|
|
|
//
|
|
// This structure is used for posting to the Ex worker threads.
|
|
//
|
|
|
|
WORK_QUEUE_ITEM WorkQueueItem;
|
|
|
|
} IRP_CONTEXT;
|
|
typedef IRP_CONTEXT *PIRP_CONTEXT;
|
|
|
|
#define IRP_CONTEXT_FLAG_ON_STACK (0x00000001)
|
|
#define IRP_CONTEXT_FLAG_MORE_PROCESSING (0x00000002)
|
|
#define IRP_CONTEXT_FLAG_WAIT (0x00000004)
|
|
#define IRP_CONTEXT_FLAG_FORCE_POST (0x00000008)
|
|
#define IRP_CONTEXT_FLAG_TOP_LEVEL (0x00000010)
|
|
#define IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS (0x00000020)
|
|
#define IRP_CONTEXT_FLAG_IN_FSP (0x00000040)
|
|
#define IRP_CONTEXT_FLAG_IN_TEARDOWN (0x00000080)
|
|
#define IRP_CONTEXT_FLAG_ALLOC_IO (0x00000100)
|
|
#define IRP_CONTEXT_FLAG_DISABLE_POPUPS (0x00000200)
|
|
#define IRP_CONTEXT_FLAG_FORCE_VERIFY (0x00000400)
|
|
|
|
//
|
|
// Flags used for create.
|
|
//
|
|
|
|
#define IRP_CONTEXT_FLAG_FULL_NAME (0x10000000)
|
|
#define IRP_CONTEXT_FLAG_TRAIL_BACKSLASH (0x20000000)
|
|
|
|
//
|
|
// The following flags need to be cleared when a request is posted.
|
|
//
|
|
|
|
#define IRP_CONTEXT_FLAGS_CLEAR_ON_POST ( \
|
|
IRP_CONTEXT_FLAG_MORE_PROCESSING | \
|
|
IRP_CONTEXT_FLAG_WAIT | \
|
|
IRP_CONTEXT_FLAG_FORCE_POST | \
|
|
IRP_CONTEXT_FLAG_TOP_LEVEL | \
|
|
IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS | \
|
|
IRP_CONTEXT_FLAG_IN_FSP | \
|
|
IRP_CONTEXT_FLAG_IN_TEARDOWN | \
|
|
IRP_CONTEXT_FLAG_DISABLE_POPUPS \
|
|
)
|
|
|
|
//
|
|
// The following flags need to be cleared when a request is retried.
|
|
//
|
|
|
|
#define IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY ( \
|
|
IRP_CONTEXT_FLAG_MORE_PROCESSING | \
|
|
IRP_CONTEXT_FLAG_IN_TEARDOWN | \
|
|
IRP_CONTEXT_FLAG_DISABLE_POPUPS \
|
|
)
|
|
|
|
//
|
|
// The following flags are set each time through the Fsp loop.
|
|
//
|
|
|
|
#define IRP_CONTEXT_FSP_FLAGS ( \
|
|
IRP_CONTEXT_FLAG_WAIT | \
|
|
IRP_CONTEXT_FLAG_TOP_LEVEL | \
|
|
IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS | \
|
|
IRP_CONTEXT_FLAG_IN_FSP \
|
|
)
|
|
|
|
|
|
//
|
|
// Following structure is used to queue a request to the delayed close queue.
|
|
// This structure should be the minimum block allocation size.
|
|
//
|
|
|
|
typedef struct _IRP_CONTEXT_LITE {
|
|
|
|
//
|
|
// Type and size of this record (must be CDFS_NTC_IRP_CONTEXT_LITE)
|
|
//
|
|
|
|
NODE_TYPE_CODE NodeTypeCode;
|
|
NODE_BYTE_SIZE NodeByteSize;
|
|
|
|
//
|
|
// Fcb for the file object being closed.
|
|
//
|
|
|
|
PFCB Fcb;
|
|
|
|
//
|
|
// List entry to attach to delayed close queue.
|
|
//
|
|
|
|
LIST_ENTRY DelayedCloseLinks;
|
|
|
|
//
|
|
// User reference count for the file object being closed.
|
|
//
|
|
|
|
ULONG UserReference;
|
|
|
|
//
|
|
// Real device object. This represents the physical device closest to the media.
|
|
//
|
|
|
|
PDEVICE_OBJECT RealDevice;
|
|
|
|
} IRP_CONTEXT_LITE;
|
|
typedef IRP_CONTEXT_LITE *PIRP_CONTEXT_LITE;
|
|
|
|
|
|
//
|
|
// Context structure for asynchronous I/O calls. Most of these fields
|
|
// are actually only required for the ReadMultiple routines, but
|
|
// the caller must allocate one as a local variable anyway before knowing
|
|
// whether there are multiple requests are not. Therefore, a single
|
|
// structure is used for simplicity.
|
|
//
|
|
|
|
typedef struct _CD_IO_CONTEXT {
|
|
|
|
//
|
|
// These two fields are used for multiple run Io
|
|
//
|
|
|
|
LONG IrpCount;
|
|
PIRP MasterIrp;
|
|
NTSTATUS Status;
|
|
BOOLEAN AllocatedContext;
|
|
|
|
union {
|
|
|
|
//
|
|
// This element handles the asynchronous non-cached Io
|
|
//
|
|
|
|
struct {
|
|
|
|
PERESOURCE Resource;
|
|
ERESOURCE_THREAD ResourceThreadId;
|
|
ULONG RequestedByteCount;
|
|
};
|
|
|
|
//
|
|
// and this element handles the synchronous non-cached Io.
|
|
//
|
|
|
|
KEVENT SyncEvent;
|
|
};
|
|
|
|
} CD_IO_CONTEXT;
|
|
typedef CD_IO_CONTEXT *PCD_IO_CONTEXT;
|
|
|
|
|
|
//
|
|
// Following structure is used to track the top level request. Each Cdfs
|
|
// Fsd and Fsp entry point will examine the top level irp location in the
|
|
// thread local storage to determine if this request is top level and/or
|
|
// top level Cdfs. The top level Cdfs request will remember the previous
|
|
// value and update that location with a stack location. This location
|
|
// can be accessed by recursive Cdfs entry points.
|
|
//
|
|
|
|
typedef struct _THREAD_CONTEXT {
|
|
|
|
//
|
|
// CDFS signature. Used to confirm structure on stack is valid.
|
|
//
|
|
|
|
ULONG Cdfs;
|
|
|
|
//
|
|
// Previous value in top-level thread location. We restore this
|
|
// when done.
|
|
//
|
|
|
|
PIRP SavedTopLevelIrp;
|
|
|
|
//
|
|
// Top level Cdfs IrpContext. Initial Cdfs entry point on stack
|
|
// will store the IrpContext for the request in this stack location.
|
|
//
|
|
|
|
PIRP_CONTEXT TopLevelIrpContext;
|
|
|
|
} THREAD_CONTEXT;
|
|
typedef THREAD_CONTEXT *PTHREAD_CONTEXT;
|
|
|
|
|
|
//
|
|
// The following structure is used for enumerating the entries in the
|
|
// path table. We will always map this two sectors at a time so we don't
|
|
// have to worry about entries which span sectors. We move through
|
|
// one sector at a time though. We will unpin and remap after
|
|
// crossing a sector boundary.
|
|
//
|
|
// The only special case is where we span a cache view. In that case
|
|
// we will allocate a buffer and read both pieces into it.
|
|
//
|
|
// This strategy takes advantage of the CC enhancement which allows
|
|
// overlapping ranges.
|
|
//
|
|
|
|
typedef struct _PATH_ENUM_CONTEXT {
|
|
|
|
//
|
|
// Pointer to the current sector and the offset of this sector to
|
|
// the beginning of the path table. The Data pointer may be
|
|
// a pool block in the case where we cross a cache view
|
|
// boundary. Also the length of the data for this block.
|
|
//
|
|
|
|
PVOID Data;
|
|
ULONG BaseOffset;
|
|
ULONG DataLength;
|
|
|
|
//
|
|
// Bcb for the sector. (We may actually have pinned two sectors)
|
|
// This will be NULL for the case where we needed to allocate a
|
|
// buffer in the case where we span a cache view.
|
|
//
|
|
|
|
PBCB Bcb;
|
|
|
|
//
|
|
// Offset to current entry within the current data block.
|
|
//
|
|
|
|
ULONG DataOffset;
|
|
|
|
//
|
|
// Did we allocate the buffer for the entry.
|
|
//
|
|
|
|
BOOLEAN AllocatedData;
|
|
|
|
//
|
|
// End of Path Table. This tells us whether the current data
|
|
// block includes the end of the path table. This is the
|
|
// only block where we need to do a careful check about whether
|
|
// the path table entry fits into the buffer.
|
|
//
|
|
// Also once we have reached the end of the path table we don't
|
|
// need to remap the data as we move into the final sector.
|
|
// We always look at the last two sectors together.
|
|
//
|
|
|
|
BOOLEAN LastDataBlock;
|
|
|
|
} PATH_ENUM_CONTEXT;
|
|
typedef PATH_ENUM_CONTEXT *PPATH_ENUM_CONTEXT;
|
|
|
|
#define VACB_MAPPING_MASK (VACB_MAPPING_GRANULARITY - 1)
|
|
#define LAST_VACB_SECTOR_OFFSET (VACB_MAPPING_GRANULARITY - SECTOR_SIZE)
|
|
|
|
|
|
//
|
|
// Path Entry. This is our representation of the on disk data.
|
|
//
|
|
|
|
typedef struct _PATH_ENTRY {
|
|
|
|
//
|
|
// Directory number and offset. This is the ordinal and the offset from
|
|
// the beginning of the path table stream for this entry.
|
|
//
|
|
//
|
|
|
|
ULONG Ordinal;
|
|
ULONG PathTableOffset;
|
|
|
|
//
|
|
// Logical block Offset on the disk for this entry. We already bias
|
|
// this by any Xar blocks.
|
|
//
|
|
|
|
ULONG DiskOffset;
|
|
|
|
//
|
|
// Length of on-disk path table entry.
|
|
//
|
|
|
|
ULONG PathEntryLength;
|
|
|
|
//
|
|
// Parent number.
|
|
//
|
|
|
|
ULONG ParentOrdinal;
|
|
|
|
//
|
|
// DirName length and Id. Typically the pointer here points to the raw on-disk
|
|
// bytes. We will point to a fixed self entry if this is the root directory.
|
|
//
|
|
|
|
ULONG DirNameLen;
|
|
PCHAR DirName;
|
|
|
|
//
|
|
// Following are the flags used to cleanup this structure.
|
|
//
|
|
|
|
ULONG Flags;
|
|
|
|
//
|
|
// The following is the filename string and version number strings. We embed a buffer
|
|
// large enough to hold two 8.3 names. One for exact case and one for case insensitive.
|
|
//
|
|
|
|
CD_NAME CdDirName;
|
|
CD_NAME CdCaseDirName;
|
|
|
|
WCHAR NameBuffer[BYTE_COUNT_EMBEDDED_NAME / sizeof( WCHAR ) * 2];
|
|
|
|
} PATH_ENTRY;
|
|
typedef PATH_ENTRY *PPATH_ENTRY;
|
|
|
|
#define PATH_ENTRY_FLAG_ALLOC_BUFFER (0x00000001)
|
|
|
|
|
|
//
|
|
// Compound path entry. This structure combines the on-disk entries
|
|
// with the in-memory structures.
|
|
//
|
|
|
|
typedef struct _COMPOUND_PATH_ENTRY {
|
|
|
|
PATH_ENUM_CONTEXT PathContext;
|
|
PATH_ENTRY PathEntry;
|
|
|
|
} COMPOUND_PATH_ENTRY;
|
|
typedef COMPOUND_PATH_ENTRY *PCOMPOUND_PATH_ENTRY;
|
|
|
|
|
|
//
|
|
// The following is used for enumerating through a directory via the
|
|
// dirents.
|
|
//
|
|
|
|
typedef struct _DIRENT_ENUM_CONTEXT {
|
|
|
|
//
|
|
// Pointer the current sector and the offset of this sector within
|
|
// the directory file. Also the data length of this pinned block.
|
|
//
|
|
|
|
PVOID Sector;
|
|
ULONG BaseOffset;
|
|
ULONG DataLength;
|
|
|
|
//
|
|
// Bcb for the sector.
|
|
//
|
|
|
|
PBCB Bcb;
|
|
|
|
//
|
|
// Offset to the current dirent within this sector.
|
|
//
|
|
|
|
ULONG SectorOffset;
|
|
|
|
//
|
|
// Length to next dirent. A zero indicates to move to the next sector.
|
|
//
|
|
|
|
ULONG NextDirentOffset;
|
|
|
|
} DIRENT_ENUM_CONTEXT;
|
|
typedef DIRENT_ENUM_CONTEXT *PDIRENT_ENUM_CONTEXT;
|
|
|
|
|
|
//
|
|
// Following structure is used to smooth out the differences in the HSG, ISO
|
|
// and Joliett directory entries.
|
|
//
|
|
|
|
typedef struct _DIRENT {
|
|
|
|
//
|
|
// Offset in the Directory of this entry. Note this includes
|
|
// any bytes added to the beginning of the directory to pad
|
|
// down to a sector boundary.
|
|
//
|
|
|
|
ULONG DirentOffset;
|
|
|
|
ULONG DirentLength;
|
|
|
|
//
|
|
// Starting offset on the disk including any Xar blocks.
|
|
//
|
|
|
|
ULONG StartingOffset;
|
|
|
|
//
|
|
// DataLength of the data. If not the last block then this should
|
|
// be an integral number of logical blocks.
|
|
//
|
|
|
|
ULONG DataLength;
|
|
|
|
//
|
|
// The following field is the time stamp out of the directory entry.
|
|
// Use a pointer into the dirent for this.
|
|
//
|
|
|
|
PCHAR CdTime;
|
|
|
|
//
|
|
// The following field is the dirent file flags field.
|
|
//
|
|
|
|
UCHAR DirentFlags;
|
|
|
|
//
|
|
// Following field is a Cdfs flag field used to clean up this structure.
|
|
//
|
|
|
|
UCHAR Flags;
|
|
|
|
//
|
|
// The following fields indicate the file unit size and interleave gap
|
|
// for interleaved files. Each of these are in logical blocks.
|
|
//
|
|
|
|
ULONG FileUnitSize;
|
|
ULONG InterleaveGapSize;
|
|
|
|
//
|
|
// System use offset. Zero value indicates no system use area.
|
|
//
|
|
|
|
ULONG SystemUseOffset;
|
|
|
|
//
|
|
// CDXA attributes and file number for this file.
|
|
//
|
|
|
|
USHORT XAAttributes;
|
|
UCHAR XAFileNumber;
|
|
|
|
//
|
|
// Filename length and ID. We copy the length (in bytes) and keep
|
|
// a pointer to the start of the name.
|
|
//
|
|
|
|
ULONG FileNameLen;
|
|
PCHAR FileName;
|
|
|
|
//
|
|
// The following are the filenames stored by name and version numbers.
|
|
// The fixed buffer here can hold two Unicode 8.3 names. This allows
|
|
// us to upcase the name into a fixed buffer.
|
|
//
|
|
|
|
CD_NAME CdFileName;
|
|
CD_NAME CdCaseFileName;
|
|
|
|
//
|
|
// Data stream type. Indicates if this is audio, XA mode2 form2 or cooked sectors.
|
|
//
|
|
|
|
XA_EXTENT_TYPE ExtentType;
|
|
|
|
WCHAR NameBuffer[BYTE_COUNT_EMBEDDED_NAME / sizeof( WCHAR ) * 2];
|
|
|
|
} DIRENT;
|
|
typedef DIRENT *PDIRENT;
|
|
|
|
#define DIRENT_FLAG_ALLOC_BUFFER (0x01)
|
|
#define DIRENT_FLAG_CONSTANT_ENTRY (0x02)
|
|
|
|
#define DIRENT_FLAG_NOT_PERSISTENT (0)
|
|
|
|
|
|
//
|
|
// Following structure combines the on-disk information with the normalized
|
|
// structure.
|
|
//
|
|
|
|
typedef struct _COMPOUND_DIRENT {
|
|
|
|
DIRENT_ENUM_CONTEXT DirContext;
|
|
DIRENT Dirent;
|
|
|
|
} COMPOUND_DIRENT;
|
|
typedef COMPOUND_DIRENT *PCOMPOUND_DIRENT;
|
|
|
|
|
|
//
|
|
// The following structure is used to enumerate the files in a directory.
|
|
// It contains three DirContext/Dirent pairs and then self pointers to
|
|
// know which of these is begin used how.
|
|
//
|
|
|
|
typedef struct _FILE_ENUM_CONTEXT {
|
|
|
|
//
|
|
// Pointers to the current compound dirents below.
|
|
//
|
|
// PriorDirent - Initial dirent for the last file encountered.
|
|
// InitialDirent - Initial dirent for the current file.
|
|
// CurrentDirent - Second or later dirent for the current file.
|
|
//
|
|
|
|
PCOMPOUND_DIRENT PriorDirent;
|
|
PCOMPOUND_DIRENT InitialDirent;
|
|
PCOMPOUND_DIRENT CurrentDirent;
|
|
|
|
//
|
|
// Flags indicating the state of the search.
|
|
//
|
|
|
|
ULONG Flags;
|
|
|
|
//
|
|
// This is an accumulation of the file sizes of the different extents
|
|
// of a single file.
|
|
//
|
|
|
|
LONGLONG FileSize;
|
|
|
|
//
|
|
// Short name for this file.
|
|
//
|
|
|
|
CD_NAME ShortName;
|
|
WCHAR ShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof( WCHAR ) ];
|
|
|
|
//
|
|
// Array of compound dirents.
|
|
//
|
|
|
|
COMPOUND_DIRENT Dirents[3];
|
|
|
|
} FILE_ENUM_CONTEXT;
|
|
typedef FILE_ENUM_CONTEXT *PFILE_ENUM_CONTEXT;
|
|
|
|
#define FILE_CONTEXT_MULTIPLE_DIRENTS (0x00000001)
|
|
|
|
|
|
//
|
|
// RIFF header. Prepended to the data of a file containing XA sectors.
|
|
// This is a hard-coded structure except that we bias the 'ChunkSize' and
|
|
// 'RawSectors' fields with the file size. We also copy the attributes flag
|
|
// from the system use area in the dirent. We always initialize this
|
|
// structure by copying the XAFileHeader.
|
|
//
|
|
|
|
typedef struct _RIFF_HEADER {
|
|
|
|
ULONG ChunkId;
|
|
LONG ChunkSize;
|
|
ULONG SignatureCDXA;
|
|
ULONG SignatureFMT;
|
|
ULONG XAChunkSize;
|
|
ULONG OwnerId;
|
|
USHORT Attributes;
|
|
USHORT SignatureXA;
|
|
UCHAR FileNumber;
|
|
UCHAR Reserved[7];
|
|
ULONG SignatureData;
|
|
ULONG RawSectors;
|
|
|
|
} RIFF_HEADER;
|
|
typedef RIFF_HEADER *PRIFF_HEADER;
|
|
|
|
//
|
|
// Audio play header for CDDA tracks.
|
|
//
|
|
|
|
typedef struct _AUDIO_PLAY_HEADER {
|
|
|
|
ULONG Chunk;
|
|
ULONG ChunkSize;
|
|
ULONG SignatureCDDA;
|
|
ULONG SignatureFMT;
|
|
ULONG FMTChunkSize;
|
|
USHORT FormatTag;
|
|
USHORT TrackNumber;
|
|
ULONG DiskID;
|
|
ULONG StartingSector;
|
|
ULONG SectorCount;
|
|
UCHAR TrackAddress[4];
|
|
UCHAR TrackLength[4];
|
|
|
|
} AUDIO_PLAY_HEADER;
|
|
typedef AUDIO_PLAY_HEADER *PAUDIO_PLAY_HEADER;
|
|
|
|
|
|
//
|
|
// Some macros for supporting the use of a Generic Table
|
|
// containing all the FCB/DCBs and indexed by their FileId.
|
|
//
|
|
// For directories:
|
|
//
|
|
// The HighPart contains the path table offset of this directory in the
|
|
// path table.
|
|
//
|
|
// The LowPart contains zero except for the upper bit which is
|
|
// set to indicate that this is a directory.
|
|
//
|
|
// For files:
|
|
//
|
|
// The HighPart contains the path table offset of the parent directory
|
|
// in the path table.
|
|
//
|
|
// The LowPart contains the byte offset of the dirent in the parent
|
|
// directory file.
|
|
//
|
|
// A directory is always entered into the Fcb Table as if it's
|
|
// dirent offset was zero. This enables any child to look in the FcbTable
|
|
// for it's parent by searching with the same HighPart but with zero
|
|
// as the value for LowPart.
|
|
//
|
|
// The Id field is a LARGE_INTEGER where the High and Low parts can be
|
|
// accessed separately.
|
|
//
|
|
// The following macros are used to access the Fid fields.
|
|
//
|
|
// CdQueryFidDirentOffset - Accesses the Dirent offset field
|
|
// CdQueryFidPathTableNumber - Accesses the PathTable offset field
|
|
// CdSetFidDirentOffset - Sets the Dirent offset field
|
|
// CdSetFidPathTableNumber - Sets the PathTable ordinal field
|
|
// CdFidIsDirectory - Queries if directory bit is set
|
|
// CdFidSetDirectory - Sets directory bit
|
|
//
|
|
|
|
#define FID_DIR_MASK 0x80000000 // high order bit means directory.
|
|
|
|
#define CdQueryFidDirentOffset(I) ((I).LowPart & ~FID_DIR_MASK)
|
|
#define CdQueryFidPathTableOffset(I) ((I).HighPart)
|
|
#define CdSetFidDirentOffset(I,D) ((I).LowPart = D)
|
|
#define CdSetFidPathTableOffset(I,P) ((I).HighPart = P)
|
|
#define CdFidIsDirectory(I) FlagOn( (I).LowPart, FID_DIR_MASK )
|
|
#define CdFidSetDirectory(I) SetFlag( (I).LowPart, FID_DIR_MASK )
|
|
|
|
#define CdSetFidFromParentAndDirent(I,F,D) { \
|
|
CdSetFidPathTableOffset( (I), CdQueryFidPathTableOffset( (F)->FileId )); \
|
|
CdSetFidDirentOffset( (I), (D)->DirentOffset ); \
|
|
if (FlagOn( (D)->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) { \
|
|
CdFidSetDirectory((I)); \
|
|
} \
|
|
}
|
|
|
|
#endif // _CDSTRUC_
|