/*
 * Copyright (c) Likewise Software.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.  You should have received a copy of the GNU General
 * Public License along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
 * TERMS AS WELL.  IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
 * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
 * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
 * GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE.  IF YOU
 * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
 * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
 * license@likewise.com
 */

/*
 * Module Name:
 *
 *        iodriver.h
 *
 * Abstract:
 *
 *        IO Manager Driver Header File
 *
 * Authors: Danilo Almeida (dalmeida@likewisesoftware.com)
 *
 */

#ifndef __IODRIVER_H__
#define __IODRIVER_H__

/**
 * @file lwio/iodriver.h
 * @brief Likewise Driver API
 */

#include <lwio/io-types.h>
#include <lw/mapsecurity-types.h>
#include <lwio/lwzct.h>

LW_BEGIN_EXTERN_C

/**
 * @defgroup iodriver Driver API
 * @ingroup server
 * @brief Driver API
 *
 * The driver API is consumed by loadable drivers in order to register
 * devices, receive I/O requests, and manage driver-side state associated
 * with open file handles and outstanding operations.
 *
 * To issue requests to other loaded drivers, use the @ref ioapi "Iomgr API" instead.
 */

/*@{*/

struct _IO_DRIVER_OBJECT;
typedef struct _IO_DRIVER_OBJECT IO_DRIVER_OBJECT, *PIO_DRIVER_OBJECT;
typedef IO_DRIVER_OBJECT *IO_DRIVER_HANDLE, **PIO_DRIVER_HANDLE;

struct _IO_DEVICE_OBJECT;
typedef struct _IO_DEVICE_OBJECT IO_DEVICE_OBJECT, *PIO_DEVICE_OBJECT;
typedef IO_DEVICE_OBJECT *IO_DEVICE_HANDLE, **PIO_DEVICE_HANDLE;

/**
 * @name IRP Types
 */

/**@{*/

/**
 * @brief IRP type
 *
 * Specifies which type of IRP this is.  The IRP type determines which IRP args
 * structure is in the #IRP.
 * - #IRP_TYPE_UNINITIALIZED
 * - #IRP_TYPE_CREATE
 * - #IRP_TYPE_CLOSE
 * - #IRP_TYPE_READ
 * - #IRP_TYPE_WRITE
 * - #IRP_TYPE_DEVICE_IO_CONTROL
 * - #IRP_TYPE_FS_CONTROL
 * - #IRP_TYPE_FLUSH_BUFFERS
 * - #IRP_TYPE_QUERY_INFORMATION
 * - #IRP_TYPE_SET_INFORMATION
 * - #IRP_TYPE_CREATE_NAMED_PIPE
 * - #IRP_TYPE_CREATE_MAILSLOT
 * - #IRP_TYPE_QUERY_DIRECTORY
 * - #IRP_TYPE_READ_DIRECTORY_CHANGE
 * - #IRP_TYPE_QUERY_VOLUME_INFORMATION
 * - #IRP_TYPE_SET_VOLUME_INFORMATION
 * - #IRP_TYPE_LOCK_CONTROL
 * - #IRP_TYPE_QUERY_SECURITY
 * - #IRP_TYPE_SET_SECURITY
 * - #IRP_TYPE_QUERY_EA
 * - #IRP_TYPE_SET_EA
 * - #IRP_TYPE_QUERY_QUOTA
 * - #IRP_TYPE_SET_QUOTA
 */
typedef ULONG IRP_TYPE;

/**
 * @brief IRP type has not yet been assigned
 */
#define IRP_TYPE_UNINITIALIZED             0
/**
 * @brief IRP type for file create
 */
#define IRP_TYPE_CREATE                    1
/**
 * @brief IRP type for file close
 */
#define IRP_TYPE_CLOSE                     2
/**
 * @brief IRP type for file read
 */
#define IRP_TYPE_READ                      3
/**
 * @brief IRP type for file write
 */
#define IRP_TYPE_WRITE                     4
/**
 * @brief IRP type to send a device IOCTL
 */
#define IRP_TYPE_DEVICE_IO_CONTROL         5
/**
 * @brief IRP type to send an FSCTL
 */
#define IRP_TYPE_FS_CONTROL                6
/**
 * @brief IRP type for buffer flush
 */
#define IRP_TYPE_FLUSH_BUFFERS             7
/**
 * @brief IRP type to query information on a file
 */
#define IRP_TYPE_QUERY_INFORMATION         8
/**
 * @brief IRP type to set information on a file
 */
#define IRP_TYPE_SET_INFORMATION           9
/**
 * @brief IRP type to create a named pipe
 */
#define IRP_TYPE_CREATE_NAMED_PIPE        10
/**
 * @brief IRP type to create a mail slot
 */
#define IRP_TYPE_CREATE_MAILSLOT          11
/**
 * @brief IRP type to query a directory
 *
 * In Windows, DIRECTORY_CONTROL has two subtypes:
 *     - QUERY_DIRECTORY
 *     - READ_CHANGE_DIRECTORY
 *
 * Here, however, two separate IRPs are used.
 */
