/*++

Copyright (c) Microsoft Corporation.  All rights reserved.

Module Name:

    NtfsExp.h

Abstract:

    This module defines the exports from NtOfs.SYS for use exclusively by
    Transactions and Encryption.

    *********************************
    *No other clients are supported.*
    *********************************

Author:

    Mark Zbikowski  [MarkZ]         7-Dec-1995
    Jeff Havens     [JHavens]
    Brian Andrew    [BrianAn]
    Gary Kimura     [GaryKi]
    Tom Miller      [TomM]

Revision History:


--*/

#ifndef _NTFS_

//
//  The MFT Segment Reference is an address in the MFT tagged with
//  a circularly reused sequence number set at the time that the MFT
//  Segment Reference was valid.  Note that this format limits the
//  size of the Master File Table to 2**48 segments.  So, for
//  example, with a 1KB segment size the maximum size of the master
//  file would be 2**58 bytes, or 2**28 gigabytes.
//

typedef struct _FILE_REFERENCE {

    //
    //  First a 48 bit segment number.
    //

    ULONG SegmentNumberLowPart;                                    //  offset = 0x000
    USHORT SegmentNumberHighPart;                                  //  offset = 0x004

    //
    //  Now a 16 bit nonzero sequence number.  A value of 0 is
    //  reserved to allow the possibility of a routine accepting
    //  0 as a sign that the sequence number check should be
    //  repressed.
    //

    USHORT SequenceNumber;                                          //  offset = 0x006

} FILE_REFERENCE, *PFILE_REFERENCE;                   //  sizeof = 0x008

#endif

//
//  Big picture view of the interaction between extensions and NtOfs:
//
//      NtOfs exports a number of interfaces that give abstract access to
//      on-disk structures and attempt to hide, as much as possible, the
//      implementation details.
//
//      V/Q/X are implemented as DLL's that link to NtOfs.Sys.  NtOfs can load
//      and function in absence of these DLL's.
//
//      All communication between user-mode code and V/Q/X occurs via the
//      Nt Io API which is routed through NtOfs.  Client code will open either
//      an NtOfs Volume, Directory, or File and will issue NtIo calls to the
//      resultant handle.
//
//      NtOfs will create an IrpContext, decode the file object appropriately,
//      and call out to entry points in V/Q/X that are registered at load-time.
//
//      V/Q/X will perform whatever actions are necessary utilizing NtOfs exports
//      and then return from the original call from NtOfs an NTSTATUS code.  NtOfs
//      will perform the appropriate CompleteIrp calls, posting for STATUS_PENDING,
//      etc.
//
//      No exceptions can be raised across the NtOfs export or NtOfs import
//      interfaces.  All user-buffer access and validation will occur in the
//      code that uses it.  Since user buffers may disappear at any time, any
//      client of these buffers must wrap access to the buffers in an exception
//      clause.
//
//      V/Q/X may perform activities in threads separate from the original
//      requestor.  For these cases, NtOfs will provide a means where calls separate
//      from a user-mode request can be accepted.  Typically, this means "cloning"
//      an IrpContext.
//

//
//  Opaque handle definitions.
//

//
//  ISSUE:  Most NtOfs internal routines rely on having an IrpContext passed in
//  along with FCB and SCB pointers.  Rather than exposing FCB and IrpContext
//  as separate contexts, should we wrap these up into a separate structure and
//  pass it along?
//

typedef struct _FCB *OBJECT_HANDLE;
typedef struct _SCB *ATTRIBUTE_HANDLE;
typedef struct _SCB *INDEX_HANDLE;
typedef struct _READ_CONTEXT *PREAD_CONTEXT;
typedef ULONG SECURITY_ID;
typedef struct _CI_CALL_BACK CI_CALL_BACK, *PCI_CALL_BACK;
typedef struct _VIEW_CALL_BACK VIEW_CALL_BACK, *PVIEW_CALL_BACK;
typedef struct _IRP_CONTEXT *PIRP_CONTEXT;

//
//  Map Handle.  This structure defines a byte range of the file which is mapped
//  or pinned, and stores the Bcb returned from the Cache Manager.
//

typedef struct _MAP_HANDLE {

    //
    //  Range being mapped or pinned
    //

    LONGLONG FileOffset;
    ULONG Length;

    //
    //  Virtual address corresponding to FileOffset
    //

    PVOID Buffer;

    //
    //  Bcb pointer returned from Cache Manager
    //

    PVOID Bcb;

} MAP_HANDLE, *PMAP_HANDLE;

//
//  Quick Index Hint.  This is stream offset information returned by
//  NtOfsFindRecord, and taken as input to NtOfsUpdateRecord, to allow
//  quick updates to index records in the event that they have not
//  moved.  This structure must always have the same size and alignment
//  as QUICK_INDEX in ntfsstru.h.
//

typedef struct _QUICK_INDEX_HINT {
    LONGLONG HintData[3];
} QUICK_INDEX_HINT, *PQUICK_INDEX_HINT;

//
//  Index structures
//

typedef struct {
    ULONG KeyLength;
    PVOID Key;
} INDEX_KEY, *PINDEX_KEY;

typedef struct {
    ULONG DataLength;
    PVOID Data;
} INDEX_DATA, *PINDEX_DATA;

typedef struct {
    INDEX_KEY KeyPart;
    INDEX_DATA DataPart;
} INDEX_ROW, *PINDEX_ROW;

//
//  COLLATION_FUNCTION returns LessThan if Key1 precedes Key2
//                             EqualTo if Key1 is identical to Key2
//                             GreaterThan if Key1 follows Key2
//

typedef FSRTL_COMPARISON_RESULT (*PCOLLATION_FUNCTION) (
            IN PINDEX_KEY Key1,
            IN PINDEX_KEY Key2,
            IN PVOID CollationData
            );

typedef struct _UPCASE_TABLE_AND_KEY {

    //
    //  Pointer to a table of upcased unicode characters indexed by character to
    //  be upcased.
    //

    PWCH UpcaseTable;

    //
    //  Size of UpcaseTable in unicode characters
    //

    ULONG UpcaseTableSize;

    //
    //  Optional addtional pointer.
    //

    INDEX_KEY Key;

} UPCASE_TABLE_AND_KEY, *PUPCASE_TABLE_AND_KEY;

