/*++

Copyright (c) 1997-1999 Microsoft Corporation

Module Name:

    replutil.h

Abstract:

    Header file for utility routines for the NT File Replication Service.

Author:

    David A. Orbits (davidor)  3-Mar-1997 Created

Environment:

    User Mode Service

Revision History:

--*/
#ifndef _REPLUTIL_INCLUDED_
#define _REPLUTIL_INCLUDED_
#endif

#ifdef __cplusplus
extern "C" {
#endif



#include <frserror.h>

#include <config.h>


#define BACKSLASH_CHAR  TEXT('\\')
#define COLON_CHAR      TEXT(':')
#define DOT_CHAR        TEXT('.')

#define UNICODE_STAR    (L'*')
#define UNICODE_QMARK   (L'?')
#define UNICODE_SPACE   0x0020
#define UNICODE_TAB     0x0009


#define TIME_STRING_LENGTH 32
//
// The maximum length of a volume label.  This is defined in ntos\inc\io.h
// but since this is the only def needed from io.h it is copied here.  sigh!
//
#define MAXIMUM_VOLUME_LABEL_LENGTH  (32 * sizeof(WCHAR)) // 32 characters

#define GUID_CHAR_LEN 40

#define OBJECT_ID_LENGTH  sizeof(GUID)
#define FILE_ID_LENGTH    sizeof(ULONGLONG)

#define GUIDS_EQUAL(_a_, _b_) (memcmp((_a_), (_b_), sizeof(GUID)) == 0)
#define COPY_GUID(_a_, _b_)    CopyMemory((_a_), (_b_), sizeof(GUID))

#define IS_GUID_ZERO(_g_) ((*((PULONG)(_g_)+0) |                     \
                            *((PULONG)(_g_)+1) |                     \
                            *((PULONG)(_g_)+2) |                     \
                            *((PULONG)(_g_)+3) ) == 0)


#define COPY_TIME(_a_, _b_)   CopyMemory((_a_), (_b_), sizeof(FILETIME))

#define IS_TIME_ZERO(_g_) ((*((PULONG)(&(_g_))+0) | *((PULONG)(&(_g_))+1) ) == 0)

//
// A few macros for working with MD5 checksums.
//
#define IS_MD5_CHKSUM_ZERO(_x_)                                              \
    (((*(((PULONG) (_x_))+0)) | (*(((PULONG) (_x_))+1)) |                    \
      (*(((PULONG) (_x_))+2)) | (*(((PULONG) (_x_))+3)) ) == (ULONG) 0)

#define MD5_EQUAL(_a_, _b_) (memcmp((_a_), (_b_), MD5DIGESTLEN) == 0)



//
// Is a handle valid?
//      Some functions set the handle to NULL and some to
//      INVALID_HANDLE_VALUE (-1). This define handles both
//      cases.
//
#define HANDLE_IS_VALID(_Handle)  ((_Handle) && ((_Handle) != INVALID_HANDLE_VALUE))

//
// Only close valid handles and then set the handle invalid.
//   FRS_CLOSE(handle);
//
#define FRS_CLOSE(_Handle)                                                   \
    if (HANDLE_IS_VALID(_Handle)) {                                          \
        CloseHandle(_Handle);                                                \
        (_Handle) = INVALID_HANDLE_VALUE;                                    \
    }



DWORD
FrsResetAttributesForReplication(
    PWCHAR  Name,
    HANDLE  Handle
    );

LONG
FrsIsParent(
    IN PWCHAR   Directory,
    IN PWCHAR   Path
    );

LPTSTR
FrsSupInitPath(
    OUT LPTSTR OutPath,
    IN  LPTSTR InPath,
    IN  ULONG  MaxOutPath
    );

ULONG
FrsForceDeleteFile(
    PTCHAR DestName
    );

HANDLE
FrsCreateEvent(
    IN  BOOL    ManualReset,
    IN  BOOL    InitialState
    );

HANDLE
FrsCreateWaitableTimer(
    IN  BOOL    ManualReset
    );

ULONG
FrsUuidCreate(
    OUT GUID *Guid
    );

VOID
FrsNowAsFileTime(
    IN  PLONGLONG   Now
    );

VOID
FileTimeToString(
    IN FILETIME *FileTime,
    OUT PCHAR    Buffer         // buffer must be at least 32 bytes long.
    );


VOID
FileTimeToStringClockTime(
    IN FILETIME *FileTime,
    OUT PCHAR     Buffer        // buffer must be at least 9 bytes long.
    );

VOID
GuidToStr(
    IN GUID  *pGuid,
    OUT PCHAR  s
    );

VOID
GuidToStrW(
    IN GUID  *pGuid,
    OUT PWCHAR  ws
    );

BOOL
StrWToGuid(
    IN  PWCHAR  ws,
    OUT GUID  *pGuid
    );

VOID
StrToGuid(
    IN PCHAR  s,
    OUT GUID  *pGuid
    );

NTSTATUS
SetupOnePrivilege (
    ULONG Privilege,
    PUCHAR PrivilegeName
    );

PWCHAR
FrsGetResourceStr(
    LONG  Id
);


//
// Convenient DesiredAccess
//
#define READ_ATTRIB_ACCESS  (FILE_READ_ATTRIBUTES | SYNCHRONIZE)

#define WRITE_ATTRIB_ACCESS  (FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)

#define READ_ACCESS         (GENERIC_READ | GENERIC_EXECUTE | SYNCHRONIZE)

#define ATTR_ACCESS         (READ_ACCESS  | FILE_WRITE_ATTRIBUTES)

#define WRITE_ACCESS        (GENERIC_WRITE | GENERIC_EXECUTE | SYNCHRONIZE)

#define RESTORE_ACCESS      (READ_ACCESS        | \
                             WRITE_ACCESS       | \
                             WRITE_DAC          | \
                             WRITE_OWNER)

#define OPLOCK_ACCESS       (FILE_READ_ATTRIBUTES)

//
// Convenient CreateOptions
//
#define OPEN_OPTIONS        (FILE_OPEN_FOR_BACKUP_INTENT     | \
                             FILE_SEQUENTIAL_ONLY            | \
                             FILE_OPEN_NO_RECALL             | \
                             FILE_OPEN_REPARSE_POINT         | \
                             FILE_SYNCHRONOUS_IO_NONALERT)
#define ID_OPTIONS          (OPEN_OPTIONS | FILE_OPEN_BY_FILE_ID)

#define OPEN_OPLOCK_OPTIONS (FILE_RESERVE_OPFILTER | FILE_OPEN_REPARSE_POINT)
#define ID_OPLOCK_OPTIONS   (FILE_OPEN_FOR_BACKUP_INTENT | \
                             FILE_RESERVE_OPFILTER       | \
                             FILE_OPEN_REPARSE_POINT     | \
                             FILE_OPEN_BY_FILE_ID)