#define IRP_TYPE_QUERY_DIRECTORY          12
/**
 * @brief IRP type to read changes to a directory
 *
 * In Windows, DIRECTORY_CONTROL has two subtypes:
 *     - QUERY_DIRECTORY
 *     - READ_CHANGE_DIRECTORY
 *
 * Here, however, two separate IRPs are used.
 */
#define IRP_TYPE_READ_DIRECTORY_CHANGE    13
/**
 * @brief IRP type to query information about a volume
 */
#define IRP_TYPE_QUERY_VOLUME_INFORMATION 14
/**
 * @brief IRP type to set information about a volume
 */
#define IRP_TYPE_SET_VOLUME_INFORMATION   15
/**
 * @brief IRP type to lock or unlock a file
 */
#define IRP_TYPE_LOCK_CONTROL             16
/**
 * @brief IRP type to query security information on a file
 */
#define IRP_TYPE_QUERY_SECURITY           17
/**
 * @brief IRP type to set security information on a file
 */
#define IRP_TYPE_SET_SECURITY             18
/**
 * @brief IRP type to query extended attributes
 */
#define IRP_TYPE_QUERY_EA                 19
/**
 * @brief IRP type to set extended attributes
 */
#define IRP_TYPE_SET_EA                   20
/**
 * @brief IRP type to query quota information on a file
 */
#define IRP_TYPE_QUERY_QUOTA              21
/**
 * @brief IRP type to set quota informaotion on a file
 */
#define IRP_TYPE_SET_QUOTA                22
#if 0
#define IRP_TYPE_QUERY_FULL_ATTRIBUTES    23
#define IRP_TYPE_RENAME                   24
#define IRP_TYPE_LINK                     25
#define IRP_TYPE_UNLINK                   26
#endif

/**@}*/

/**
 * @name IRP Flags
 */

/**@{*/

/**
 * @brief IO flags for IRPs
 *
 * #IRP_IO_FLAGS may include flags related to #IO_FLAGS flags as
 * well as flags that are specific to specific parameters for
 * a given #IRP_TYPE.  Never mix #IO_FLAGS and #IRP_IO_FLAGS values.
 * - #IRP_IO_FLAG_PAGING_IO
 * - #IRP_IO_FLAG_WRITE_THROUGH
 * - #IRP_IO_FLAG_RESTART_SCAN
 * - #IRP_IO_FLAG_RETURN_SINGLE_ENTRY
 * - #IRP_IO_FLAG_USE_INDEX
 */
typedef ULONG IRP_IO_FLAGS;

#define IRP_IO_FLAG_PAGING_IO           0x00000001
#define IRP_IO_FLAG_WRITE_THROUGH       0x00000002

// Specific flags
#define IRP_IO_FLAG_RESTART_SCAN        0x00010000
#define IRP_IO_FLAG_RETURN_SINGLE_ENTRY 0x00020000
#define IRP_IO_FLAG_USE_INDEX           0x00040000

/**@}*/

/**
 * @name IO Lock control
 */

/**@{*/

/**
 * @brief Lock Control
 *
 * Describes the type of lock operation being requested.
 * - #IO_LOCK_CONTROL_LOCK
 * - #IO_LOCK_CONTROL_UNLOCK
 * - #IO_LOCK_CONTROL_UNLOCK_ALL_BY_KEY
 * - #IO_LOCK_CONTROL_UNLOCK_ALL
 */
typedef ULONG IO_LOCK_CONTROL;

#define IO_LOCK_CONTROL_LOCK              1
#define IO_LOCK_CONTROL_UNLOCK            2
#define IO_LOCK_CONTROL_UNLOCK_ALL_BY_KEY 3
#define IO_LOCK_CONTROL_UNLOCK_ALL        4

/**@}*/

/**
 * @name Zero-Copy Operations
 */

/**@{*/

/**
 * @brief ZCT operation
 *
 * Describes the type of ZCT operation being requested.
 * - #IRP_ZCT_OPERATION_NONE
 * - #IRP_ZCT_OPERATION_PREPARE
 * - #IRP_ZCT_OPERATION_COMPLETE
 */
typedef UINT8 IRP_ZCT_OPERATION;

/**
 * @brief Pointer to #IRP_ZCT_OPERATION
 */
typedef IRP_ZCT_OPERATION *PIRP_ZCT_OPERATION;

#define IRP_ZCT_OPERATION_NONE      0
#define IRP_ZCT_OPERATION_PREPARE   1
#define IRP_ZCT_OPERATION_COMPLETE  2

/**@}*/

/**
 * @name IRP Argument Structure Pointers
 */

/**@{*/

/**
 * @brief Arguments for use with #IRP_TYPE_CREATE
 */
