/*++

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_