//
// convenient ShareMode
//
#define SHARE_ALL   (FILE_SHARE_READ |  \
                     FILE_SHARE_WRITE | \
                     FILE_SHARE_DELETE)
#define SHARE_NONE  (0)

//
// File attributes that prevent installation and prevent
// hammering the object id.
//
#define NOREPL_ATTRIBUTES   (FILE_ATTRIBUTE_READONLY | \
                             FILE_ATTRIBUTE_SYSTEM   | \
                             FILE_ATTRIBUTE_HIDDEN)

DWORD
FrsOpenSourceFileW(
    OUT PHANDLE     Handle,
    IN  LPCWSTR     lpFileName,
    IN  ACCESS_MASK DesiredAccess,
    IN  ULONG       CreateOptions
    );

DWORD
FrsOpenSourceFile2W(
    OUT PHANDLE     Handle,
    IN  LPCWSTR     lpFileName,
    IN  ACCESS_MASK DesiredAccess,
    IN  ULONG       CreateOptions,
    IN  ULONG       ShareMode
    );

DWORD
FrsCheckReparse(
    IN     PWCHAR Name,
    IN     PVOID  Id,
    IN     DWORD  IdLen,
    IN     HANDLE VolumeHandle
    );

DWORD
FrsDeleteReparsePoint(
    IN  HANDLE  Handle
    );

DWORD
FrsChaseSymbolicLink(
    IN  PWCHAR  SymLink,
    OUT PWCHAR  *OutPrintName,
    OUT PWCHAR  *OutSubstituteName
    );

DWORD
FrsTraverseReparsePoints(
    IN  PWCHAR  SuppliedPath,
    OUT PWCHAR  *RealPath
    );

DWORD
FrsOpenSourceFileById(
    OUT PHANDLE     Handle,
    OUT PFILE_NETWORK_OPEN_INFORMATION  FileOpenInfo,
    OUT OVERLAPPED  *OverLap,
    IN  HANDLE      VolumeHandle,
    IN  PVOID       ObjectId,
    IN  ULONG       Length,
    IN  ACCESS_MASK DesiredAccess,
    IN  ULONG       CreateOptions,
    IN  ULONG       ShareMode,
    IN  ULONG       CreateDispostion
    );

PWCHAR
FrsGetFullPathByHandle(
    IN PWCHAR   Name,
    IN HANDLE   Handle
    );

PWCHAR
FrsGetRelativePathByHandle(
    IN PWCHAR   Name,
    IN HANDLE   Handle
    );

DWORD
FrsCreateFileRelativeById(
    OUT PHANDLE Handle,
    IN  HANDLE  VolumeHandle,
    IN  PVOID   ParentObjectId,
    IN  ULONG   OidLength,
    IN  ULONG   FileCreateAttributes,
    IN  PWCHAR  BaseFileName,
    IN  USHORT  FileNameLength,
    IN  PLARGE_INTEGER  AllocationSize,
    IN  ULONG           CreateDisposition,
    IN  ACCESS_MASK     DesiredAccess
    );

DWORD
FrsOpenFileRelativeByName(
    IN  HANDLE     VolumeHandle,
    IN  PULONGLONG FileReferenceNumber,
    IN  PWCHAR     FileName,
    IN  GUID       *ParentGuid,
    IN  GUID       *FileGuid,
    OUT HANDLE     *Handle
    );

typedef struct _QHASH_TABLE_ QHASH_TABLE, *PQHASH_TABLE;
DWORD
FrsDeleteFileRelativeByName(
    IN  HANDLE       VolumeHandle,
    IN  GUID         *ParentGuid,
    IN  PWCHAR       FileName,
    IN  PQHASH_TABLE FrsWriteFilter
    );

DWORD
FrsDeleteFileObjectId(
    IN  HANDLE Handle,
    IN  LPCWSTR FileName
    );

DWORD
FrsGetOrSetFileObjectId(
    IN  HANDLE Handle,
    IN  LPCWSTR FileName,
    IN  BOOL CallerSupplied,
    OUT PFILE_OBJECTID_BUFFER ObjectIdBuffer
    );

DWORD
FrsReadFileUsnData(
    IN  HANDLE Handle,
    OUT USN *UsnBuffer
    );

DWORD
FrsMarkHandle(
    IN HANDLE   VolumeHandle,
    IN HANDLE   Handle
    );

DWORD
FrsReadFileParentFid(
    IN  HANDLE     Handle,
    OUT ULONGLONG *ParentFid
    );

DWORD
FrsDeletePath(
    IN  PWCHAR  Path,
    IN DWORD    DirectoryFlags
    );

DWORD
FrsRestrictAccessToFileOrDirectory(
    PWCHAR  Name,
    HANDLE  Handle,
    BOOL    NoInherit
    );


VOID
FrsAddToMultiString(
    IN     PWCHAR   AddStr,
    IN OUT DWORD    *IOSize,
    IN OUT DWORD    *IOIdx,
    IN OUT PWCHAR   *IOStr
    );

VOID
FrsCatToMultiString(
    IN     PWCHAR   CatStr,
    IN OUT DWORD    *IOSize,
    IN OUT DWORD    *IOIdx,
    IN OUT PWCHAR   *IOStr
    );

BOOL
FrsSearchArgv(
    IN LONG     ArgC,
    IN PWCHAR  *ArgV,
    IN PWCHAR   ArgKey,
    OUT PWCHAR *ArgValue
    );

BOOL
FrsSearchArgvDWord(
    IN LONG     ArgC,
    IN PWCHAR  *ArgV,
    IN PWCHAR   ArgKey,
    OUT PDWORD  ArgValue
    );

BOOL
FrsDissectCommaList (
    IN UNICODE_STRING RawArg,
    OUT PUNICODE_STRING FirstArg,
    OUT PUNICODE_STRING RemainingArg
    );

BOOL
FrsCheckNameFilter(
    IN  PUNICODE_STRING Name,
    IN  PLIST_ENTRY FilterListHead
    );

VOID
FrsEmptyNameFilter(
    IN PLIST_ENTRY FilterListHead
);

VOID
FrsLoadNameFilter(
    IN PUNICODE_STRING FilterString,
    IN PLIST_ENTRY FilterListHead
);

ULONG
FrsParseIntegerCommaList(
    IN PWCHAR ArgString,
    IN ULONG MaxResults,
    OUT PLONG Results,
    OUT PULONG NumberResults,
    OUT PULONG Offset
);