//
//  Wait for new length block used to synchronize a thread with FileSize
//  exceeding the specified Length.
//

typedef struct _WAIT_FOR_NEW_LENGTH {

    //
    //  Link words for multiple waiters on the Scb.
    //

    LIST_ENTRY WaitList;

    //
    //  Set event when FileSize exceeds this length.
    //

    LONGLONG Length;

    //
    //  Event to set when new length achieved.
    //

    KEVENT Event;

    //
    //  Irp to complete when new length achieved. (If Irp present, Event is
    //  ignored.)
    //

    PIRP Irp;

    //
    //  Stream we are waiting on.
    //

    ATTRIBUTE_HANDLE Stream;

    //
    //  Status code for operation that caused the new length to be satisfied.
    //  It may be STATUS_CANCELLED, STATUS_TIMEOUT or STATUS_SUCCESS
    //  or a request specific status.
    //

    NTSTATUS Status;

    //
    //  Flags.
    //

    ULONG Flags;

} WAIT_FOR_NEW_LENGTH, *PWAIT_FOR_NEW_LENGTH;

#define NTFS_WAIT_FLAG_ASYNC                    (0x00000001)

//
//  Standard collation functions for simple indices
//

FSRTL_COMPARISON_RESULT
NtOfsCollateUlong (             //  Both must be single Ulong
    IN PINDEX_KEY Key1,
    IN PINDEX_KEY Key2,
    IN PVOID CollationData      //  Don't care, may be NULL
    );

FSRTL_COMPARISON_RESULT
NtOfsCollateUlongs (            //  Lengths do not have to be equal
    IN PINDEX_KEY Key1,
    IN PINDEX_KEY Key2,
    IN PVOID CollationData      //  Don't care, may be NULL
    );

FSRTL_COMPARISON_RESULT
NtOfsCollateSid (
    IN PINDEX_KEY Key1,
    IN PINDEX_KEY Key2,
    IN PVOID CollationData      //  Don't care, may be NULL
    );

FSRTL_COMPARISON_RESULT
NtOfsCollateUnicode (
    IN PINDEX_KEY Key1,
    IN PINDEX_KEY Key2,
    IN PVOID CollationData      //  PUPCASE_TABLE_AND_KEY (with no key)
    );

//
//  Standard match functions for simple indices
//

NTSTATUS
NtOfsMatchAll (
    IN PINDEX_ROW IndexRow,
    IN OUT PVOID MatchData      //  Don't care, may be NULL
    );

NTSTATUS
NtOfsMatchUlongExact (
    IN PINDEX_ROW IndexRow,     //  Both must be single Ulong
    IN OUT PVOID MatchData      //  PINDEX_KEY describing Ulong
    );

NTSTATUS
NtOfsMatchUlongsExact (         //  Lengths do not have to be equal
    IN PINDEX_ROW IndexRow,
    IN OUT PVOID MatchData      //  PINDEX_KEY describing Ulongs
    );

NTSTATUS
NtOfsMatchUnicodeExpression (
    IN PINDEX_ROW IndexRow,
    IN OUT PVOID MatchData      //  PUPCASE_TABLE_AND_KEY with Uni expression (must have wildcards)
    );

NTSTATUS
NtOfsMatchUnicodeString (
    IN PINDEX_ROW IndexRow,
    IN OUT PVOID MatchData      //  PUPCASE_TABLE_AND_KEY with Uni string (no wildcards)
    );

//
//  MATCH_FUNCTION returns
//      STATUS_SUCCESS if the IndexRow matches
//      STATUS_NO_MATCH if the IndexRow does not match, but the enumeration should
//          continue
//      STATUS_NO_MORE_MATCHES if the IndexRow does not match, and the enumeration
//          should terminate
//

typedef NTSTATUS (*PMATCH_FUNCTION) (IN PINDEX_ROW IndexRow, IN OUT PVOID MatchData);

//
//  CREATE_OPTIONS - common flags governing creation/opening of objects
//

typedef enum _CREATE_OPTIONS
{
    CREATE_NEW = 0,
    CREATE_OR_OPEN = 1,
    OPEN_EXISTING = 2
} CREATE_OPTIONS;


//
//  EXCLUSION - Form of exclusion desired when opening an object
//

typedef enum _EXCLUSION
{
    SHARED = 0,
    EXCLUSIVE
} EXCLUSION;



//
//  Additional Dos Attribute indicating Content Index status of an object.
//  If this is set on a document, it suppresses indexing.  It is inherited
//  from a parent directory at create time.  This is stored in the
//  DUPLICATED_INFORMATION structure.
//

#define SUPPRESS_CONTENT_INDEX      (0x20000000)

//
//  Define the size of the index buffer/bucket for view indexes, in bytes.
//

#define NTOFS_VIEW_INDEX_BUFFER_SIZE    (0x1000)

//
//  Exported constants.
//

//
//  NtOfsContentIndexSystemFile is the repository for all CI related data on the
//  disk.

extern FILE_REFERENCE NtOfsContentIndexSystemFile;

#if defined(_NTFSPROC_)

#define NTFSAPI

#else

#define NTFSAPI //DECLSPEC_IMPORT

#endif

////////////////////////////////////////////////////////////////////////////////

//
//  Index API - These encapsulate the NtOfs BTree mechanisms.
//

//
//  NtOfsCreateIndex creates or opens a named index attribute in an object.  The
//  ObjectHandle has been acquired exclusive and the returned handle is not
//  acquired.  The collation data is interpreted only by the CollationFunction.
//
//  IndexHandles retain a "seek" position where enumerations (NtOfsReadRecords)
//  may continue.  This seek position may be updated by the routines as described
//  below.
//
//  If DeleteCollationData is 1, ExFreePool will be called on CollationData, either
//  immediately if the index already exists, or when the index is deleted some time
//  after the final close.  If NtOfsCreateIndex returns an error, then CollationData
//  must be deleted by the caller.  If specified as 0, then ColloationData will not
//  be deleted.
//

NTFSAPI
NTSTATUS
NtOfsCreateIndex (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ObjectHandle,
    IN UNICODE_STRING Name,
    IN CREATE_OPTIONS CreateOptions,
    IN ULONG DeleteCollationData,
    IN ULONG CollationRule,
    IN PCOLLATION_FUNCTION CollationFunction,
    IN PVOID CollationData OPTIONAL,
    OUT INDEX_HANDLE *IndexHandle
    );