typedef struct _IRP_ARGS_CREATE {
    /**
     * @brief The security context of the initiator of this IRP
     */
    IN PIO_CREATE_SECURITY_CONTEXT SecurityContext;
    /**
     * @brief The name of the file being created or opened
     */
    IN IO_FILE_NAME FileName;
    /**
     * @brief The requested access permissions
     */
    IN ACCESS_MASK DesiredAccess;
    /**
     * @brief The allocation size (optional)
     */
    IN OPTIONAL LONG64 AllocationSize;
    /**
     * @brief The attributes with which to create or open the file
     */
    IN FILE_ATTRIBUTES FileAttributes;
    /**
     * @brief Share flags indicating shared access permissions
     */
    IN FILE_SHARE_FLAGS ShareAccess;
    /**
     * @brief Create disposition
     *
     * Specifies what type of open this is.
     */
    IN FILE_CREATE_DISPOSITION CreateDisposition;
    /**
     * @brief Additional create options
     */
    IN FILE_CREATE_OPTIONS CreateOptions;
    /**
     * @brief Extended attributes information (optional)
     */
    IN OPTIONAL PFILE_FULL_EA_INFORMATION EaBuffer;
    /**
     * @brief Specifies the length of the #EaBuffer if any
     */
    IN ULONG EaLength;
    /**
     * @brief Security descriptor (optional)
     */
    IN OPTIONAL PSECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor;
    /**
     * @brief TBD
     */
    IN OPTIONAL PVOID SecurityQualityOfService;
    /**
     * @brief Extra create parameters
     */
    IN OPTIONAL PIO_ECP_LIST EcpList;
} IRP_ARGS_CREATE;

/**
 * @brief #IRP_TYPE_CREATE arguments pointer
 *
 * Pointer to an #IRP_ARGS_CREATE structure.
 */
typedef IRP_ARGS_CREATE *PIRP_ARGS_CREATE;

/**
 * @brief Arguments for use with #IRP_TYPE_READ and #IRP_TYPE_WRITE
 */
typedef struct _IRP_ARGS_READ_WRITE {
    union {
        /**
         * @brief Buffer for non-ZCT reads and writes
         *
         * IN parameter when used with #IRP_TYPE_WRITE, OUT parameter when used
         * with #IRP_TYPE_READ.
         */
        IN OUT PVOID Buffer;
        /**
         * @brief Pointer to a #LW_ZCT_VECTOR for ZCT reads and writes
         *
         * IN parameter when used with #IRP_TYPE_WRITE, OUT parameter when used
         * with #IRP_TYPE_READ.
         */
        IN OUT PLW_ZCT_VECTOR Zct;
    };
    /**
     * @brief Length to read or write
     */
    IN ULONG Length;
    /**
     * @brief Byte offset at which to start read or write (optional)
     */
    IN OPTIONAL PULONG64 ByteOffset;
    /**
     * @brief Key
     */
    IN OPTIONAL PULONG Key;
    /**
     * @brief Type of ZCT operation to perform
     *
     * For ZCT read/write only.
     */
    IN IRP_ZCT_OPERATION ZctOperation;
    /**
     * @brief ZCT completion context
     *
     * For ZCT read/write only.
     */
    IN OUT PVOID ZctCompletionContext;
    /**
     * @brief ZCT write bytes transferred
     *
     * For ZCT write only.
     */
    IN ULONG ZctWriteBytesTransferred;
    /**
     * @brief Storage area for optional parameters
     *
     * Storage field is so we do not have to allocate extra memory blocks for
     * small optional parameters that are provided via pointers.
     */
    struct {
        /**
         * @brief Byte offset to parameter
         */
        ULONG64 ByteOffset;
        /**
         * @brief Parameter key
         */
        ULONG Key;
    } Storage;
} IRP_ARGS_READ_WRITE;

/**
 * @brief #IRP_TYPE_READ or #IRP_TYPE_WRITE arguments pointer
 *
 * Pointer to an #IRP_ARGS_READ_WRITE structure.
 */
typedef IRP_ARGS_READ_WRITE *PIRP_ARGS_READ_WRITE;

/**
 * @brief Arguments for use with #IRP_TYPE_DEVICE_IO_CONTROL and
 *        #IRP_TYPE_FS_CONTROL
 */
typedef struct _IRP_ARGS_IO_FS_CONTROL {
    /**
     * @brief FSCTL code
     */
    IN ULONG ControlCode;
    /**
     * @brief Input buffer for the FSCTL
     */
    IN PVOID InputBuffer;
    /**
     * @brief Length of the input buffer
     */
    IN ULONG InputBufferLength;
    /**
     * @brief Output buffer
     */
    OUT PVOID OutputBuffer;
    /**
     * @brief Length of the output buffer
     */
    IN ULONG OutputBufferLength;
} IRP_ARGS_IO_FS_CONTROL;

/**
 * @brief #IRP_TYPE_DEVICE_IO_CONTROL or #IRP_TYPE_FS_CONTROL arguments pointers
 *
 * Pointer to an #IRP_ARGS_IO_FS_CONTROL structure.
 */
typedef IRP_ARGS_IO_FS_CONTROL *PIRP_ARGS_IO_FS_CONTROL;

/**
 * @brief Arguments for use with #IRP_TYPE_QUERY_INFORMATION and
 *        #IRP_TYPE_SET_INFORMATION
 */