//
//  Unicode Name support routines, implemented in Name.c
//
//  The routines here are used to manipulate unicode names
//  The code is copied here from FsRtl because it calls the pool allocator.
//

//
//  The following macro is used to determine if a character is wild.
//
#define FrsIsUnicodeCharacterWild(C) (                               \
    (((C) == UNICODE_STAR) || ((C) == UNICODE_QMARK))                \
)

VOID
FrsDissectName (
    IN UNICODE_STRING Path,
    OUT PUNICODE_STRING FirstName,
    OUT PUNICODE_STRING RemainingName
    );

BOOLEAN
FrsDoesNameContainWildCards (
    IN PUNICODE_STRING Name
    );

BOOLEAN
FrsAreNamesEqual (
    IN PUNICODE_STRING ConstantNameA,
    IN PUNICODE_STRING ConstantNameB,
    IN BOOLEAN IgnoreCase,
    IN PCWCH UpcaseTable OPTIONAL
    );

BOOLEAN
FrsIsNameInExpression (
    IN PUNICODE_STRING Expression,
    IN PUNICODE_STRING Name,
    IN BOOLEAN IgnoreCase,
    IN PWCH UpcaseTable OPTIONAL
    );


//
// The following is taken from clusrtl.h
//
//
//  Routine Description:
//
//      Initializes the FRS run time library.
//
//  Arguments:
//
//      RunningAsService  - TRUE if the process is running as an NT service.
//                          FALSE if running as a console app.
//
//  Return Value:
//
//      ERROR_SUCCESS if the function succeeds.
//      A Win32 error code otherwise.
//
DWORD
FrsRtlInitialize(
    IN  BOOL    RunningAsService
    );


//
//  Routine Description:
//
//      Cleans up the FRS run time library.
//
//  Arguments:
//
//      RunningAsService  - TRUE if the process is running as an NT service.
//                          FALSE if running as a console app.
//
//  Return Value:
//
//      None.
//
VOID
FrsRtlCleanup(
    VOID
    );


//
//  PLIST_ENTRY
//  GetListHead(
//      PLIST_ENTRY ListHead
//      );
//
#define GetListHead(ListHead) ((ListHead)->Flink)

//
//  PLIST_ENTRY
//  GetListTail(
//      PLIST_ENTRY ListHead
//      );
//
#define GetListTail(ListHead) ((ListHead)->Blink)
//
//  PLIST_ENTRY
//  GetListNext(
//      PLIST_ENTRY Entry
//      );
//
#define GetListNext(Entry) ((Entry)->Flink)

//
//  VOID
//  FrsRemoveEntryList(
//      PLIST_ENTRY Entry
//      );
//
// *NOTE*  The Flink/Blink of the removed entry are set to NULL to cause an
// Access violation if a thread is following a list and an element is removed.
// UNFORTUNATELY there is still code that depends on this, perhaps through
// remove head/tail.  Sigh.  For now leave as is.
//
#define FrsRemoveEntryList(Entry) {\
    PLIST_ENTRY _EX_Blink;\
    PLIST_ENTRY _EX_Flink;\
    PLIST_ENTRY _EX_Entry;\
    _EX_Entry = (Entry);\
    _EX_Flink = _EX_Entry->Flink;\
    _EX_Blink = _EX_Entry->Blink;\
    _EX_Blink->Flink = _EX_Flink;\
    _EX_Flink->Blink = _EX_Blink;\
    _EX_Entry->Flink = _EX_Entry->Blink = _EX_Entry;\
    }


//
//  VOID
//  RemoveEntryListB(
//      PLIST_ENTRY Entry
//      );
//
// The BillyF version of remove entry list.  The Flink/Blink of the removed
// entry are set to the entry address.
//
#define RemoveEntryListB(Entry) {\
    PLIST_ENTRY _EX_Blink;\
    PLIST_ENTRY _EX_Flink;\
    PLIST_ENTRY _EX_Entry;\
    _EX_Entry = (Entry);\
    _EX_Flink = _EX_Entry->Flink;\
    _EX_Blink = _EX_Entry->Blink;\
    _EX_Blink->Flink = _EX_Flink;\
    _EX_Flink->Blink = _EX_Blink;\
    _EX_Entry->Flink = _EX_Entry->Blink = _EX_Entry;\
    }


//
// Traverse a singlely linked NULL terminated list.
// Pass in the address of the list head, the type of the containing record,
// the offset to the link entry in the conatining record, and code for
// the loop body.  pE is the iterator and is of type specified.
// Within the loop body the macros InsertSingleListEntry() and
// RemoveSingleListEntry() can be used to do the obvious things.
//

#define ForEachSingleListEntry( _HEAD_, _TYPE_, _OFFSET_, _STMT_ ) \
{                                                             \
    PSINGLE_LIST_ENTRY __Entry, __NextEntry, __PrevEntry;     \
    _TYPE_ *pE;                                               \
                                                              \
    __Entry = (_HEAD_);                                       \
    __NextEntry = (_HEAD_)->Next;                             \
                                                              \
    while (__PrevEntry = __Entry, __Entry = __NextEntry, __Entry != NULL) { \
                                                              \
        __NextEntry = __Entry->Next;                          \
        pE = CONTAINING_RECORD(__Entry, _TYPE_, _OFFSET_);    \
                                                              \
        { _STMT_ }                                            \
                                                              \
    }                                                         \
                                                              \
}
//
// The following three macros are only valid within the loop body above.
// Insert an entry before the current entry with pointer pE.
//
#define InsertSingleListEntry( _Item_, _xOFFSET_ ) \
    (_Item_)->_xOFFSET_.Next = __Entry;            \
    __PrevEntry->Next = (PSINGLE_LIST_ENTRY) &((_Item_)->_xOFFSET_);

//
// Note that after you remove an entry the value for __Entry is set back to
// the __PrevEntry so when the loop continues __PrevEntry doesn't change
// since current entry had been removed.
//
#define RemoveSingleListEntry( _UNUSED_ )  \
    __PrevEntry->Next = __NextEntry;       \
    __Entry->Next = NULL;                  \
    __Entry = __PrevEntry;

//
// Return ptr to the previous node.  Only valid inside above FOR loop.
// Useful when deleting the current entry.
//
#define PreviousSingleListEntry( _TYPE_, _OFFSET_)  \
    CONTAINING_RECORD(__PrevEntry, _TYPE_, _OFFSET_)


//
// General-purpose queue package.  Taken from cluster\clusrtl.c
// *** WARNING ***  To make the macros work properly for both lists and queues
// the first five items in FRS_LIST and FRS_QUEUE MUST match.
//
typedef struct _FRS_QUEUE FRS_QUEUE, *PFRS_QUEUE;
struct _FRS_QUEUE {
    LIST_ENTRY          ListHead;
    CRITICAL_SECTION    Lock;
    DWORD               Count;
    PFRS_QUEUE          Control;
    DWORD               ControlCount;