//
//  NtOfsFindRecord finds a single record in an index stream for read-only access
//  or in preparation for calling NtOfsUpdateRecord.
//

NTFSAPI
NTSTATUS
NtOfsFindRecord (
    IN PIRP_CONTEXT IrpContext,
    IN INDEX_HANDLE IndexHandle,
    IN PINDEX_KEY IndexKey,
    OUT PINDEX_ROW IndexRow,
    OUT PMAP_HANDLE MapHandle,
    IN OUT PQUICK_INDEX_HINT QuickIndexHint OPTIONAL
    );

//
//  NtOfsFindRecord finds a single record in an index stream for read-only access
//  or in preparation for calling NtOfsUpdateRecord.
//

NTFSAPI
NTSTATUS
NtOfsFindLastRecord (
    IN PIRP_CONTEXT IrpContext,
    IN INDEX_HANDLE IndexHandle,
    IN PINDEX_KEY MaxIndexKey,
    OUT PINDEX_ROW IndexRow,
    OUT PMAP_HANDLE MapHandle
    );

//
//  NtOfsAddRecords performs bulk, logged inserts into an index.  The index will
//  be acquired exclusive for this call.  Each record added must have a unique
//  (with regards to the collation function) key.  No maps are currently
//  outstanding on this index.  If SequentialInsertMode is nonzero, this is a hint
//  to the index package to keep all BTree buffers as full as possible, by splitting
//  as close to the end of the buffer as possible.  If specified as zero, random
//  inserts are assumed, and buffers are always split in the middle for better balance.
//
//  This call may update the IndexHandle seek position
//

NTFSAPI
VOID
NtOfsAddRecords (
    IN PIRP_CONTEXT IrpContext,
    IN INDEX_HANDLE IndexHandle,
    IN ULONG Count,
    IN PINDEX_ROW IndexRow,
    IN ULONG SequentialInsertMode
    );

//
//  NtOfsDeleteRecords performs bulk, logged deletion from an index.  The index
//  will be acquired exclusive for this call.  No maps are currently outstanding
//  on this index.
//
//  This call may update the IndexHandle seek position
//

NTFSAPI
VOID
NtOfsDeleteRecords (
    IN PIRP_CONTEXT IrpContext,
    IN INDEX_HANDLE IndexHandle,
    IN ULONG Count,
    IN PINDEX_KEY IndexKey
    );

//
//  NtOfsReadRecords applies a match function to a block of contiguous records in
//  the BTree starting either at a given IndexKey or beginning where it last left
//  off.
//
//  IndexKey is an optional point at which to begin the enumeration.  The
//  seek position of IndexHandle is set to return the next logical record
//  on the next NtOfsReadRecords call.
//
//  NtOfsReadRecords will seek to the appropriate point in the BTree (as defined
//  by the IndexKey or saved position and the CollateFunction) and begin calling
//  MatchFunction for each record.  It continues doing this while MatchFunction
//  returns STATUS_SUCCESS.  If MatchFunction returns STATUS_NO_MORE_MATCHES,
//  NtOfsReadRecords will cache this result and not call MatchFunction again until
//  called with a non-NULL IndexKey.
//
//  NtOfsReadRecords returns the last status code returned by MatchFunction.
//
//  The IndexHandle does not have to be acquired as it is acquired shared for the
//  duration of the call.  NtOfsReadRecords may
//  return with STATUS_SUCCESS without filling the output buffer (say, every 10
//  index pages) to reduce lock contention.
//
//  NtOfsReadRecords will read up to Count rows, comprising up to BufferLength
//  bytes in total and will fill in the Rows[] array for each row returned.
//
//  Note that this call is self-synchronized, such that successive calls to
//  the routine are guaranteed to make progress through the index and to return
//  items in Collation order, in spite of Add and Delete record calls being
//  interspersed with Read records calls.
//

NTFSAPI
NTSTATUS
NtOfsReadRecords (
        IN PIRP_CONTEXT IrpContext,
        IN INDEX_HANDLE IndexHandle,
        IN OUT PREAD_CONTEXT *ReadContext,
        IN OPTIONAL PINDEX_KEY IndexKey,
        IN PMATCH_FUNCTION MatchFunction,
        IN PVOID MatchData,
        IN OUT ULONG *Count,
        OUT PINDEX_ROW Rows,
        IN ULONG BufferLength,
        OUT PVOID Buffer
        );

NTFSAPI
VOID
NtOfsFreeReadContext (
        IN PREAD_CONTEXT ReadContext
        );

//
//  NtOfsUpdateRecord updates a single record in place.  It is guaranteed that the
//  length of the data/key portion of the record does not change.  The index will
//  be acquired exclusive for this call.
//
//  This call may update the IndexHandle seek position
//

NTFSAPI
VOID
NtOfsUpdateRecord (
    IN PIRP_CONTEXT IrpContext,
    IN INDEX_HANDLE IndexHandle,
    IN ULONG Count,
    IN PINDEX_ROW IndexRow,
    IN OUT PQUICK_INDEX_HINT QuickIndexHint OPTIONAL,
    IN OUT PMAP_HANDLE MapHandle OPTIONAL
    );

//
//  NtOfsCloseIndex closes an index handle.  The index must not be acquired for this
//  call.  No outstanding maps are allowed.
//

NTFSAPI
VOID
NtOfsCloseIndex (
    IN PIRP_CONTEXT IrpContext,
    IN INDEX_HANDLE IndexHandle
    );

//
//  NtOfsDeleteIndex removes an index attribute from an object.  The object will be
//  acquired exclusive for this call.
//

NTFSAPI
VOID
NtOfsDeleteIndex (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ObjectHandle,
    IN INDEX_HANDLE IndexHandle
    );

////////////////////////////////////////////////////////////////////////////////

//
//  Map API - These encapsulate the NtOfs/Cache manager interactions
//

//
//  NtOfsInitializeMapHandle initializes a map handle so it can be safely
//  released at any time.
//
//  NTFSAPI
//  VOID
//  NtOfsInitializeMapHandle (
//      IN PMAP_HANDLE Map
//      );
//

#define NtOfsInitializeMapHandle( M ) { (M)->Bcb = NULL; }