typedef struct _IRP_ARGS_QUERY_SET_INFORMATION {
    /**
     * @brief File information to set or retrieve
     *
     * IN parameter when used with #IRP_TYPE_SET_INFORMATION, OUT parameter when
     * used with #IRP_TYPE_QUERY_INFORMATION.
     */
    IN OUT PVOID FileInformation;
    /**
     * @brief Length of the file information set or retrieved
     *
     * IN parameter when used with #IRP_TYPE_SET_INFORMATION, OUT parameter when
     * used with #IRP_TYPE_QUERY_INFORMATION.
     */
    IN ULONG Length;
    /**
     * @brief Type of file information to set or retrieve
     */
    IN FILE_INFORMATION_CLASS FileInformationClass;
} IRP_ARGS_QUERY_SET_INFORMATION;

/**
 * @brief #IRP_TYPE_QUERY_INFORMATION or #IRP_TYPE_SET_INFORMATION arguments
 *        pointer
 *
 * Pointer to an #IRP_ARGS_QUERY_SET_INFORMATION structure.
 */
typedef IRP_ARGS_QUERY_SET_INFORMATION *PIRP_ARGS_QUERY_SET_INFORMATION;

/**
 * @brief Arguments for use with #IRP_TYPE_QUERY_DIRECTORY
 */
typedef struct _IRP_ARGS_QUERY_DIRECTORY {
    /**
     * @brief File information for the directory
     */
    OUT PVOID FileInformation;
    /**
     * @brief Length of #FileInformation
     */
    IN ULONG Length;
    /**
     * @brief Type of file information to retrieve
     */
    IN FILE_INFORMATION_CLASS FileInformationClass;
    /**
     * @brief Indicates whether to return a single entry
     */
    IN BOOLEAN ReturnSingleEntry;
    /**
     * @brief Pointer to FileSpec storage field (optional)
     */
    IN OPTIONAL PIO_MATCH_FILE_SPEC FileSpec;
    /**
     * @brief Indicates whether to restart scan
     */
    IN BOOLEAN RestartScan;
    /**
     * @brief Storage area for optional parameters
     *
     * Storage field is so we do not have to allocate extra memory blocks for
     * small optional parameters that are provided via pointers.
     */
    struct {
    /**
     * @brief File specification to match
     */
        IO_MATCH_FILE_SPEC FileSpec;
    } Storage;
} IRP_ARGS_QUERY_DIRECTORY;

/**
 * @brief #IRP_TYPE_QUERY_DIRECTORY arguments pointer
 *
 * Pointer to an #IRP_ARGS_QUERY_DIRECTORY structure.
 */
typedef IRP_ARGS_QUERY_DIRECTORY *PIRP_ARGS_QUERY_DIRECTORY;

/**
 * @brief Arguments for use with #IRP_TYPE_READ_DIRECTORY_CHANGE
 */
typedef struct _IRP_ARGS_READ_DIRECTORY_CHANGE {
    /**
     * @brief Buffer for returned directory change information
     */
    OUT PVOID Buffer;
    /**
     * @brief Length of the buffer
     */
    IN ULONG Length;
    /**
     * @brief Indicates whether to watch the directory tree
     */
    IN BOOLEAN WatchTree;
    /**
     * @brief Flags indicating which types of changes to notify about
     */
    IN FILE_NOTIFY_CHANGE NotifyFilter;
    /**
     * @brief Pointer to the #MaxBufferSize storage field (optional)
     */
    IN OPTIONAL PULONG MaxBufferSize;
    /**
     * @brief Storage area for optional parameters
     *
     * Storage field is so we do not have to allocate extra memory blocks for
     * small optional parameters that are provided via pointers.
     */
    struct {
    /**
     * @brief Maximum size for #Buffer
     */
        ULONG MaxBufferSize;
    } Storage;
} IRP_ARGS_READ_DIRECTORY_CHANGE;

/**
 * @brief #IRP_TYPE_READ_DIRECTORY_CHANGE arguments pointer
 *
 * Pointer to an #IRP_ARGS_READ_DIRECTORY_CHANGE structure.
 */
typedef IRP_ARGS_READ_DIRECTORY_CHANGE *PIRP_ARGS_READ_DIRECTORY_CHANGE;

/**
 * @brief Arguments for use with #IRP_TYPE_QUERY_VOLUME_INFORMATION and
 *        #IRP_TYPE_SET_VOLUME_INFORMATION
 */
typedef struct _IRP_ARGS_QUERY_SET_VOLUME_INFORMATION {
    /**
     * @brief Volume information to set
     */
    IN OUT PVOID FsInformation;
    /**
     * @brief Length of #FsInformation
     */
    IN ULONG Length;
    /**
     * @brief Type of information to set
     */
    IN FS_INFORMATION_CLASS FsInformationClass;
} IRP_ARGS_QUERY_SET_VOLUME_INFORMATION;

/**
 * @brief #IRP_TYPE_QUERY_VOLUME_INFORMATION or #IRP_TYPE_SET_VOLUME_INFORMATION
 *        arguments pointer
 *
 * Pointer to an #IRP_ARGS_QUERY_SET_VOLUME_INFORMATION structure.
 */
typedef IRP_ARGS_QUERY_SET_VOLUME_INFORMATION *PIRP_ARGS_QUERY_SET_VOLUME_INFORMATION;