    HANDLE              Event;
    HANDLE              RunDown;
    ULONG               InitTime;
    LIST_ENTRY          Full;
    LIST_ENTRY          Empty;
    LIST_ENTRY          Idled;
    BOOL                IsRunDown;
    BOOL                IsIdled;
};

VOID
FrsInitializeQueue(
    IN PFRS_QUEUE Queue,
    IN PFRS_QUEUE Control
    );

VOID
FrsRtlDeleteQueue(
    IN PFRS_QUEUE Queue
    );

PLIST_ENTRY
FrsRtlRemoveHeadQueue(
    IN PFRS_QUEUE Queue
    );

VOID
FrsRtlUnIdledQueue(
    IN PFRS_QUEUE   IdledQueue
    );

VOID
FrsRtlUnIdledQueueLock(
    IN PFRS_QUEUE   IdledQueue
    );

VOID
FrsRtlIdleQueue(
    IN PFRS_QUEUE   Queue
    );

VOID
FrsRtlIdleQueueLock(
    IN PFRS_QUEUE Queue
    );

PLIST_ENTRY
FrsRtlRemoveHeadQueueTimeoutIdled(
    IN PFRS_QUEUE   Queue,
    IN DWORD        dwMilliseconds,
    OUT PFRS_QUEUE  *IdledQueue
    );

PLIST_ENTRY
FrsRtlRemoveHeadQueueTimeout(
    IN PFRS_QUEUE Queue,
    IN DWORD dwMilliseconds
    );

VOID
FrsRtlRemoveEntryQueue(
    IN PFRS_QUEUE Queue,
    IN PLIST_ENTRY Entry
    );

DWORD
FrsRtlWaitForQueueFull(
    IN PFRS_QUEUE Queue,
    IN DWORD dwMilliseconds
    );

DWORD
FrsRtlInsertTailQueue(
    IN PFRS_QUEUE Queue,
    IN PLIST_ENTRY Item
    );

DWORD
FrsRtlInsertHeadQueue(
    IN PFRS_QUEUE Queue,
    IN PLIST_ENTRY Item
    );

VOID
FrsRtlRunDownQueue(
    IN PFRS_QUEUE Queue,
    OUT PLIST_ENTRY ListHead
    );

#define FrsRtlAcquireQueueLock(_pQueue_) \
            EnterCriticalSection(&(((_pQueue_)->Control)->Lock))

#define FrsRtlReleaseQueueLock(_pQueue_) \
            LeaveCriticalSection(&(((_pQueue_)->Control)->Lock))

#define FrsRtlCountQueue(_pQueue_) \
            (((_pQueue_)->Control)->ControlCount)

#define FrsRtlCountSubQueue(_pQueue_) \
            ((_pQueue_)->Count)

#define FrsRtlNoIdledQueues(_pQueue_) \
            (IsListEmpty(&(((_pQueue_)->Control)->Idled)))


//
// The Lock suffix on the routines below means the user already has the
// queue lock.
//
VOID
FrsRtlRemoveEntryQueueLock(
    IN PFRS_QUEUE Queue,
    IN PLIST_ENTRY Entry
    );

DWORD
FrsRtlInsertTailQueueLock(
    IN PFRS_QUEUE Queue,
    IN PLIST_ENTRY Item
    );

DWORD
FrsRtlInsertHeadQueueLock(
    IN PFRS_QUEUE Queue,
    IN PLIST_ENTRY Item
    );

//
// COMMAND SERVER
// A command server is a dynamic pool of threads and a controlled queue
//      The default queue is set up as a controlled queue. Other
//      controlled queues can be added in a server specific manner.
// A command server exports an initialize, abort, and none or more
// submit routines. The parameters and names of these functions is
// server specific. The consumers of a server's interface are intimate
// with the server.
//
typedef struct _COMMAND_SERVER  COMMAND_SERVER, *PCOMMAND_SERVER;
struct _COMMAND_SERVER {
    DWORD           MaxThreads;     // Max # of threads
    DWORD           FrsThreads;     // current # of frs threads
    DWORD           Waiters;        // current # of frs threads waiting
    PWCHAR          Name;           // Thread's name
    HANDLE          Idle;           // No active threads; no queue entries
    DWORD           (*Main)(PVOID); // Thread's entry point
    FRS_QUEUE       Control;        // controlling queue
    FRS_QUEUE       Queue;          // queue
};

//
// Interlocked list.
// *** WARNING ***  To make the macros work properly for both lists and queues
// the first five items in FRS_LIST and FRS_QUEUE MUST match.
//
typedef struct _FRS_LIST FRS_LIST, *PFRS_LIST;
struct _FRS_LIST {
    LIST_ENTRY ListHead;
    CRITICAL_SECTION Lock;
    DWORD Count;
    PFRS_LIST Control;
    DWORD ControlCount;
};


DWORD
FrsRtlInitializeList(
    PFRS_LIST List
    );

VOID
FrsRtlDeleteList(
    PFRS_LIST List
    );

PLIST_ENTRY
FrsRtlRemoveHeadList(
    IN PFRS_LIST List
    );

VOID
FrsRtlInsertHeadList(
    IN PFRS_LIST List,
    IN PLIST_ENTRY Entry
    );

PLIST_ENTRY
FrsRtlRemoveTailList(
    IN PFRS_LIST List
    );

VOID
FrsRtlInsertTailList(
    IN PFRS_LIST List,
    IN PLIST_ENTRY Entry
    );

VOID
FrsRtlRemoveEntryList(
    IN PFRS_LIST List,
    IN PLIST_ENTRY Entry
    );


#define FrsRtlAcquireListLock(_pList_) EnterCriticalSection(&(((_pList_)->Control)->Lock))

#define FrsRtlReleaseListLock(_pList_) LeaveCriticalSection(&(((_pList_)->Control)->Lock))

#define FrsRtlCountList(_pList_) (((_pList_)->Control)->ControlCount)


VOID
FrsRtlRemoveEntryListLock(
    IN PFRS_LIST List,
    IN PLIST_ENTRY Entry
    );

VOID
FrsRtlInsertTailListLock(
    IN PFRS_LIST List,
    IN PLIST_ENTRY Entry
    );

VOID
FrsRtlInsertHeadListLock(
    IN PFRS_LIST List,
    IN PLIST_ENTRY Entry
    );