//
//  NtOfsMapAttribute maps a portion of the specified attribute and returns a pointer
//  to the memory.  The memory mapped may not span a mapping window.  Multiple maps
//  are allowed through different handles in different threads.  The data is not
//  preread nor is the memory pinned.
//


#ifndef _NTFSPROC_
NTFSAPI
VOID
NtOfsMapAttribute (
    IN PIRP_CONTEXT IrpContext,
    IN ATTRIBUTE_HANDLE Attribute,
    IN LONGLONG Offset,
    IN ULONG Length,
    OUT PVOID *Buffer,
    OUT PMAP_HANDLE MapHandle
    );

#else
#ifdef MAPCOUNT_DBG
#define NtOfsMapAttribute(I,S,O,L,B,M) (                                             \
    CcMapData((S)->FileObject, (PLARGE_INTEGER)&(O), (L), TRUE, &(M)->Bcb, (B)),     \
    (I)->MapCount++,                                                                 \
    (M)->FileOffset = (O),                                                           \
    (M)->Length = (L),                                                               \
    (M)->Buffer = *(PVOID *)(B)                                                      \
)
#else
#define NtOfsMapAttribute(I,S,O,L,B,M) (                                             \
    CcMapData((S)->FileObject, (PLARGE_INTEGER)&(O), (L), TRUE, &(M)->Bcb, (B)),     \
    (M)->FileOffset = (O),                                                           \
    (M)->Length = (L),                                                               \
    (M)->Buffer = *(PVOID *)(B)                                                      \
)
#endif
#endif

//
//  NtOfsPreparePinWrite maps and pins a portion of the specified attribute and
//  returns a pointer to the memory.  This is equivalent to doing a NtOfsMapAttribute
//  followed by NtOfsPinRead and NtOfsDirty but is more efficient.
//

#ifndef _NTFSPROC_
NTFSAPI
VOID
NtOfsPreparePinWrite (
    IN PIRP_CONTEXT IrpContext,
    IN ATTRIBUTE_HANDLE Attribute,
    IN LONGLONG Offset,
    IN ULONG Length,
    OUT PVOID *Buffer,
    OUT PMAP_HANDLE MapHandle
    );

#else
#ifdef MAPCOUNT_DBG
#define NtOfsPreparePinWrite(I,S,O,L,B,M) {                                                     \
    if (((O) + (L)) > (S)->Header.AllocationSize.QuadPart) {                                    \
        ExRaiseStatus(STATUS_END_OF_FILE);                                                      \
    }                                                                                           \
    CcPreparePinWrite((S)->FileObject, (PLARGE_INTEGER)&(O), (L), FALSE, TRUE, &(M)->Bcb, (B)); \
    (I)->MapCount++;                                                                            \
    (M)->FileOffset = (O);                                                                      \
    (M)->Length = (L);                                                                          \
    (M)->Buffer = (B);                                                                          \
}
#else
#define NtOfsPreparePinWrite(I,S,O,L,B,M) {                                                     \
    if (((O) + (L)) > (S)->Header.AllocationSize.QuadPart) {                                    \
        ExRaiseStatus(STATUS_END_OF_FILE);                                                      \
    }                                                                                           \
    CcPreparePinWrite((S)->FileObject, (PLARGE_INTEGER)&(O), (L), FALSE, TRUE, &(M)->Bcb, (B)); \
    (M)->FileOffset = (O);                                                                      \
    (M)->Length = (L);                                                                          \
    (M)->Buffer = (B);                                                                          \
}
#endif
#endif

//
//  NtOfsPinRead pins a section of a map and read in all pages from the mapped
//  attribute.  Offset and Length must describe a byte range which is equal to
//  or included by the original mapped range.
//

#ifndef _NTFSPROC_
NTFSAPI
VOID
NtOfsPinRead(
    IN PIRP_CONTEXT IrpContext,
    IN ATTRIBUTE_HANDLE Attribute,
    IN LONGLONG Offset,
    IN ULONG Length,
    OUT PMAP_HANDLE MapHandle
    );

#else
#ifdef MAPCOUNT_DBG
#define NtOfsPinRead(I,S,O,L,M) {                                                           \
    ASSERT((M)->Bcb != NULL);                                                               \
    ASSERT(((O) >= (M)->FileOffset) && (((O) + (L)) <= ((M)->FileOffset + (M)->Length)));   \
    CcPinMappedData((S)->FileObject, (PLARGE_INTEGER)&(O), (L), TRUE, &(M)->Bcb);           \
    (I)->MapCount++;                                                                        \
    (M)->FileOffset = (O);                                                                  \
    (M)->Length = (L);                                                                      \
}
#else
#define NtOfsPinRead(I,S,O,L,M) {                                                           \
    ASSERT((M)->Bcb != NULL);                                                               \
    ASSERT(((O) >= (M)->FileOffset) && (((O) + (L)) <= ((M)->FileOffset + (M)->Length)));   \
    CcPinMappedData((S)->FileObject, (PLARGE_INTEGER)&(O), (L), TRUE, &(M)->Bcb);           \
    (M)->FileOffset = (O);                                                                  \
    (M)->Length = (L);                                                                      \
}
#endif
#endif

//
//  NtOfsDirty marks a map as being dirty (eligible for lazy writer access) and
//  marks the pages with an optional LSN for coordination with LFS.  This call
//  is invalid unless the map has been pinned.
//

//  NTFSAPI
//  NtOfsDirty (
//      IN PIRP_CONTEXT IrpContext,
//      IN PMAP_HANDLE MapHandle,
//      PLSN Lsn OPTIONAL
//      );

#define NtOfsDirty(I,M,L) {CcSetDirtyPinnedData((M)->Bcb,(L));}

//
//  NtOfsReleaseMap unmaps/unpins a mapped portion of an attribute.
//


#ifndef _NTFSPROC_
NTFSAPI
VOID
NtOfsReleaseMap (
    IN PIRP_CONTEXT IrpContext,
    IN PMAP_HANDLE MapHandle
    );

#else