/**
 * @brief Arguments for use with #IRP_TYPE_LOCK_CONTROL
 */
typedef struct _IRP_ARGS_LOCK_CONTROL {
    /**
     * @brief Indicates what type of lock control operation to execute
     */
    IN IO_LOCK_CONTROL LockControl;
    /**
     * @brief Byte offset to lock or unlock
     */
    IN ULONG64 ByteOffset;
    /**
     * @brief Length, in bytes, to lock or unlock
     */
    IN ULONG64 Length;
    /**
     * @brief Key for use with #IO_LOCK_CONTROL_UNLOCK_ALL_BY_KEY
     */
    IN ULONG Key;
    /**
     * @brief Don't block
     */
    IN BOOLEAN FailImmediately;
    /**
     * @brief Exclusive lock
     */
    IN BOOLEAN ExclusiveLock;
} IRP_ARGS_LOCK_CONTROL;

/**
 * @brief #IRP_TYPE_LOCK_CONTROL arguments pointer
 *
 * Pointer to an #IRP_ARGS_LOCK_CONTROL structure.
 */
typedef IRP_ARGS_LOCK_CONTROL *PIRP_ARGS_LOCK_CONTROL;

/**
 * @brief Arguments for use with #IRP_TYPE_QUERY_SECURITY and
 *        #IRP_TYPE_SET_SECURITY
 */
typedef struct _IRP_ARGS_QUERY_SET_SECURITY {
    /**
     * @brief Security information to set or retrieve
     */
    IN SECURITY_INFORMATION SecurityInformation;
    /**
     * @brief Security descriptor
     *
     * IN parameter when used with #IRP_TYPE_SET_SECURITY, OUT parameter when
     * used with #IRP_TYPE_QUERY_SECURITY.
     */
    IN OUT PSECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor;
    /**
     * @brief Length of #SecurityDescriptor
     */
    IN OUT PULONG Length;
} IRP_ARGS_QUERY_SET_SECURITY;

/**
 * @brief #IRP_TYPE_QUERY_SECURITY or #IRP_TYPE_SET_SECURITY arguments pointer
 *
 * Pointer to an #IRP_ARGS_QUERY_SET_SECURITY structure.
 */
typedef IRP_ARGS_QUERY_SET_SECURITY *PIRP_ARGS_QUERY_SET_SECUIRTY;

/**
 * @brief Arguments for use with #IRP_TYPE_QUERY_EA
 */
typedef struct _IRP_ARGS_QUERY_EA {
    // Look for:
    // - IRP_IO_FLAG_RESTART_SCAN
    // - IRP_IO_FLAG_RETURN_SINGLE_ENTRY
    // - IRP_IO_FLAG_USE_INDEX
    /**
     * @brief Return buffer for EA information
     */
    OUT PFILE_FULL_EA_INFORMATION Buffer;
    /**
     * @brief Length of #Buffer
     */
    IN ULONG Length;
    /**
     * @brief List of EAs to retrieve
     */
    IN PFILE_GET_EA_INFORMATION EaList;
    /**
     * @brief Number of entries in #EaList
     */
    IN ULONG EaListLength;
    /**
     * @brief EA index (optional)
     *
     * Use if #IRP_IO_FLAG_USE_INDEX is set
     */
    IN OPTIONAL ULONG EaIndex;
} IRP_ARGS_QUERY_EA;

/**
 * @brief #IRP_TYPE_QUERY_EA arguments pointer
 *
 * Pointer to an #IRP_ARGS_QUERY_EA structure.
 */
typedef IRP_ARGS_QUERY_EA *PIRP_ARGS_QUERY_EA;

/**
 * @brief Arguments for use with #IRP_TYPE_SET_EA
 */
typedef struct _IRP_ARGS_SET_EA {
    /**
     * @brief EA information to set
     */
    IN PFILE_FULL_EA_INFORMATION Buffer;
    /**
     * @brief Length of #Buffer
     */
    IN ULONG Length;
} IRP_ARGS_SET_EA;

/**
 * @brief #IRP_TYPE_SET_EA arguments pointer
 *
 * Pointer to an #IRP_ARGS_SET_EA structure.
 */
typedef IRP_ARGS_SET_EA *PIRP_ARGS_SET_EA;

/**
 * @brief Arguments for use with #IRP_TYPE_QUERY_QUOTA
 */
typedef struct _IRP_ARGS_QUERY_QUOTA {
    /**
     * @brief Return buffer for quota information
     */
    OUT PFILE_QUOTA_INFORMATION Buffer;
    /**
     * @brief Length of #Buffer
     */
    IN ULONG Length;
    /**
     * @brief Indicates whether to limit returned information to a single entry
     */
    IN BOOLEAN ReturnSingleEntry;
    /**
     * @brief List of SIDs to query (optional)
     */
    IN OPTIONAL PFILE_GET_QUOTA_INFORMATION SidList;
    /**
     * @brief Number of SIDs in #SidList
     */
    IN ULONG SidListLength;
    /**
     * @brief SID to start with (optional)
     */
    IN OPTIONAL PFILE_GET_QUOTA_INFORMATION StartSid;
    /**
     * @brief Indicates whether to restart scan
     */
    IN BOOLEAN RestartScan;
} IRP_ARGS_QUERY_QUOTA;