//VOID
//FrsRtlInsertBeforeEntryListLock(
//    IN PFRS_LIST List,
//    IN PLIST_ENTRY BeforeEntry
//    IN PLIST_ENTRY NewEntry
//    )
//
//    Inserts newEntry before the BeforeEntry on the interlocked list (List).
//    This is used to keep the list elements in ascending order by KeyValue.
//
//    Assumes caller already has the list lock.
//

#define  FrsRtlInsertBeforeEntryListLock( _List, _BeforeEntry, _NewEntry ) \
    InsertTailList((_BeforeEntry), (_NewEntry)); \
    (_List)->Count += 1; \
    ((_List)->Control)->ControlCount += 1; \


//
// Walk thru an interlocked queue or list (_QUEUE_) with elements of type
// _TYPE_ and execute {_STMT_} for each one.  The list entry in _TYPE_ is
// at _OFFSET_.  Use pE in the statement body as a pointer to the entry.
// The entry may be removed from within the loop since we capture the
// link to the next entry before executing the loop body.  You may also use
// 'continue' within the loop body because the assignment of nextentry to entry
// is in a comma expression inside the while test.
//

#define ForEachListEntry( _QUEUE_, _TYPE_, _OFFSET_, _STMT_ ) \
{                                                             \
    PLIST_ENTRY __Entry, __NextEntry;                         \
    BOOL __Hold__=FALSE;                                      \
    _TYPE_ *pE;                                               \
                                                              \
    FrsRtlAcquireQueueLock(_QUEUE_);                          \
    __NextEntry = GetListHead(&((_QUEUE_)->ListHead));        \
                                                              \
    while (__Entry = __NextEntry, __Entry != &((_QUEUE_)->ListHead)) { \
                                                              \
        __NextEntry = GetListNext(__Entry);                   \
        pE = CONTAINING_RECORD(__Entry, _TYPE_, _OFFSET_);    \
                                                              \
        { _STMT_ }                                            \
                                                              \
    }                                                         \
                                                              \
    if (!__Hold__) FrsRtlReleaseQueueLock(_QUEUE_);           \
                                                              \
}

#define AquireListLock( _QUEUE_ )  FrsRtlAcquireListLock(_QUEUE_)
#define ReleaseListLock( _QUEUE_ ) FrsRtlReleaseListLock(_QUEUE_)

#define BreakAndHoldLock __Hold__ = TRUE; break


//
// Just like the above except the caller already has the list lock.
//

#define ForEachListEntryLock( _QUEUE_, _TYPE_, _OFFSET_, _STMT_ ) \
{                                                             \
    PLIST_ENTRY __Entry, __NextEntry;                         \
    _TYPE_ *pE;                                               \
                                                              \
    __NextEntry = GetListHead(&((_QUEUE_)->ListHead));        \
                                                              \
    while (__Entry = __NextEntry, __Entry != &((_QUEUE_)->ListHead)) {  \
                                                              \
        __NextEntry = GetListNext(__Entry);                   \
        pE = CONTAINING_RECORD(__Entry, _TYPE_, _OFFSET_);    \
                                                              \
        { _STMT_ }                                            \
                                                              \
    }                                                         \
                                                              \
}


//
// Just like the above except pass in the address of the list head
// instead of using QUEUE->ListHEad.
//

#define ForEachSimpleListEntry( _HEAD_, _TYPE_, _OFFSET_, _STMT_ ) \
{                                                             \
    PLIST_ENTRY __Entry, __NextEntry;                         \
    _TYPE_ *pE;                                               \
                                                              \
    __NextEntry = GetListHead(_HEAD_);                        \
                                                              \
    while (__Entry = __NextEntry, __Entry != (_HEAD_)) {      \
                                                              \
        __NextEntry = GetListNext(__Entry);                   \
        pE = CONTAINING_RECORD(__Entry, _TYPE_, _OFFSET_);    \
                                                              \
        { _STMT_ }                                            \
                                                              \
    }                                                         \
                                                              \
}


//VOID
//FrsRtlInsertQueueOrdered(
//    IN PFRS_QUEUE List,
//    IN PLIST_ENTRY NewEntry,
//    IN <Entry-Data-Type>,
//    IN <LIST_ENTRY-offset-name>,
//    IN <Orderkey-Offset-name>,
//    IN EventHandle or NULL
//    )
//
//    Inserts NewEntry on an ordered queue of <Entry-Data-Type> elements.
//    The offset to the LIST_ENTRY in each element is <LIST_ENTRY-offset-name>
//    The offset to the Ordering key (.eg. a ULONG) is <Orderkey-Offset-name>
//    It acquires the List Lock.
//    The list elements are kept in ascending order by KeyValue.
//    If a new element is placed at the head of the queue and the EventHandle
//    is non-NULL, the event is signalled.
//
//
#define FrsRtlInsertQueueOrdered(                                           \
    _QUEUE_, _NEWENTRY_, _TYPE_, _OFFSET_, _BY_, _EVENT_, _STATUS_)         \
{                                                                           \
    BOOL __InsertDone = FALSE;                                              \
    BOOL __FirstOnQueue = TRUE;                                             \
    _STATUS_ = ERROR_SUCCESS;                                               \
                                                                            \
    FrsRtlAcquireQueueLock(_QUEUE_);                                        \
                                                                            \
    ForEachListEntryLock(_QUEUE_, _TYPE_, _OFFSET_,                         \
                                                                            \
        /* pE is loop iterator of type _TYPE_                          */   \
                                                                            \
        if ((_NEWENTRY_)->_BY_ < pE->_BY_) {                                \
            FrsRtlInsertBeforeEntryListLock( _QUEUE_,                       \
                                             &pE->_OFFSET_,                 \
                                             &((_NEWENTRY_)->_OFFSET_));    \
            __InsertDone = TRUE;                                            \
            break;                                                          \
        }                                                                   \
                                                                            \
        __FirstOnQueue = FALSE;                                             \
    );                                                                      \
                                                                            \
    /* Handle new head or new tail case.  If the queue was previously  */   \
    /* the insert will set the event.                                  */   \
                                                                            \
    if (!__InsertDone) {                                                    \
        if (__FirstOnQueue) {                                               \
            _STATUS_ = FrsRtlInsertHeadQueueLock(_QUEUE_, &((_NEWENTRY_)->_OFFSET_));  \
        } else {                                                            \
            _STATUS_ = FrsRtlInsertTailQueueLock(_QUEUE_, &((_NEWENTRY_)->_OFFSET_));  \
        }                                                                   \
    }                                                                       \
                                                                            \
    /* If this command became the new first one on the queue and the   */   \
    /* queue wasn't previously empty we have to set the event here to  */   \
    /* get the thread to readjust its wait time.                       */   \
                                                                            \
    if (__FirstOnQueue &&                                                   \
        (FrsRtlCountQueue(_QUEUE_) != 1)) {                                 \
        if (HANDLE_IS_VALID(_EVENT_)) {                                     \
            SetEvent(_EVENT_);                                              \
        }                                                                   \
    }                                                                       \
                                                                            \
    FrsRtlReleaseQueueLock(_QUEUE_);                                        \
                                                                            \
}