#ifdef MAPCOUNT_DBG
#define NtOfsReleaseMap(IC,M) {                             \
    if ((M)->Bcb != NULL) {                                 \
        CcUnpinData((M)->Bcb);                              \
        (IC)->MapCount--;                                   \
        (M)->Bcb = NULL;                                    \
    }                                                       \
}
#else
#define NtOfsReleaseMap(IC,M) {                             \
    if ((M)->Bcb != NULL) {                                 \
        CcUnpinData((M)->Bcb);                              \
        (M)->Bcb = NULL;                                    \
    }                                                       \
}
#endif
#endif

//
//  NtOfsPutData writes data into an attribute in a recoverable fashion.  The
//  caller must have opened the attribute with LogNonresidentToo.
//
//  NtOfsPutData will write the data atomically and update the mapped image,
//  subject to the normal lazy commit of the transaction.
//

NTFSAPI
VOID
NtOfsPutData (
    IN PIRP_CONTEXT IrpContext,
    IN ATTRIBUTE_HANDLE Attribute,
    IN LONGLONG Offset,
    IN ULONG Length,
    IN PVOID Data OPTIONAL
    );


////////////////////////////////////////////////////////////////////////////////

//
//  Attribute API - These encapsulate access to attributes on files/directories
//  and summary catalogs
//

//
//  NtOfsCreateAttribute will create or open a data attribute and return a handle
//  that will allow mapping operations.
//
//  For attributes that wish to have logging behavior, LogNonresidentToo must be
//  set to true.  See the discussion on NtOfsPutData (in the mapping section
//  above).
//

NTFSAPI
NTSTATUS
NtOfsCreateAttribute (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ObjectHandle,
    IN UNICODE_STRING Name,
    IN CREATE_OPTIONS CreateOptions,
    IN ULONG LogNonresidentToo,
    OUT ATTRIBUTE_HANDLE *AttributeHandle
    );

//
//  NtOfsCreateAttributeEx will create or open an attribute and return a handle
//  that will allow mapping operations.  If a standard data attribute is to be
//  used, call NtOfsCreateAttribute instead.  This function is here for callers
//  who need to use a different attribute type code.
//
//  For attributes that wish to have logging behavior, LogNonresidentToo must be
//  set to true.  See the discussion on NtOfsPutData (in the mapping section
//  above).
//

NTFSAPI
NTSTATUS
NtOfsCreateAttributeEx (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ObjectHandle,
    IN UNICODE_STRING Name,
    IN ULONG AttributeTypeCode,
    IN CREATE_OPTIONS CreateOptions,
    IN ULONG LogNonresidentToo,
    OUT ATTRIBUTE_HANDLE *AttributeHandle
    );

//
//  Valid AttributeTypeCode values for NtOfsCreateAttributeEx:
//

#define $LOGGED_UTILITY_STREAM           (0x100)


//
//  NtOfsCloseAttribute releases the attribute.  The attribute is not acquired.  No
//  outstanding maps are active.
//

NTFSAPI
VOID
NtOfsCloseAttribute (
    IN PIRP_CONTEXT IrpContext,
    IN ATTRIBUTE_HANDLE AttributeHandle
    );

//
//  NtOfsDeleteAttribute releases all storage associated with the attribute.  The
//  object will be acquired exclusive.  The attribute will be acquired exclusive.
//  No outstanding maps are active.
//

NTFSAPI
VOID
NtOfsDeleteAttribute (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ObjectHandle,
    IN ATTRIBUTE_HANDLE AttributeHandle
    );

//
//  NtOfsQueryLength returns the current length of user data within the attribute.
//  The attribute may be mapped.  The attribute may be acquired.
//

NTFSAPI
LONGLONG
NtOfsQueryLength (
    IN ATTRIBUTE_HANDLE AttributeHandle
    );

//
//  NtOfsSetLength sets the current EOF on the given attribute.  The attribute
//  may not be mapped to the view containing Length, or any subsequent view.
//  The attribute will be acquired exclusive.
//

NTFSAPI
VOID
NtOfsSetLength (
    IN PIRP_CONTEXT IrpContext,
    IN ATTRIBUTE_HANDLE Attribute,
    IN LONGLONG Length
    );
//
//  NtOfsWaitForNewLength allows the caller to wait for the specified length to
//  be exceeded, or optionally timeout, if the specified Irp has not been cancelled.
//

NTFSAPI
NTSTATUS
NtOfsWaitForNewLength (
    IN ATTRIBUTE_HANDLE Attribute,
    IN LONGLONG Length,
    IN ULONG Async,
    IN PIRP Irp,
    IN PDRIVER_CANCEL CancelRoutine,
    IN PLARGE_INTEGER Timeout OPTIONAL
    );

//
//  This routine may be called any time FileSize has changed to wake any threads
//  waiting for a particular FileSize change.  Or specify WakeAll to unconditionally
//  wake all waiters.
//

VOID
NtOfsPostNewLength (
    IN PIRP_CONTEXT IrpContext OPTIONAL,
    IN ATTRIBUTE_HANDLE Attribute,
    IN BOOLEAN WakeAll
    );

//
//  NtOfsDecommit releases storage associated with a range of the attribute.  It does
//  not change the EOF marker nor does it change the logical position of data within
//  the attribute.  The range of the attribute being released may be mapped or
//  pinned.
//
//  Reads from decommitted ranges should return zero (although Query will never read
//  from these ranges).
//
//  Writes to decommitted pages should fail or be nooped (although Query will never
//  write to these ranges).
//
//  This call will purge, so none of the views overlapping the specified range may
//  be mapped.
//

NTFSAPI
VOID
NtOfsDecommit (
    IN PIRP_CONTEXT IrpContext,
    IN ATTRIBUTE_HANDLE Attribute,
    IN LONGLONG Offset,
    IN LONGLONG Length
    );

//
//  NtOfsFlushAttribute flushes all cached data to the disk and returns upon
//  completion.  If the attribute is LogNonresidentToo, then only the log file
//  is flushed.  Optionally, the range may be purged as well.  If the attribute
//  is purged, then there can be no mapped views.
//

NTFSAPI
VOID
NtOfsFlushAttribute (
    IN PIRP_CONTEXT IrpContext,
    IN ATTRIBUTE_HANDLE Attribute,
    IN ULONG Purge
    );

//
//  NtOfsQueryAttributeSecurityId returns the security ID for the attribute if
//  present.
//