/**
 * @brief #IRP_TYPE_QUERY_QUOTA arguments pointer
 *
 * Pointer to an #IRP_ARGS_QUERY_QUOTA structure.
 */
typedef IRP_ARGS_QUERY_QUOTA *PIRP_ARGS_QUERY_QUOTA;

/**
 * @brief Arguments for use with #IRP_TYPE_SET_QUOTA
 */
typedef struct _IRP_ARGS_SET_QUOTA {
    /**
     * @brief Quota information to set
     */
    IN PFILE_QUOTA_INFORMATION Buffer;
    /**
     * @brief Length of #Buffer
     */
    IN ULONG Length;
} IRP_ARGS_SET_QUOTA;

/**
 * @brief #IRP_TYPE_SET_QUOTA arguments pointer
 *
 * Pointer to an #IRP_ARGS_SET_QUOTA structure.
 */
typedef IRP_ARGS_SET_QUOTA *PIRP_ARGS_SET_QUOTA;

/**@}*/

/**
 * @name The IRP
 */

/**@{*/

/**
 * @brief The IRP structure
 */
typedef struct _IRP {
    /**
     * @brief The type of IRP this is
     */
    IN IRP_TYPE Type;
    /**
     * @brief Flags associated with this IRP
     */
    IN IRP_IO_FLAGS Flags;
    /**
     * @brief Status block to be filled in when the IRP is processed
     */
    OUT IO_STATUS_BLOCK IoStatusBlock;
    /**
     * @brief Handle for the driver that is processing this IRP
     */
    IN IO_DRIVER_HANDLE DriverHandle;
    /**
     * @brief Device handle associated with this IRP
     */
    IN IO_DEVICE_HANDLE DeviceHandle;
    /**
     * @brief File handle associated with this IRP
     */
    IN IO_FILE_HANDLE FileHandle;
    /**
     * @brief Arguments associated with this IRP
     */
    union {
        /**
         * @brief Use with #IRP_TYPE_CREATE
         */
        IRP_ARGS_CREATE Create;
        /**
         * @brief Use with #IRP_TYPE_READ and #IRP_TYPE_WRITE
         */
        IRP_ARGS_READ_WRITE ReadWrite;
        /**
         * @brief Use with #IRP_TYPE_IO_CONTROL and #IRP_TYPE_FS_CONTROL
         */
        IRP_ARGS_IO_FS_CONTROL IoFsControl;
        /**
         * @brief Use with #IRP_TYPE_QUERY_INFORMATION and
         *        #IRP_TYPE_SET_INFORMATION
         */
        IRP_ARGS_QUERY_SET_INFORMATION QuerySetInformation;
        /**
         * @brief Use with #IRP_TYPE_QUERY_DIRECTORY
         */
        IRP_ARGS_QUERY_DIRECTORY QueryDirectory;
        /**
         * @brief Use with #IRP_TYPE_READ_DIRECTORY_CHANGE
         */
        IRP_ARGS_READ_DIRECTORY_CHANGE ReadDirectoryChange;
        /**
         * @brief Use with #IRP_TYPE_QUERY_VOLUME_INFORMATION and
         *        #IRP_TYPE_SET_VOLUME_INFORMATION
         */
        IRP_ARGS_QUERY_SET_VOLUME_INFORMATION QuerySetVolumeInformation;
        /**
         * @brief Use with #IRP_TYPE_LOCK_CONTROL
         */
        IRP_ARGS_LOCK_CONTROL LockControl;
        /**
         * @brief Use with #IRP_TYPE_QUERY_SECURITY and #IRP_TYPE_SET_SECURITY
         */
        IRP_ARGS_QUERY_SET_SECURITY QuerySetSecurity;
        /**
         * @brief Use with #IRP_TYPE_QUERY_EA
         */
        IRP_ARGS_QUERY_EA QueryEa;
        /**
         * @brief Use with #IRP_TYPE_SET_EA
         */
        IRP_ARGS_SET_EA SetEa;
        /**
         * @brief Use with #IRP_TYPE_QUERY_QUOTA
         */
        IRP_ARGS_QUERY_QUOTA QueryQuota;
        /**
         * @brief Use with #IRP_TYPE_SET_QUOTA
         */
        IRP_ARGS_SET_QUOTA SetQuota;
        //No args for IRP_TYPE_CLOSE, IRP_TYPE_FLUSH
    } Args;
    // TODO: Rename Args to Params?
    // Internal data at the end...
} IRP;

/**
 * @brief #IRP pointer
 *
 * Pointer to an #IRP structure.
 */
typedef IRP *PIRP;

/**@}*/


typedef VOID (*PIO_IRP_CALLBACK)(
    IN PIRP Irp,
    IN PVOID CallbackContext
    );

typedef VOID (*PIO_DRIVER_SHUTDOWN_CALLBACK)(
    IN IO_DRIVER_HANDLE DriverHandle
    );