//VOID
//FrsRtlInsertListOrdered(
//    IN PFRS_LIST List,
//    IN PLIST_ENTRY NewEntry,
//    IN <Entry-Data-Type>,
//    IN <LIST_ENTRY-offset-name>,
//    IN <Orderkey-Offset-name>,
//    IN EventHandle or NULL
//    )
//
//    Inserts NewEntry on an ordered list of <Entry-Data-Type> elements.
//    The offset to the LIST_ENTRY in each element is <LIST_ENTRY-offset-name>
//    The offset to the Ordering key (.eg. a ULONG) is <Orderkey-Offset-name>
//    It acquires the List Lock.
//    The list elements are kept in ascending order by KeyValue.
//    If a new element is placed at the head of the queue and the EventHandle
//    is non-NULL, the event is signalled.
//
//
#define FrsRtlInsertListOrdered(                                            \
    _FRSLIST_, _NEWENTRY_, _TYPE_, _OFFSET_, _BY_, _EVENT_)                 \
{                                                                           \
    BOOL __InsertDone = FALSE;                                              \
    BOOL __FirstOnList = TRUE;                                              \
                                                                            \
    FrsRtlAcquireListLock(_FRSLIST_);                                       \
                                                                            \
    ForEachListEntryLock(_FRSLIST_, _TYPE_, _OFFSET_,                       \
                                                                            \
        /* pE is loop iterator of type _TYPE_                          */   \
                                                                            \
        if ((_NEWENTRY_)->_BY_ < pE->_BY_) {                                \
            FrsRtlInsertBeforeEntryListLock( _FRSLIST_,                     \
                                             &pE->_OFFSET_,                 \
                                             &((_NEWENTRY_)->_OFFSET_));    \
            __InsertDone = TRUE;                                            \
            break;                                                          \
        }                                                                   \
                                                                            \
        __FirstOnList = FALSE;                                              \
    );                                                                      \
                                                                            \
    /* Handle new head or new tail case. */                                 \
                                                                            \
    if (!__InsertDone) {                                                    \
        if (__FirstOnList) {                                                \
            FrsRtlInsertHeadListLock(_FRSLIST_, &((_NEWENTRY_)->_OFFSET_)); \
        } else {                                                            \
            FrsRtlInsertTailListLock(_FRSLIST_, &((_NEWENTRY_)->_OFFSET_)); \
        }                                                                   \
    }                                                                       \
                                                                            \
    /* If this command became the new first one on the list              */ \
    /* we set the event here to get the thread to readjust its wait time.*/ \
                                                                            \
    if (__FirstOnList) {                                                    \
        if (HANDLE_IS_VALID(_EVENT_)) {                                     \
            SetEvent(_EVENT_);                                              \
        }                                                                   \
    }                                                                       \
                                                                            \
    FrsRtlReleaseListLock(_FRSLIST_);                                       \
                                                                            \
}



//
// Request counts are used as a simple means for tracking the number of
// command requests that are pending so the requestor can wait until
// all the commands have been processed.
//
typedef struct _FRS_REQUEST_COUNT FRS_REQUEST_COUNT, *PFRS_REQUEST_COUNT;
struct _FRS_REQUEST_COUNT {
    CRITICAL_SECTION    Lock;
    LONG                Count;     // Number of requests active
    HANDLE              Event;     // Event set when count goes to zero.
    ULONG               Status;    // Optional status return
};


#define FrsIncrementRequestCount(_RC_)     \
    EnterCriticalSection(&(_RC_)->Lock);   \
    (_RC_)->Count += 1;                    \
    if ((_RC_)->Count == 1) {              \
        ResetEvent((_RC_)->Event);         \
    }                                      \
    LeaveCriticalSection(&(_RC_)->Lock);


#define FrsDecrementRequestCount(_RC_, _Status_)   \
    EnterCriticalSection(&(_RC_)->Lock);   \
    (_RC_)->Status |= _Status_;            \
    (_RC_)->Count -= 1;                    \
    FRS_ASSERT((_RC_)->Count >= 0);        \
    if ((_RC_)->Count == 0) {              \
        SetEvent((_RC_)->Event);           \
    }                                      \
    LeaveCriticalSection(&(_RC_)->Lock);


ULONG
FrsWaitOnRequestCount(
    IN PFRS_REQUEST_COUNT RequestCount,
    IN ULONG Timeout
    );


struct _COMMAND_PACKET;
VOID
FrsCompleteRequestCount(
    IN struct _COMMAND_PACKET *CmdPkt,
    IN PFRS_REQUEST_COUNT RequestCount
    );

VOID
FrsCompleteRequestCountKeepPkt(
    IN struct _COMMAND_PACKET *CmdPkt,
    IN PFRS_REQUEST_COUNT RequestCount
    );

VOID
FrsCompleteKeepPkt(
    IN struct _COMMAND_PACKET *CmdPkt,
    IN PVOID           CompletionArg
    );

VOID
FrsInitializeRequestCount(
    IN PFRS_REQUEST_COUNT RequestCount
    );

VOID
FrsDeleteRequestCount(
    IN PFRS_REQUEST_COUNT RequestCount
    );



#define FrsInterlockedIncrement64(_Dest_, _Data_, _Lock_) \
    EnterCriticalSection(_Lock_);                         \
    _Data_ += (ULONGLONG) 1;                              \
    _Dest_ = (_Data_);                                    \
    LeaveCriticalSection(_Lock_);


//
//  ADVANCE_VALUE_INTERLOCKED(
//      IN PULONG _dest,
//      IN ULONG  _newval
//  )
//  Advance the destination to the value given in newval atomically using
//  interlocked exchange.  _dest is never moved to a smaller value so this
//  is a no-op if _newval is < _dest.
//
//  *NOTE* Other operations on _dest MUST be done with interlocked ops like
//  InterlockedIncrement to ensure that an incremented value is not lost if
//  it occurs simultaneously on another processor.
//
#define ADVANCE_VALUE_INTERLOCKED(_dest, _newval)  {                           \
    ULONG CurVal, SaveCurVal, Result, *pDest = (_dest);                        \
    CurVal = SaveCurVal = *pDest;                                              \
    while ((_newval) > CurVal) {                                               \
        Result = (ULONG)InterlockedCompareExchange((PLONG)pDest, (_newval), CurVal); \
        if (Result == CurVal) {                                                \
            break;                                                             \
        }                                                                      \
        CurVal = Result;                                                       \
    }                                                                          \
    FRS_ASSERT(*pDest >= SaveCurVal);                                          \
}