NTFSAPI
VOID
NtOfsQueryAttributeSecurityId (
    IN PIRP_CONTEXT IrpContext,
    IN ATTRIBUTE_HANDLE Attribute,
    OUT SECURITY_ID *SecurityId
    );

////////////////////////////////////////////////////////////////////////////////

//
//  Concurrency control API
//
//  As a rule, these routines are not required.  All NtOfs routines are
//  self-synchronized as atomic actions, or as parts of a top-level action when
//  called within a top-level action routine.
//
//  ISSUE:  In particular, supporting the exclusive access call is an implementation
//          problem for Ntfs.  Wrapping top-level actions is the best way to preserve
//          exclusive access across calls.
//

VOID
NtOfsAcquireObjectShared (
    HANDLE ObjectHandle
    );

//  VOID
//  NtOfsAcquireObjectExclusive (
//      HANDLE ObjectHandle
//      );

VOID
NtOfsReleaseObject (
    HANDLE ObjectHandle
    );

//  Debugging routines
BOOLEAN
NtOfsIsObjectAcquiredExclusive (
    HANDLE ObjectHandle
    );

BOOLEAN
NtOfsIsObjectAcquiredShared (
    HANDLE ObjectHandle
    );


////////////////////////////////////////////////////////////////////////////////

//
//  File/Directory/Etc API
//

//
//  NtOfsOpenByFileReference opens an object given a file reference.  The file is
//  assumed to exist; this call cannot be used to create a file.  The returned
//  handle is acquired according to the input exclusion.
//

NTFSAPI
NTSTATUS
NtOfsOpenByFileReference (
    IN PIRP_CONTEXT IrpContext,
    IN FILE_REFERENCE FileReference,
    IN EXCLUSION Exclusion,
    OUT OBJECT_HANDLE *ObjectHandle
    );

//
//  NtOfsCreateRelativeObject opens or creates an object relative to a specified
//  parent object.  The parent will be acquired exclusive.  The child is opened
//  acquired according to the input exclusion.
//
//  ISSUE:  When creating an object, is the transaction committed before this
//  call returns?
//

NTFSAPI
NTSTATUS
NtOfsCreateRelativeObject (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ParentObjectHandle,
    IN UNICODE_STRING Name,
    IN CREATE_OPTIONS CreateOptions,
    IN EXCLUSION Exclusion,
    OUT OBJECT_HANDLE *ObjectHandle
    );

//
//  NtOfsCloseObject releases the object handle.
//

NTFSAPI
NTSTATUS
NtOfsCloseObject (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ObjectHandle
    );

//
//  NtOfsDeleteObject deletes the object.  No user-mode handle is attached to
//  the object.  No attributes are currently open.  The object is acquired
//  exclusive.
//

NTFSAPI
NTSTATUS
NtOfsDeleteObject (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ObjectHandle
    );

//
//  NtOfsDeleteAllAttributes deletes all attributes of the object.  No attribute
//  is open.  The object is acquired exclusive.
//

NTFSAPI
NTSTATUS
NtOfsDeleteAllAttributes (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ObjectHandle
    );

//
//  NtOfsQueryPathFromRoot returns *A* path from the root to a node.  In the
//  presence of hard links, several paths may exist, however, only one needs
//  to be returned.  Memory for the file name is provided by the caller.
//

NTFSAPI
NTSTATUS
NtOfsQueryPathFromRoot (
    IN PIRP_CONTEXT IrpContext,
    IN FILE_REFERENCE FileReference,
    OUT UNICODE_STRING *PathName
    );

//
//  NtOfsQueryFileName returns the final component in the path name into a
//  caller-supplied buffer.  In the presence of hard links, several names
//  may exist, however, only one needs to be returned.
//

NTFSAPI
NTSTATUS
NtOfsQueryFileName (
    IN PIRP_CONTEXT IrpContext,
    IN FILE_REFERENCE FileReference,
    OUT UNICODE_STRING *FileName
    );

//
//  NtOfsQueryFileReferenceFromName returns the file reference named by the path
//

NTFSAPI
NTSTATUS
NtOfsQueryFileReferenceFromName (
    IN PIRP_CONTEXT IrpContext,
    IN UNICODE_STRING Name,
    OUT FILE_REFERENCE *FileReference
    );

//
//  This call must be very fast;  it is a very common call made by CI/Query.
//

NTFSAPI
NTSTATUS
NtOfsQueryFileReferenceFromHandle (
    IN OBJECT_HANDLE Object,
    OUT FILE_REFERENCE *FileReference
    );

//
//  NtOfsQueryObjectSecurityId returns the security Id associated with an object.
//  The object is acquired shared or exclusive.  This call must be very fast
//

NTFSAPI
NTSTATUS
NtOfsQueryObjectSecurityId (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ObjectHandle,
    OUT SECURITY_ID *SecurityId
    );


////////////////////////////////////////////////////////////////////////////////

//
//  Scope API
//

//
//  NtOfsIsAncestorOf must quickly tell if one file is an ancestor of the given
//  child.  In the presence of hard links, we may pick a "preferred" path (i.e.
//  we don't have to travel to all ancestors).  This call must be reasonably fast
//  since this is a very frequent call from Query.
//

NTFSAPI
NTSTATUS
NtOfsIsAncestorOf (
    IN PIRP_CONTEXT IrpContext,
    IN FILE_REFERENCE Ancestor,
    IN FILE_REFERENCE Child
    );

//
//  NtOfsGetParentFileReferenceFromHandle is used to retrieve the FileReference
//  of the parent of the named object.  With hard links the "first" parent may
//  be chosen.  This call needs to be reasonably efficient.
//

NTFSAPI
NTSTATUS
NtOfsGetParentFileReferenceFromHandle (
    IN PIRP_CONTEXT IrpContext,
    IN OBJECT_HANDLE ChildObject,
    OUT FILE_REFERENCE *ParentFileReference
    );


////////////////////////////////////////////////////////////////////////////////

//
//  Security API
//
//  NtOfs maintains a "per-IrpContext" cache that speeds up security validation.
//  Clients clear the cache (at the beginning of a query, say) and then do
//  successive probes which may populate the cache.
//

//
//  NtOfsClearSecurityCache clears the cache.
//

NTFSAPI
NTSTATUS
NtOfsClearSecurityCache (
    IN PIRP_CONTEXT IrpContext
    );