typedef NTSTATUS (*PIO_DRIVER_DISPATCH_CALLBACK)(
    IN IO_DEVICE_HANDLE DeviceHandle,
    IN PIRP Irp
    );

typedef NTSTATUS (*PIO_DRIVER_REFRESH_CALLBACK)(
    IN IO_DRIVER_HANDLE DriverHandle
    );

typedef NTSTATUS (*PIO_DRIVER_ENTRY)(
    IN IO_DRIVER_HANDLE DriverHandle,
    IN ULONG InterfaceVersion
    );

typedef struct _IO_STATIC_DRIVER
{
    PCSTR pszName;
    PIO_DRIVER_ENTRY pEntry;
} IO_STATIC_DRIVER, *PIO_STATIC_DRIVER;

#define IO_DRIVER_ENTRY_FUNCTION_NAME "DriverEntry"
#define IO_DRIVER_ENTRY_INTERFACE_VERSION 1

// Driver functions

// Can only be called in DriverEntry.
NTSTATUS
IoDriverInitialize(
    IN OUT IO_DRIVER_HANDLE DriverHandle,
    IN OPTIONAL PVOID DriverContext,
    IN PIO_DRIVER_SHUTDOWN_CALLBACK ShutdownCallback,
    IN PIO_DRIVER_DISPATCH_CALLBACK DispatchCallback
    );

NTSTATUS
IoDriverRegisterRefreshCallback(
    IN OUT IO_DRIVER_HANDLE DriverHandle,
    IN PIO_DRIVER_REFRESH_CALLBACK RefreshCallback
    );

PCSTR
IoDriverGetName(
    IN IO_DRIVER_HANDLE DriverHandle
    );

PVOID
IoDriverGetContext(
    IN IO_DRIVER_HANDLE DriverHandle
    );


// Device functions

NTSTATUS
IoDeviceCreate(
    OUT PIO_DEVICE_HANDLE pDeviceHandle,
    IN IO_DRIVER_HANDLE DriverHandle,
    IN PCSTR pszName,
    IN OPTIONAL PVOID DeviceContext
    );

VOID
IoDeviceDelete(
    IN OUT PIO_DEVICE_HANDLE pDeviceHandle
    );

PVOID
IoDeviceGetContext(
    IN IO_DEVICE_HANDLE DeviceHandle
    );

// File functions

NTSTATUS
IoFileSetContext(
    IN IO_FILE_HANDLE FileHandle,
    IN PVOID FileContext
    );

PVOID
IoFileGetContext(
    IN IO_FILE_HANDLE FileHandle
    );

// The FSD must synchronize calling this itself
VOID
IoFileSetZctSupportMask(
    IN IO_FILE_HANDLE FileHandle,
    IN LW_ZCT_ENTRY_MASK ZctReadMask,
    IN LW_ZCT_ENTRY_MASK ZctWriteMask
    );

/**
 * @name Asynchronous Completion
 *
 * These functions allow I/O requests to be completed separately
 * from the original dispatch function.  All requests that cannot
 * be completed immediately must be completed in this fashion.
 */

/**@{*/

#if 0
BOOLEAN
IoIrpIsCancelled(
    IN PIRP pIrp
    );
#endif

/**
 * @brief Mark IRP as pending
 *
 * Marks the given IRP as pending asynchronous completion.  After calling
 * this function, the original IRP dispatch function must return @a LW_STATUS_PENDING,
 * and the IRP must be completed by setting an appropriate status in @a pIrp->IoStatusBlock
 * and calling #IoIrpComplete().
 *
 * The caller must provide a cancellation callback.  If the I/O operation is canceled,
 * the callback will be invoked with the provided context pointer.  The operation must
 * then be completed as quickly as possible.  This is typically accomplished by aborting
 * it entirely and completing with @a LW_STATUS_CANCELLED.
 *
 * @param[in] pIrp                   The IRP.
 * @param[in] CancelCallback         A cancellation callback function.
 * @param[in] CancelCallbackContext  An optional user context pointer to pass to
 *                                   the callback function.
 */
VOID
IoIrpMarkPending(
    IN PIRP pIrp,
    IN PIO_IRP_CALLBACK CancelCallback,
    IN OPTIONAL PVOID CancelCallbackContext
    );

#if 0
VOID
IoIrpSetCancelRoutine(
    IN PIRP pIrp,
    IN OPTIONAL PIO_IRP_CALLBACK CancelCallback,
    IN OPTIONAL PVOID CancelCallbackContext
    );
#endif

/**
 * @brief Complete IRP
 *
 * Completes the given IRP which was previously pended with #IoIrpMarpPending().  The
 * status in @a Irp->IoStatusBlock, in addition to any other relevant output parameters,
 * must be set before calling this function.
 *
 * @param[in] Irp The IRP.
 */
VOID
IoIrpComplete(
    IN OUT PIRP Irp
    );

/**@}*/

// Drivrer memory

VOID
IoMemoryZero(
    IN OUT PVOID pMemory,
    IN size_t Size
    );

PVOID
IoMemoryAllocate(
    IN size_t Size
    );

VOID
IoMemoryFree(
    IN OUT PVOID pMemory
    );

