599 lines
13 KiB
C
599 lines
13 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
msstruc.h
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module defines the data structures that make up the major internal
|
|||
|
part of the mailslot file system.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Manny Weiser (mannyw) 7-Jan-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#ifndef _MSSTRUC_
|
|||
|
#define _MSSTRUC_
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The VCB record is the top record in the mailslot file system in-memory
|
|||
|
// data structure. This structure must be allocated from non-paged pool
|
|||
|
// and immediately follows (in memory) the Device object for the mailslot
|
|||
|
// Structurally the layout of the data structure is as follows
|
|||
|
//
|
|||
|
// +------------+
|
|||
|
// |MSDO |
|
|||
|
// | |
|
|||
|
// +------------+
|
|||
|
// |Vcb |
|
|||
|
// | |
|
|||
|
// | |
|
|||
|
// +------------+
|
|||
|
// | ^
|
|||
|
// | |
|
|||
|
// | |
|
|||
|
// v |
|
|||
|
// +-------------+
|
|||
|
// |RootDcb |
|
|||
|
// | |<-+
|
|||
|
// +-------------+ |
|
|||
|
// : |
|
|||
|
// : |
|
|||
|
// : |
|
|||
|
// v |
|
|||
|
// +----------------+ +-------------------+
|
|||
|
// |Fcb | |Ccb |
|
|||
|
// | |<---| |
|
|||
|
// | | | |
|
|||
|
// +----------------+ +-------------------+
|
|||
|
// ^ ^
|
|||
|
// | |
|
|||
|
// +---------+ +---------+
|
|||
|
// |Server FO| |Client FO|
|
|||
|
// | | | |
|
|||
|
// +---------+ +---------+
|
|||
|
//
|
|||
|
//
|
|||
|
// Where there is only one VCB for the entire mailslot file system, and
|
|||
|
// it contains a single pointer to the root DCB for the file system. Off
|
|||
|
// of the DCB is a queue of FCB's. There is one FCB for every mailslot.
|
|||
|
// There are also two additional CCB types for the VCB and the root DCB,
|
|||
|
// and notify records for the notify change operations.
|
|||
|
//
|
|||
|
// A newly initialized mailslot file system only contains the VCB and
|
|||
|
// the root DCB. A new FCB is created when a new mailslot is created
|
|||
|
// The file object for the creater (i.e., server end) points to the FCB
|
|||
|
// and indicates that it is the server end. When a user does an open on
|
|||
|
// the mailslot its file object is set to point to a CCB which belongs
|
|||
|
// to the FCB.
|
|||
|
//
|
|||
|
// A file object with a null pointer to the FsContext field is a closed or
|
|||
|
// disconnected mailslot.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Each Fcb has a data queues for holding the outstanding
|
|||
|
// read/write requests. The following type is used to determine
|
|||
|
// if the data queue contains read requests, write requests, or is empty.
|
|||
|
//
|
|||
|
|
|||
|
typedef enum _QUEUE_STATE {
|
|||
|
ReadEntries,
|
|||
|
WriteEntries,
|
|||
|
Empty
|
|||
|
} QUEUE_STATE;
|
|||
|
|
|||
|
//
|
|||
|
// The node state.
|
|||
|
//
|
|||
|
// Currently only 2 states are defined. When a node is created it's state
|
|||
|
// is NodeStateActive. When a cleanup IRP is processed, it set the node
|
|||
|
// state of the corresponding node to NodeStateClosing. Only the close
|
|||
|
// IRP can get processed on this node.
|
|||
|
//
|
|||
|
|
|||
|
typedef enum _NODE_STATE {
|
|||
|
NodeStateActive,
|
|||
|
NodeStateClosing
|
|||
|
} NODE_STATE;
|
|||
|
|
|||
|
//
|
|||
|
// The types of data entry there are. Each corresponds to an IRP
|
|||
|
// that can be added to a data queue.
|
|||
|
//
|
|||
|
|
|||
|
typedef enum _ENTRY_TYPE {
|
|||
|
Read,
|
|||
|
ReadMailslot,
|
|||
|
Write,
|
|||
|
WriteMailslot,
|
|||
|
Peek
|
|||
|
} ENTRY_TYPE;
|
|||
|
|
|||
|
//
|
|||
|
// The data queue is a structure that contains the queue state, quota
|
|||
|
// information, and the list head. The quota information is used to
|
|||
|
// maintain mailslot quota.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _DATA_QUEUE {
|
|||
|
|
|||
|
//
|
|||
|
// The current state of what is contained in this data queue,
|
|||
|
// how many bytes of read/write data there are, and how many individual
|
|||
|
// requests there are in the queue that contain data (includes
|
|||
|
// close or flush requests).
|
|||
|
//
|
|||
|
|
|||
|
QUEUE_STATE QueueState;
|
|||
|
ULONG BytesInQueue;
|
|||
|
ULONG EntriesInQueue;
|
|||
|
|
|||
|
//
|
|||
|
// The following two fields denote who much quota was reserved for
|
|||
|
// this mailslot and how much we've used up. This is only
|
|||
|
// the creator quota and not the user quota.
|
|||
|
//
|
|||
|
|
|||
|
ULONG Quota;
|
|||
|
ULONG QuotaUsed;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The size of the largest message that can be written to
|
|||
|
// this data queue.
|
|||
|
//
|
|||
|
|
|||
|
ULONG MaximumMessageSize;
|
|||
|
|
|||
|
//
|
|||
|
// The queue of data entries.
|
|||
|
//
|
|||
|
|
|||
|
LIST_ENTRY DataEntryList;
|
|||
|
|
|||
|
|
|||
|
} DATA_QUEUE, *PDATA_QUEUE;
|
|||
|
|
|||
|
//
|
|||
|
// The following type is used to denote where we got the memory for the
|
|||
|
// data entry and possibly the data buffer. We either got the memory
|
|||
|
// from the mailslot quota, the user quota, or it is part of the next IRP
|
|||
|
// stack location.
|
|||
|
//
|
|||
|
|
|||
|
typedef enum _FROM {
|
|||
|
MailslotQuota,
|
|||
|
UserQuota,
|
|||
|
InIrp
|
|||
|
} FROM;
|
|||
|
|
|||
|
//
|
|||
|
// Each entry in the data queue is a data entry. Processing an IRP
|
|||
|
// has the potential of creating and inserting a new data entry. If the
|
|||
|
// memory for the entry is taken from the IRP we use the current stack
|
|||
|
// location.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _DATA_ENTRY {
|
|||
|
|
|||
|
//
|
|||
|
// Where the data buffer came from
|
|||
|
//
|
|||
|
|
|||
|
UCHAR From;
|
|||
|
CHAR Spare1;
|
|||
|
USHORT Spare2;
|
|||
|
|
|||
|
//
|
|||
|
// The following field is how we connect into the queue of data entries
|
|||
|
//
|
|||
|
|
|||
|
LIST_ENTRY ListEntry;
|
|||
|
|
|||
|
//
|
|||
|
// The following field indicates if we still have an IRP associated
|
|||
|
// with this data entry that need to be completed when the remove
|
|||
|
// the data entry. Note that if From is InIrp that this IRP field
|
|||
|
// must not be null.
|
|||
|
//
|
|||
|
|
|||
|
PIRP Irp;
|
|||
|
|
|||
|
//
|
|||
|
// The following two fields describe the size and location of the data
|
|||
|
// buffer described by this entry. These fields are only used if the
|
|||
|
// type is buffered, and are ignored otherwise.
|
|||
|
//
|
|||
|
|
|||
|
ULONG DataSize;
|
|||
|
PVOID DataPointer;
|
|||
|
|
|||
|
//
|
|||
|
// Used for read data entries only. A pointer to the work context
|
|||
|
// of the time out.
|
|||
|
//
|
|||
|
|
|||
|
struct _WORK_CONTEXT *TimeoutWorkContext;
|
|||
|
|
|||
|
} DATA_ENTRY, *PDATA_ENTRY;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The node header is used to manage standard nodes within MSFS.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _NODE_HEADER {
|
|||
|
|
|||
|
NODE_TYPE_CODE NodeTypeCode; // The node type
|
|||
|
NODE_BYTE_SIZE NodeByteSize; // The size of the node
|
|||
|
NODE_STATE NodeState; // The current node state
|
|||
|
ULONG ReferenceCount; // Number of active references to the node
|
|||
|
|
|||
|
} NODE_HEADER, *PNODE_HEADER;
|
|||
|
|
|||
|
typedef struct _VCB {
|
|||
|
|
|||
|
NODE_HEADER Header;
|
|||
|
|
|||
|
//
|
|||
|
// The filesystem name
|
|||
|
//
|
|||
|
|
|||
|
UNICODE_STRING FileSystemName;
|
|||
|
|
|||
|
//
|
|||
|
// The time we created the volume
|
|||
|
//
|
|||
|
LARGE_INTEGER CreationTime;
|
|||
|
|
|||
|
//
|
|||
|
// A pointer to the root DCB for this volume
|
|||
|
//
|
|||
|
|
|||
|
struct _FCB *RootDcb;
|
|||
|
|
|||
|
//
|
|||
|
// A prefix table that is used for quick, prefix directed, lookup of
|
|||
|
// FCBs/DCBs that are part of this volume
|
|||
|
//
|
|||
|
|
|||
|
UNICODE_PREFIX_TABLE PrefixTable;
|
|||
|
|
|||
|
//
|
|||
|
// A resource variable to control access to the volume specific data
|
|||
|
// structures
|
|||
|
//
|
|||
|
|
|||
|
ERESOURCE Resource;
|
|||
|
|
|||
|
//
|
|||
|
// The following field is used to check share access people who want
|
|||
|
// to open the mailslot driver
|
|||
|
//
|
|||
|
|
|||
|
SHARE_ACCESS ShareAccess;
|
|||
|
|
|||
|
} VCB, *PVCB;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The Mailslot Device Object is an I/O system device object with
|
|||
|
// additional workqueue parameters appended to the end. There is only
|
|||
|
// one of these records created for the entire system during system
|
|||
|
// initialization. The workqueue is used by the FSD to post requests to
|
|||
|
// the filesystem.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _MSFS_DEVICE_OBJECT {
|
|||
|
|
|||
|
DEVICE_OBJECT DeviceObject;
|
|||
|
|
|||
|
//
|
|||
|
// This is the file system specific volume control block.
|
|||
|
//
|
|||
|
|
|||
|
VCB Vcb;
|
|||
|
|
|||
|
} MSFS_DEVICE_OBJECT, *PMSFS_DEVICE_OBJECT;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The Fcb/Dcb record corresponds to every opened mailslot and directory,
|
|||
|
// and to every directory on an opened path.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _FCB {
|
|||
|
|
|||
|
//
|
|||
|
// Header.NodeTypeCode of this record (must be MSFS_NTC_FCB, or
|
|||
|
// MSFS_NTC_ROOT_DCB)
|
|||
|
//
|
|||
|
|
|||
|
NODE_HEADER Header;
|
|||
|
|
|||
|
//
|
|||
|
// The links for the queue of all fcbs for a specific DCB off of
|
|||
|
// Dcb.ParentDcbQueue. For the root directory this queue is empty.
|
|||
|
//
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
//
|
|||
|
// Back pointer to the server's file object.
|
|||
|
//
|
|||
|
|
|||
|
PFILE_OBJECT FileObject;
|
|||
|
|
|||
|
//
|
|||
|
// A pointer to the security descriptor for this mailslot.
|
|||
|
//
|
|||
|
|
|||
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
|||
|
|
|||
|
//
|
|||
|
// The following union is cased off of the node type code for the FCB.
|
|||
|
// is a seperate case for the directory versus file FCBs.
|
|||
|
//
|
|||
|
|
|||
|
union {
|
|||
|
|
|||
|
//
|
|||
|
// A Directory Control Block (DCB)
|
|||
|
//
|
|||
|
|
|||
|
struct {
|
|||
|
|
|||
|
//
|
|||
|
// A queue of the notify IRPs that will be completed when any
|
|||
|
// change is made to a file in the directory. Queued using
|
|||
|
// the Tail.Overlay.ListEntry of the IRP.
|
|||
|
//
|
|||
|
|
|||
|
LIST_ENTRY NotifyFullQueue;
|
|||
|
|
|||
|
//
|
|||
|
// A queue of the notify IRPs that will be completed only if a
|
|||
|
// file is added, deleted, or renamed in the directory. Queued
|
|||
|
// using the Tail.Overlay.ListEntry of the IRP.
|
|||
|
//
|
|||
|
|
|||
|
LIST_ENTRY NotifyPartialQueue;
|
|||
|
|
|||
|
//
|
|||
|
// A queue of all the FCBs/DCBs that are opened under this
|
|||
|
// DCB.
|
|||
|
//
|
|||
|
|
|||
|
LIST_ENTRY ParentDcbQueue;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Spinlock to protect the queues above that contain cancelable IRPs. We can't
|
|||
|
// synchronize with a resource because IoCancelIrp can be called at DISPATCH_LEVEL.
|
|||
|
//
|
|||
|
|
|||
|
KSPIN_LOCK SpinLock;
|
|||
|
} Dcb;
|
|||
|
|
|||
|
//
|
|||
|
// A File Control Block (FCB)
|
|||
|
//
|
|||
|
|
|||
|
struct {
|
|||
|
|
|||
|
//
|
|||
|
// The following field is a queue head for a list of CCBs
|
|||
|
// that are opened under us.
|
|||
|
//
|
|||
|
|
|||
|
LIST_ENTRY CcbQueue;
|
|||
|
|
|||
|
//
|
|||
|
// The default read timeout. This is always a relative value.
|
|||
|
//
|
|||
|
|
|||
|
LARGE_INTEGER ReadTimeout;
|
|||
|
|
|||
|
//
|
|||
|
// File timestamps.
|
|||
|
//
|
|||
|
|
|||
|
LARGE_INTEGER CreationTime;
|
|||
|
LARGE_INTEGER LastModificationTime;
|
|||
|
LARGE_INTEGER LastAccessTime;
|
|||
|
LARGE_INTEGER LastChangeTime;
|
|||
|
|
|||
|
} Fcb;
|
|||
|
|
|||
|
} Specific;
|
|||
|
|
|||
|
//
|
|||
|
// The following field is used to check share access for
|
|||
|
// clients that want to open the file/directory.
|
|||
|
//
|
|||
|
|
|||
|
SHARE_ACCESS ShareAccess;
|
|||
|
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
|
|||
|
UNICODE_STRING FullFileName;
|
|||
|
UNICODE_STRING LastFileName;
|
|||
|
|
|||
|
//
|
|||
|
// The following field contains a prefix table entry that is used when
|
|||
|
// searching a volume for a name (or longest matching prefix)
|
|||
|
//
|
|||
|
|
|||
|
UNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The following field is used to remember the process that created this
|
|||
|
// mailslot. It is needed to allocate quota and return quota.
|
|||
|
//
|
|||
|
|
|||
|
PEPROCESS CreatorProcess;
|
|||
|
|
|||
|
//
|
|||
|
// The following data queue is used to contain the buffered information
|
|||
|
// for the mailslot.
|
|||
|
//
|
|||
|
|
|||
|
DATA_QUEUE DataQueue;
|
|||
|
|
|||
|
//
|
|||
|
// A resource variable to control access to the File specific data
|
|||
|
// structures
|
|||
|
//
|
|||
|
|
|||
|
ERESOURCE Resource;
|
|||
|
|
|||
|
} FCB, DCB, ROOT_DCB, *PFCB, *PDCB, *PROOT_DCB;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The CCB record is allocated for every cliennt side open of a mailslot.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _CCB {
|
|||
|
|
|||
|
//
|
|||
|
// Header.NodeTypeCode of this record (must be MSFS_NTC_CCB).
|
|||
|
//
|
|||
|
|
|||
|
NODE_HEADER Header;
|
|||
|
|
|||
|
//
|
|||
|
// The following field is a list entry for the list of ccb that we
|
|||
|
// are a member of.
|
|||
|
//
|
|||
|
|
|||
|
LIST_ENTRY CcbLinks;
|
|||
|
|
|||
|
//
|
|||
|
// A pointer to the FCB, or VCB that we are tied to
|
|||
|
//
|
|||
|
|
|||
|
PFCB Fcb;
|
|||
|
|
|||
|
//
|
|||
|
// Pointers to the file object of the client has opened this file.
|
|||
|
//
|
|||
|
|
|||
|
PFILE_OBJECT FileObject;
|
|||
|
|
|||
|
//
|
|||
|
// A resource to control access to the CCB.
|
|||
|
//
|
|||
|
|
|||
|
ERESOURCE Resource;
|
|||
|
|
|||
|
} CCB, *PCCB;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The root DCB CCB record is allocated for every opened instance of the
|
|||
|
// root dcb. This record is pointed at by FsContext2.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _ROOT_DCB_CCB {
|
|||
|
|
|||
|
//
|
|||
|
// Header.NodeTypeCode of this record (must be MSFS_NTC_ROOT_DCB_CCB).
|
|||
|
//
|
|||
|
|
|||
|
NODE_HEADER Header;
|
|||
|
|
|||
|
//
|
|||
|
// A pointer to the VCB containing this CCB.
|
|||
|
//
|
|||
|
|
|||
|
PVCB Vcb;
|
|||
|
|
|||
|
//
|
|||
|
// Pointer to the DCB for this CCB
|
|||
|
//
|
|||
|
PROOT_DCB Dcb;
|
|||
|
|
|||
|
//
|
|||
|
// The following field is a count of the last index returned
|
|||
|
// by query directory.
|
|||
|
//
|
|||
|
|
|||
|
ULONG IndexOfLastCcbReturned;
|
|||
|
|
|||
|
//
|
|||
|
// The following string is used as a query template for directory
|
|||
|
// query operations
|
|||
|
//
|
|||
|
|
|||
|
PUNICODE_STRING QueryTemplate;
|
|||
|
|
|||
|
} ROOT_DCB_CCB, *PROOT_DCB_CCB;
|
|||
|
|
|||
|
//
|
|||
|
// A work context contains the information needed to do read timeouts.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _WORK_CONTEXT {
|
|||
|
|
|||
|
//
|
|||
|
// Pointer to unload safe work item.
|
|||
|
//
|
|||
|
|
|||
|
PIO_WORKITEM WorkItem;
|
|||
|
|
|||
|
//
|
|||
|
// A pointer to the IRP for this operation.
|
|||
|
//
|
|||
|
|
|||
|
PIRP Irp;
|
|||
|
|
|||
|
//
|
|||
|
// A referenced pointer to the FCB that will process this operation.
|
|||
|
//
|
|||
|
|
|||
|
PFCB Fcb;
|
|||
|
|
|||
|
//
|
|||
|
// A timer and dpc tourine to accomplish the timeout.
|
|||
|
//
|
|||
|
|
|||
|
KTIMER Timer;
|
|||
|
|
|||
|
KDPC Dpc;
|
|||
|
|
|||
|
} WORK_CONTEXT, *PWORK_CONTEXT;
|
|||
|
|
|||
|
#endif // _MSSTRUC_
|