//
//  NtOfsIsAccessGranted uses the Se routines to validate access and caches the
//  result for the specified SecurityId and DesiredAccess.  The cache is first
//  probed to see if the access can be granted immediately.  If the SecurityId is
//  not found, the corresponding ACL is retrieved and tested with the supplied
//  access state and DesiredAccess.  The result of this test is cached and
//  returned.
//

NTFSAPI
NTSTATUS
NtOfsIsAccessGranted (
    IN PIRP_CONTEXT IrpContext,
    IN SECURITY_ID SecurityId,
    IN ACCESS_MASK DesiredAccess,
    IN ACCESS_STATE *SecurityAccessState
    );


////////////////////////////////////////////////////////////////////////////////

//
//  Worker thread stuff.  Worker threads are needed for building new indexes
//


////////////////////////////////////////////////////////////////////////////////

//
//  Miscellaneous information query/set
//

//
//  Content Index may need to mark the volume as dirty to allow garbage collection
//  of orphan objects by CHKDSK.
//

NTFSAPI
NTSTATUS
NtOfsMarkVolumeCorrupt (
    IN PIRP_CONTEXT IrpContext,
    IN ULONG NewState,
    IN ULONG StateMask,
    OUT ULONG *OldState
    );

//
//  NtOfsQueryVolumeStatistics returns the current capacity and free space on a
//  volume.  Ci uses this for heuristics to decide on when to trigger master merge,
//  when to suppress master merge, etc.
//

NTFSAPI
NTSTATUS
NtOfsQueryVolumeStatistics (
    IN PIRP_CONTEXT IrpContext,
    OUT LONGLONG *TotalClusters,
    OUT LONGLONG *FreeClusters
    );

//
//  Query needs to retain some state in the NtOfs Ccb.
//

NTFSAPI
NTSTATUS
NtOfsQueryHandleState (
    IN PIRP_CONTEXT IrpContext,
    OUT VOID *OldData
    );

NTFSAPI
NTSTATUS
NtOfsSetHandleState (
    IN PIRP_CONTEXT IrpContext,
    IN VOID *Data
    );

//
//  Generic unwrapping routines that get access to SCB/IRPC and FCB/IRPC
//  pairs.
//

NTFSAPI
NTSTATUS
NtOfsQueryAttributeHandle (
    IN PIRP_CONTEXT IrpContext,
    OUT ATTRIBUTE_HANDLE *AttributeHandle
    );

NTFSAPI
NTSTATUS
NtOfsQueryObjectHandle (
    IN PIRP_CONTEXT IrpContext,
    OUT OBJECT_HANDLE *ObjectHandle
    );

//
//  Create a context in which the caller can perform I/O in separate.
//  threads.  This means creating an IRP/IRP_CONTEXT.  Each IrpContext corresponds
//  to one I/O activity at a time.  Multiple IrpContexts may be active in a thread
//  at a single time.
//

NTFSAPI
NTSTATUS
NtOfsCloneIrpContext (
    IN PIRP_CONTEXT IrpContext,
    OUT PIRP_CONTEXT *NewIrpContext
    );

//
//  NtOfsCompleteRequest completes an IrpContext that has been previously cloned.
//  All other FsCtl Irps are completed by Ntfs.
//

NTFSAPI
NTSTATUS
NtOfsCompleteRequest (
    IN PIRP_CONTEXT IrpContext,
    NTSTATUS Status
    );


////////////////////////////////////////////////////////////////////////////////

//
//  Iterators.  While each iterator is created through a separate API, each one
//  must support two operations:
//      Next - this fills a buffer with as many records as possible
//      Close - this releases the iterator.
//

typedef struct _BASE_FILE_SEGMENT_ITERATOR BASE_FILE_SEGMENT_ITERATOR;

typedef struct _USN_ITERATOR USN_ITERATOR;

//
//  The types of iterators are:
//
//      Scope            iterate over a directory (optionally RECURSIVE)
//                       (implemented in Query)
//      View             iterate over the rows in a view with a partial key match
//                       (implemented in View)
//      BaseFileSegment  iterate over all base file record segments
//                       (implemented in NtOfs)
//      SummaryCatalog   iterate over all rows in a summary catalog
//      Usn              iterate over all objects with Usn's in a specific range
//                       (implmented in NtOfs)
//
//  Each iteration is passed a buffer which is filled (as much as possible) with
//  a packed array of:
//      FILE_REFERENCE
//      DUPLICATED_INFORMATION
//      STAT_INFORMATION
//  for each enumerated object.  The output length is the length in bytes that
//  was filled in with the enumeration request.

NTFSAPI
NTSTATUS
NtOfsCreateBaseFileSegmentIterator (
    IN PIRP_CONTEXT IrpContext,
    OUT BASE_FILE_SEGMENT_ITERATOR *Iterator
    );

NTFSAPI
NTSTATUS
NtOfsNextBaseFileSegmentIteration (
    IN PIRP_CONTEXT IrpContext,
    IN BASE_FILE_SEGMENT_ITERATOR *Iterator,
    IN OUT ULONG *BufferLength,
    IN OUT PVOID Buffer
    );

NTFSAPI
NTSTATUS
NtOfsCloseBaseFileSegmentIterator (
    IN PIRP_CONTEXT IrpContext,
    IN BASE_FILE_SEGMENT_ITERATOR *Iterator
    );

NTFSAPI
NTSTATUS
NtOfsCreateUsnIterator (
    IN PIRP_CONTEXT IrpContext,
    IN USN BeginningUsn,
    IN USN EndingUsn,
    OUT USN_ITERATOR *Iterator
    );

NTFSAPI
NTSTATUS
NtOfsNextUsnIteration (
    IN PIRP_CONTEXT IrpContext,
    IN USN_ITERATOR *Iterator,
    IN OUT ULONG *BufferLength,
    IN OUT PVOID Buffer
    );

NTFSAPI
NTSTATUS
NtOfsCloseUsnIterator (
    IN PIRP_CONTEXT IrpContext,
    IN USN_ITERATOR *Iterator
    );


////////////////////////////////////////////////////////////////////////////////

//
//  Infrastructure support.
//
//  V/C/X register callbacks with NtOfs when they are loaded.  Until they are loaded
//  NtOfs will call default routines (that do nothing).
//