#define IO_ALLOCATE(ppMemory, Type, Size) \
    ( (*(ppMemory)) = (Type*) IoMemoryAllocate(Size), (*(ppMemory)) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES )

#define IO_FREE(ppMemory) \
    do { \
        if (*(ppMemory)) \
        { \
            IoMemoryFree(*(ppMemory)); \
            (*(ppMemory)) = NULL; \
        } \
    } while (0)

//
// Security Context
//

PIO_SECURITY_CONTEXT_PROCESS_INFORMATION
IoSecurityGetProcessInfo(
    IN PIO_CREATE_SECURITY_CONTEXT SecurityContext
    );

PACCESS_TOKEN
IoSecurityGetAccessToken(
    IN PIO_CREATE_SECURITY_CONTEXT SecurityContext
    );

LW_PIO_CREDS
IoSecurityGetCredentials(
    IN PIO_CREATE_SECURITY_CONTEXT SecurityContext
    );

VOID
IoSecurityDereferenceSecurityContext(
    IN OUT PIO_CREATE_SECURITY_CONTEXT* SecurityContext
    );

NTSTATUS
IoSecurityCreateSecurityContextFromUidGid(
    OUT PIO_CREATE_SECURITY_CONTEXT* SecurityContext,
    IN uid_t Uid,
    IN gid_t Gid,
    IN OPTIONAL LW_PIO_CREDS Credentials
    );

NTSTATUS
IoSecurityCreateSecurityContextFromUsername(
    OUT PIO_CREATE_SECURITY_CONTEXT* SecurityContext,
    IN PUNICODE_STRING Username
    );

NTSTATUS
IoSecurityCreateSecurityContextFromGssContext(
    OUT PIO_CREATE_SECURITY_CONTEXT* SecurityContext,
    IN LW_MAP_SECURITY_GSS_CONTEXT hGssContext
    );

NTSTATUS
IoSecurityCreateSecurityContextFromNtlmLogon(
    OUT PIO_CREATE_SECURITY_CONTEXT* ppSecurityContext,
    OUT PLW_MAP_SECURITY_NTLM_LOGON_RESULT* ppNtlmLogonResult,
    IN PLW_MAP_SECURITY_NTLM_LOGON_INFO pNtlmLogonInfo
    );

NTSTATUS
IoSecurityCreateSecurityContextFromAccessToken(
    OUT PIO_CREATE_SECURITY_CONTEXT* ppSecurityContext,
    IN PACCESS_TOKEN pToken,
    IN uid_t Uid,
    IN gid_t Gid,
    IN OPTIONAL LW_PIO_CREDS pCredentials
    );

VOID
IoSecurityFreeNtlmLogonResult(
    IN OUT PLW_MAP_SECURITY_NTLM_LOGON_RESULT* ppNtlmLogonResult
    );

//
// Logging
//

PCSTR
IoGetIrpTypeString(
    IN IRP_TYPE Type
    );

#define IO_LOG_ENTER(Format, ...) \
    LWIO_LOG_DEBUG("ENTER: " Format, ## __VA_ARGS__)

#define IO_LOG_LEAVE(Format, ...) \
    LWIO_LOG_DEBUG("LEAVE: " Format, ## __VA_ARGS__)

#define IO_LOG_ENTER_LEAVE(Format, ...) \
    LWIO_LOG_DEBUG("ENTER/LEAVE: " Format, ## __VA_ARGS__)

#define IO_LOG_LEAVE_ON_STATUS_EE(status, EE) \
    do { \
        if (EE || status) \
        { \
            IO_LOG_LEAVE("-> 0x%08x (EE = %d)", status, EE); \
        } \
    } while (0)

#define IO_LOG_ENTER_LEAVE_STATUS_EE(status, EE) \
    IO_LOG_ENTER_LEAVE("-> 0x%08x (EE = %d)", status, EE)

#define IO_LOG_ENTER_LEAVE_STATUS_EE_EX(status, EE, Format, ...) \
    IO_LOG_ENTER_LEAVE(Format " -> 0x%08x (EE = %d)", ## __VA_ARGS__, status, EE)

#define IO_LOG_LEAVE_STATUS_EE(status, EE) \
    IO_LOG_LEAVE("-> 0x%08x (EE = %d)", status, EE)

#define IO_LOG_LEAVE_STATUS_EE_EX(status, EE, Format, ...) \
    IO_LOG_LEAVE(Format " -> 0x%08x (EE = %d)", ## __VA_ARGS__, status, EE)

#ifdef ENABLE_STATIC_DRIVERS
#define IO_DRIVER_ENTRY(name) DriverEntry_##name
#else
#define IO_DRIVER_ENTRY(name) DriverEntry
#endif

#define IO_STATIC_DRIVER_ENTRY(name) {#name, IO_DRIVER_ENTRY(name)}
#define IO_STATIC_DRIVER_END {NULL, NULL}

/*@}*/

LW_END_EXTERN_C


#endif /* __IODRIVER_H__ */

/*
local variables:
mode: c
c-basic-offset: 4
indent-tabs-mode: nil
tab-width: 4
end:
*/