//
//
// Avoiding a torn quadword result (without a crit sect) when 1 thread is
// writing a quadord and another is reading the quadword, or,
// 2 threads are writing the same quadword.
//
// To do this in alpha we need an assembler routine to use load_locked / store_cond.
// To do this in x86 (per DaveC):
#if 0
    if (USER_SHARED_DATA->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] == FALSE) {
        // code to use a crit section.
    } else {
        // code to use inline assembly with cmpxchg8b.
    }
#endif
// KUSER_SHARED_DATA is defined in sdk\inc\ntxapi.h
// USER_SHARED_DATA is an arch specific typecast pointer to KUSER_SHARED_DATA.
// User shared data has a processor feature list with a cell for
// PF_COMPARE_EXCHANGE_DOUBLE that tells if the processor supports
// the cmpxchg8b instruction for x86.  The 486 doesn't have it.
//
#define ReadQuadLock(_qw, _Lock)  \
    (EnterCriticalSection((_Lock)), *(_qw))

#define WriteQuadUnlock(_qw, _newval, _Lock)  \
    *(_qw) = (_newval);                       \
    LeaveCriticalSection((_Lock))

#define AcquireQuadLock(_Lock)  EnterCriticalSection((_Lock))
#define ReleaseQuadLock(_Lock)  LeaveCriticalSection((_Lock))



//
//  SET_FLAG_INTERLOCKED(
//      IN PULONG _dest,
//      IN ULONG  _flags
//  )
//
//  *NOTE* Other operations on _dest MUST be done with interlocked ops like
//  InterlockedIncrement to ensure that an incremented value is not lost if
//  it occurs simultaneously on another processor.
//
#define SET_FLAG_INTERLOCKED(_dest, _flags)  {                                 \
    ULONG CurVal, NewVal, Result, *pDest = (_dest);                            \
    CurVal = *pDest;                                                           \
    NewVal = (_flags) | CurVal;                                                \
    while ((NewVal) != CurVal) {                                               \
        Result = (ULONG)InterlockedCompareExchange((PLONG)pDest, NewVal, CurVal);    \
        if (Result == CurVal) {                                                \
            break;                                                             \
        }                                                                      \
        CurVal = Result;                                                       \
        NewVal = (_flags) | CurVal;                                            \
    }                                                                          \
}


//
//  CLEAR_FLAG_INTERLOCKED(
//      IN PULONG _dest,
//      IN ULONG  _flags
//  )
//
//  *NOTE* Other operations on _dest MUST be done with interlocked ops like
//  InterlockedIncrement to ensure that an incremented value is not lost if
//  it occurs simultaneously on another processor.
//
#define CLEAR_FLAG_INTERLOCKED(_dest, _flags)  {                               \
    ULONG CurVal, NewVal, Result, *pDest = (_dest);                            \
    CurVal = *pDest;                                                           \
    NewVal = CurVal & ~(_flags);                                               \
    while ((NewVal) != CurVal) {                                               \
        Result = (ULONG)InterlockedCompareExchange((PLONG)pDest, NewVal, CurVal);    \
        if (Result == CurVal) {                                                \
            break;                                                             \
        }                                                                      \
        CurVal = Result;                                                       \
        NewVal = CurVal & ~(_flags);                                           \
    }                                                                          \
}



#define FlagOn(Flags,SingleFlag)  ((Flags) & (SingleFlag))

#define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)(((Flags) & (SingleFlag)) != 0))

#define SetFlag(_F,_SF) { \
    (_F) |= (_SF);        \
}

#define ClearFlag(_F,_SF) { \
    (_F) &= ~(_SF);         \
}

#define ValueIsMultOf2(_x_)  (((ULONG_PTR)(_x_) & 0x00000001) == 0)
#define ValueIsMultOf4(_x_)  (((ULONG_PTR)(_x_) & 0x00000003) == 0)
#define ValueIsMultOf8(_x_)  (((ULONG_PTR)(_x_) & 0x00000007) == 0)
#define ValueIsMultOf16(_x_) (((ULONG_PTR)(_x_) & 0x0000000F) == 0)


#define ARRAY_SZ(_ar)  (sizeof(_ar)/sizeof((_ar)[0]))
#define ARRAY_SZ2(_ar, _type)  (sizeof(_ar)/sizeof(_type))


//
// This macros below take a pointer (or ulong) and return the value rounded
// up to the next aligned boundary.
//
#define WordAlign(Ptr)     ((PVOID)((((ULONG_PTR)(Ptr)) + 1)  & ~1))
#define LongAlign(Ptr)     ((PVOID)((((ULONG_PTR)(Ptr)) + 3)  & ~3))
#define QuadAlign(Ptr)     ((PVOID)((((ULONG_PTR)(Ptr)) + 7)  & ~7))
#define DblQuadAlign(Ptr)  ((PVOID)((((ULONG_PTR)(Ptr)) + 15) & ~15))
#define QuadQuadAlign(Ptr) ((PVOID)((((ULONG_PTR)(Ptr)) + 31) & ~31))

#define QuadQuadAlignSize(Size) ((((ULONG)(Size)) + 31) & ~31)

//
// Check for a zero FILETIME.
//
#define FILETIME_IS_ZERO(_F_) \
    ((_F_.dwLowDateTime == 0) && (_F_.dwHighDateTime == 0))


//
// Convert a quad to two ULONGs for printing with format: %08x %08x
//
#define PRINTQUAD(__ARG__) (ULONG)((__ARG__)>>32) ,(ULONG)(__ARG__)

//
// Convert to printable cxtion path with format: %ws\%ws\%ws -> %ws\%ws
//
#define FORMAT_CXTION_PATH2  "%ws\\%ws\\%ws %ws %ws %ws"
#define FORMAT_CXTION_PATH2W  L"%ws\\%ws\\%ws %ws %ws %ws"
#define PRINT_CXTION_PATH2(_REPLICA, _CXTION)                       \
    (_REPLICA)->ReplicaName->Name,                                  \
    (_REPLICA)->MemberName->Name,                                   \
    (((_CXTION) != NULL) ? (_CXTION)->Name->Name : L"null"),        \
    (((_CXTION) != NULL) ? (((_CXTION)->Inbound) ? L"<-" : L"->") : \
                           L"?"),                                   \
    (((_CXTION) != NULL) ? (_CXTION)->PartSrvName : L"null"),       \
    (((_CXTION) != NULL) ? (((_CXTION)->JrnlCxtion) ? L"JrnlCxt" : L"RemoteCxt") : L"null")