typedef enum _NTFS_ADDON_TYPES {
    Encryption = 3
} NTFS_ADDON_TYPES;


////////////////////////////////////////////////////////////////////////////////

//
//  Encryption
//

//
//  Stream Create Status       for FileDirFlag
//

#define STREAM_NEW_OR_EXIST_MASK  0x000f0000
#define FILE_DIR_TYPE_MASK        0x000000ff

#define FILE_NEW                  0x00000001
#define FILE_EXISTING             0x00000002
#define DIRECTORY_NEW             0x00000004
#define DIRECTORY_EXISTING        0x00000008
#define EXISTING_FILE_ENCRYPTED   0x00000010
#define STREAM_NEW                0x00010000
#define STREAM_EXISTING           0x00020000

//
//  Encryption flag         for EncryptionFlag
//

#define STREAM_ENCRYPTED          0x00000001
#define FILE_ENCRYPTED            0x00000002

//
//  Access flags
//
//  NB -- These values are NOT arbitrary.  Notice also that they are not
//        in value order, they are grouped according to their meaning.
//        Their values correspond to FILE_READ_DATA, etc. and
//        TOKEN_HAS_BACKUP_PRIVILEGE, etc.
//

#define READ_DATA_ACCESS          0x01
#define WRITE_DATA_ACCESS         0x02
#define APPEND_DATA_ACCESS        0x04
#define EXECUTE_ACCESS            0x20
#define READ_ATTRIBUTES_ACCESS    0x80
#define WRITE_ATTRIBUTES_ACCESS   0x100

#define BACKUP_ACCESS             0x08
#define RESTORE_ACCESS            0x10
#define TRAVERSE_ACCESS           0x40
#define MANAGE_VOLUME_ACCESS      0x200

//
//  Volume State
//

#define READ_ONLY_VOLUME         0x00000001

typedef NTSTATUS
(*ENCRYPTED_FILE_CREATE) (
    IN OBJECT_HANDLE FileHdl,
    IN OBJECT_HANDLE ParentDir OPTIONAL,
    IN PIO_STACK_LOCATION IrpSp,
    IN ULONG FileDirFlag,
    IN ULONG VolumeState,
    IN PIRP_CONTEXT IrpContext,
    IN PDEVICE_OBJECT VolDo,
    IN PVOID FileKeyContext,
    IN OUT PVOID *PKeyContext,
    IN OUT ULONG *ContextLength,
    IN OUT PVOID *PCreateContext,
    IN OUT PBOOLEAN Reserved
    );

typedef NTSTATUS
(*ENCRYPTED_FILE_PRE_CREATE) (
    IN PDEVICE_OBJECT VolDo,
    IN PIRP Irp,
    IN PFILE_OBJECT FileObject
    );

typedef NTSTATUS
(*ENCRYPTED_FILE_POST_CREATE) (
    IN PDEVICE_OBJECT VolDo,
    IN PIRP Irp,
    IN PFILE_OBJECT FileObject,
    IN NTSTATUS Status,
    IN OUT PVOID *PCreateContext
    );

typedef NTSTATUS
(*ENCRYPTED_FILE_SYSTEM_CONTROL) (
    IN PVOID PInputBuffer OPTIONAL,
    IN ULONG InputDataLength,
    OUT PVOID OutputBuffer OPTIONAL,
    IN OUT ULONG *OutputBufferLength OPTIONAL,
    IN ULONG EncryptionFlag,
    IN ULONG AccessFlag,
    IN ULONG VolumeState,
    IN ULONG FsControlCode,
    IN OBJECT_HANDLE FileHdl,
    IN PIRP_CONTEXT IrpContext,
    IN PDEVICE_OBJECT VolDo,
    IN ATTRIBUTE_HANDLE Attribute,
    IN OUT PVOID *PContext OPTIONAL,
    IN OUT ULONG *ContextLength OPTIONAL
    );

typedef NTSTATUS
(*ENCRYPTED_FILE_PRE_FILE_SYSTEM_CONTROL) (
    IN PDEVICE_OBJECT VolDo,
    IN PIRP Irp,
    IN PFILE_OBJECT FileObject
    );

typedef NTSTATUS
(*ENCRYPTED_FILE_READ)(
    IN OUT PUCHAR InOutBuffer,
    IN PLARGE_INTEGER Offset,
    IN ULONG BufferSize,
    IN PVOID Context
    );

typedef NTSTATUS
(*ENCRYPTED_FILE_WRITE)(
    IN PUCHAR InBuffer,
    OUT PUCHAR OutBuffer,
    IN PLARGE_INTEGER Offset,
    IN ULONG BufferSize,
    IN PUCHAR Context
    );

typedef VOID
(*ENCRYPTED_FILE_CLEANUP)(
    IN OUT PVOID *Context
    );

#define ENCRYPTION_CURRENT_INTERFACE_VERSION 3

#define ENCRYPTION_ALL_STREAMS       0x00000001
#define ENCRYPTION_ALLOW_COMPRESSION 0x00000002

typedef struct _ENCRYPTION_CALL_BACK {
    ULONG InterfaceVersion;
    ULONG ImplementationFlags;
    ENCRYPTED_FILE_CREATE FileCreate;
    ENCRYPTED_FILE_PRE_CREATE PreCreate;
    ENCRYPTED_FILE_POST_CREATE PostCreate;
    ENCRYPTED_FILE_SYSTEM_CONTROL FileSystemControl_1;
    ENCRYPTED_FILE_SYSTEM_CONTROL FileSystemControl_2;
    ENCRYPTED_FILE_PRE_FILE_SYSTEM_CONTROL PreFileSystemControl;
    ENCRYPTED_FILE_READ AfterReadProcess;
    ENCRYPTED_FILE_WRITE BeforeWriteProcess;
    ENCRYPTED_FILE_CLEANUP CleanUp;
} ENCRYPTION_CALL_BACK, *PENCRYPTION_CALL_BACK;

//
//  NtOfsRegisterCallBacks supplies a call table to NtOfs.  Each table has an
//  interface version number.  If the interface version does not exactly match
//  what NtOfs expects, the call will fail.
//

NTFSAPI
NTSTATUS
NtOfsRegisterCallBacks (
    NTFS_ADDON_TYPES NtfsAddonType,
    PVOID CallBackTable
    );