#define PRINT_CXTION_PATH(_REPLICA, _CXTION)                    \
    (_REPLICA)->ReplicaName->Name,                              \
    (_REPLICA)->MemberName->Name,                               \
    (((_CXTION) != NULL) ? (_CXTION)->Name->Name : L"null"),    \
    (((_CXTION) != NULL) ? (_CXTION)->Partner->Name : L"null"), \
    (((_CXTION) != NULL) ? (_CXTION)->PartSrvName : L"null")

//
// Lower case
//
#define FRS_WCSLWR(_s_) \
{ \
    if (_s_) { \
        _wcslwr(_s_); \
    } \
}

//
// Lock to protect the child lists in the Filter Table.  (must be pwr of 2)
// Instead of paying the overhead of having one per node we just use an array
// to help reduce contention.  We use the ReplicaNumber masked by the lock
// table size as the index.
//
// Acquire the lock on the ReplicaSet Filter table Child List before
// inserting or removing a child from the list.
//
#define NUMBER_FILTER_TABLE_CHILD_LOCKS 8
extern CRITICAL_SECTION JrnlFilterTableChildLock[NUMBER_FILTER_TABLE_CHILD_LOCKS];

#define FILTER_TABLE_CHILD_INDEX(_x_) \
((ULONG)((_x_)->ReplicaNumber) & (NUMBER_FILTER_TABLE_CHILD_LOCKS - 1))

#define JrnlAcquireChildLock(_replica_) EnterCriticalSection( \
    &JrnlFilterTableChildLock[FILTER_TABLE_CHILD_INDEX(_replica_)] )

#define JrnlReleaseChildLock(_replica_) LeaveCriticalSection( \
    &JrnlFilterTableChildLock[FILTER_TABLE_CHILD_INDEX(_replica_)] )

//
// Renaming a subtree from one replica set to another requires the child locks
// for both replica sets.  Always get them in the same order (low to high)
// to avoid deadlock.  Also check if the both use the same lock.
// Note: The caller must use JrnlReleaseChildLockPair() so the check for
// using the same lock can be repeated.  Release in reverse order to avoid
// an extra context switch if another thread was waiting behind the first lock.
//
#define JrnlAcquireChildLockPair(_replica1_, _replica2_)        \
{                                                               \
    ULONG Lx1, Lx2, Lxt;                                        \
    Lx1 = FILTER_TABLE_CHILD_INDEX(_replica1_);                 \
    Lx2 = FILTER_TABLE_CHILD_INDEX(_replica2_);                 \
    if (Lx1 > Lx2) {                                            \
        Lxt = Lx1; Lx1 = Lx2; Lx2 = Lxt;                        \
    }                                                           \
    EnterCriticalSection(&JrnlFilterTableChildLock[Lx1]);       \
    if (Lx1 != Lx2) {                                           \
        EnterCriticalSection(&JrnlFilterTableChildLock[Lx2]);   \
    }                                                           \
}


#define JrnlReleaseChildLockPair(_replica1_, _replica2_)        \
{                                                               \
    ULONG Lx1, Lx2, Lxt;                                        \
    Lx1 = FILTER_TABLE_CHILD_INDEX(_replica1_);                 \
    Lx2 = FILTER_TABLE_CHILD_INDEX(_replica2_);                 \
    if (Lx1 < Lx2) {                                            \
        Lxt = Lx1; Lx1 = Lx2; Lx2 = Lxt;                        \
    }                                                           \
    LeaveCriticalSection(&JrnlFilterTableChildLock[Lx1]);       \
    if (Lx1 != Lx2) {                                           \
        LeaveCriticalSection(&JrnlFilterTableChildLock[Lx2]);   \
    }                                                           \
}

#ifdef __cplusplus
  }
#endif



ULONG
FrsRunProcess(
    IN PWCHAR   CommandLine,
    IN HANDLE   StandardIn,
    IN HANDLE   StandardOut,
    IN HANDLE   StandardError
    );


VOID
FrsFlagsToStr(
    IN DWORD            Flags,
    IN PFLAG_NAME_TABLE NameTable,
    IN ULONG            Length,
    OUT PSTR            Buffer
    );


//
//######################### COMPRESSION OF STAGING FILE STARTS ###############
//

//
//  The compressed chunk header is the structure that starts every
//  new chunk in the compressed data stream.  In our definition here
//  we union it with a ushort to make setting and retrieving the chunk
//  header easier.  The header stores the size of the compressed chunk,
//  its signature, and if the data stored in the chunk is compressed or
//  not.
//
//  Compressed Chunk Size:
//
//      The actual size of a compressed chunk ranges from 4 bytes (2 byte
//      header, 1 flag byte, and 1 literal byte) to 4098 bytes (2 byte
//      header, and 4096 bytes of uncompressed data).  The size is encoded
//      in a 12 bit field biased by 3.  A value of 1 corresponds to a chunk
//      size of 4, 2 => 5, ..., 4095 => 4098.  A value of zero is special
//      because it denotes the ending chunk header.
//
//  Chunk Signature:
//
//      The only valid signature value is 3.  This denotes a 4KB uncompressed
//      chunk using with the 4/12 to 12/4 sliding offset/length encoding.
//
//  Is Chunk Compressed:
//
//      If the data in the chunk is compressed this field is 1 otherwise
//      the data is uncompressed and this field is 0.
//
//  The ending chunk header in a compressed buffer contains the a value of
//  zero (space permitting).
//

typedef union _FRS_COMPRESSED_CHUNK_HEADER {

    struct {

        USHORT CompressedChunkSizeMinus3 : 12;
        USHORT ChunkSignature            :  3;
        USHORT IsChunkCompressed         :  1;

    } Chunk;

    USHORT Short;

} FRS_COMPRESSED_CHUNK_HEADER, *PFRS_COMPRESSED_CHUNK_HEADER;

typedef struct _FRS_DECOMPRESS_CONTEXT {
    DWORD   BytesProcessed;
} FRS_DECOMPRESS_CONTEXT, *PFRS_DECOMPRESS_CONTEXT;

#define FRS_MAX_CHUNKS_TO_DECOMPRESS 16
#define FRS_UNCOMPRESSED_CHUNK_SIZE  4096

//
//######################### COMPRESSION OF STAGING FILE ENDS ###############
//


//
// This context is used to send data to the callback functions for the RAW
// encrypt APIs.
//
typedef struct _FRS_ENCRYPT_DATA_CONTEXT {

    PWCHAR         StagePath;
    HANDLE         StageHandle;
    LARGE_INTEGER  RawEncryptedBytes;

} FRS_ENCRYPT_DATA_CONTEXT, *PFRS_ENCRYPT_DATA_CONTEXT;