//----------------------------------------------------------------------------
// Pismo Technic Inc. Copyright 2003-2024 Joe Lowe
//
// Permission is granted to any person obtaining a copy of this Software,
// to deal in the Software without restriction, including the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and sell copies of
// the Software.
//
// The above copyright and permission notice must be left intact in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS WITHOUT WARRANTY.
//----------------------------------------------------------------------------
// file name:  fsrformatter.hxx
// created:    2020.09.04
//----------------------------------------------------------------------------
#ifndef FSRFORMATTER_HXX
#define FSRFORMATTER_HXX
#include "fsrapi.hxx"
#include "ptiobuf.h"
#ifdef __cplusplus_cli
#pragma managed(push,off)
#endif
extern "C" {
PT_C_ASSERT_STRUCT_PACKING(FSRFORMATTER_HXX);

struct/*interface*/ FsrFile;

struct FsrOpenAttribs
{
   PT_INT8 accessLevel;
   PT_UINT8 controlFlags;
   PT_UINT32 touch;
   PT_UINT64 sequence;
   FsrAttribs attribs;
};

static const int fsrOpTypeOpen = 3;
static const int fsrOpTypeReplace = 4;
static const int fsrOpTypeMove = 5;
static const int fsrOpTypeMoveReplace = 6;
static const int fsrOpTypeDelete = 7;
static const int fsrOpTypeFlush = 9;
static const int fsrOpTypeList = 10;
static const int fsrOpTypeRead = 12;
static const int fsrOpTypeWrite = 13;
static const int fsrOpTypeSetSize = 14;
static const int fsrOpTypeCapacity = 15;
static const int fsrOpTypeFlushMedia = 16;
static const int fsrOpTypeControl = 17;
static const int fsrOpTypeMediaInfo = 18;
static const int fsrOpTypeAccess = 19;
static const int fsrOpTypeReadXattr = 20;
static const int fsrOpTypeWriteXattr = 21;
static const int fsrOpTypeReadTouchMap = 23;

struct FsrControlOpResult
{
   PT_SIZE_T outputSize;
};
struct FsrControlOp
{
   void (PT_CCALL*complete)( FsrControlOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrControlOpResult result;
      //
   PT_INT8 accessLevel;
   PT_UINT8 controlScope;
   PT_SZC_T interfaceId;
   int controlCode;
   const void* input;
   PT_SIZE_T inputSize;
   void* output;
   PT_SIZE_T maxOutputSize;
};

struct FsrMediaInfoOpResult
{
   PT_UUID mediaUuid;
   PT_UINT64 mediaId64;
   PT_UINT32 mediaId32;
   PT_UINT8 mediaFlags;
   PT_INT64 createTime;
   PT_SZC_T mediaLabel;
};
struct FsrMediaInfoOp
{
   void (PT_CCALL*complete)( FsrMediaInfoOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrMediaInfoOpResult result;
      //
};

struct FsrCapacityOpResult
{
   PT_UINT64 totalCapacity;
   PT_UINT64 availableCapacity;
};
struct FsrCapacityOp
{
   void (PT_CCALL*complete)( FsrCapacityOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrCapacityOpResult result;
      //
};

struct FsrFlushMediaOpResult
{
   int msecFlushDelay;
};
struct FsrFlushMediaOp
{
   void (PT_CCALL*complete)( FsrFlushMediaOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrFlushMediaOpResult result;
      //
};

struct FsrListOpResult
{
   PT_BOOL noMore;
};
struct FsrListOp
{
   void (PT_CCALL*complete)( FsrListOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrListOpResult result;
      //
PT_BOOL /*ok*/ (PT_CCALL* add)( FsrListOp* op, const FsrAttribs* attribs, PT_SZC_T name);
};

struct FsrFlushOpResult
{
   FsrOpenAttribs openAttribs;
};
struct FsrFlushOp
{
   void (PT_CCALL*complete)( FsrFlushOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrFlushOpResult result;
      //
   PT_UINT8 flushFlags;
   PT_UINT8 fileFlags;
   PT_UINT8 color;
   PT_INT64 createTime;
   PT_INT64 accessTime;
   PT_INT64 writeTime;
   PT_INT64 changeTime;
   const void* linkData;
   PT_SIZE_T linkDataSize;
};

struct FsrOpenOpResult
{
   FsrFile* existedFile;
   FsrOpenAttribs openAttribs;
   PT_INT64 parentFileId;
   PT_SZC_T endName;
   PT_SIZE_T linkNamePartCount;
   const void* linkData;
   PT_SIZE_T linkDataSize;
};
struct FsrOpenOp
{
   void (PT_CCALL*complete)( FsrOpenOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrOpenOpResult result;
      //
   PT_SZC_T*const nameParts;
   PT_SIZE_T namePartCount;
   FsrFile* newCreatedFile;
   PT_INT8 createFileType;
   PT_UINT8 createFileFlags;
   PT_INT64 writeTime;
   PT_INT8 existingAccessLevel;
};

struct FsrReplaceOpResult
{
   FsrOpenAttribs openAttribs;
};
struct FsrReplaceOp
{
   void (PT_CCALL*complete)( FsrReplaceOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrReplaceOpResult result;
      //
   FsrFile* newCreatedFile;
   PT_INT64 targetParentFileId;
   PT_SZC_T targetEndName;
   PT_UINT8 createFileFlags;
   PT_INT64 writeTime;
};

struct FsrAccessOpResult
{
   FsrOpenAttribs openAttribs;
};
struct FsrAccessOp
{
   void (PT_CCALL*complete)( FsrAccessOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrAccessOpResult result;
      //
   PT_INT8 accessLevel;
};

struct FsrMoveOpResult
{
   FsrFile* targetExistedFile;
   FsrOpenAttribs openAttribs;
   PT_INT64 parentFileId;
   PT_SZC_T endName;
   PT_SIZE_T linkNamePartCount;
   const void* linkData;
   PT_SIZE_T linkDataSize;
};
struct FsrMoveOp
{
   void (PT_CCALL*complete)( FsrMoveOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrMoveOpResult result;
      //
   PT_INT64 sourceParentFileId;
   PT_SZC_T sourceEndName;
   PT_SZC_T*const targetNameParts;
   PT_SIZE_T targetNamePartCount;
   PT_BOOL deleteSource;
   PT_INT64 writeTime;
   PT_INT8 existingAccessLevel;
};

struct FsrMoveReplaceOp
{
   void (PT_CCALL*complete)( FsrMoveReplaceOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   PT_INT64 sourceParentFileId;
   PT_SZC_T sourceEndName;
   FsrFile* targetFile;
   PT_INT64 targetParentFileId;
   PT_SZC_T targetEndName;
   PT_BOOL deleteSource;
   PT_INT64 writeTime;
};

struct FsrDeleteOp
{
   void (PT_CCALL*complete)( FsrDeleteOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   PT_INT64 parentFileId;
   PT_SZC_T endName;
   PT_INT64 writeTime;
};

struct FsrReadOpResult
{
   PT_SIZE_T actualSize;
};
struct FsrReadOp
{
   void (PT_CCALL*complete)( FsrReadOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrReadOpResult result;
      //
   PT_UINT64 fileOffset;
   pt_iobufv_t* buf;
   PT_SIZE_T bufOff;
   PT_BOOL bufUnstable;
   PT_SIZE_T requestedSize;
};

struct FsrWriteOpResult
{
   PT_SIZE_T actualSize;
};
struct FsrWriteOp
{
   void (PT_CCALL*complete)( FsrWriteOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrWriteOpResult result;
      //
   PT_UINT64 fileOffset;
   pt_iobufv_t* buf;
   PT_SIZE_T bufOff;
   PT_BOOL bufUnstable;
   PT_SIZE_T requestedSize;
};

struct FsrSetSizeOp
{
   void (PT_CCALL*complete)( FsrSetSizeOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   PT_UINT64 fileSize;
};

struct FsrReadXattrOpResult
{
   PT_SIZE_T xattrSize;
   PT_SIZE_T actualSize;
};
struct FsrReadXattrOp
{
   void (PT_CCALL*complete)( FsrReadXattrOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrReadXattrOpResult result;
      //
   PT_SZC_T name;
   PT_UINT32 offset;
   pt_iobufv_t* buf;
   PT_SIZE_T bufOff;
   PT_BOOL bufUnstable;
   PT_SIZE_T requestedSize;
};

struct FsrWriteXattrOpResult
{
   PT_SIZE_T actualSize;
};
struct FsrWriteXattrOp
{
   void (PT_CCALL*complete)( FsrWriteXattrOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   FsrWriteXattrOpResult result;
      //
   PT_SZC_T name;
   PT_SIZE_T xattrSize;
   PT_SIZE_T offset;
   pt_iobufv_t* buf;
   PT_SIZE_T bufOff;
   PT_BOOL bufUnstable;
   PT_SIZE_T requestedSize;
};

struct FsrReadTouchMapOp
{
   void (PT_CCALL*complete)( FsrReadTouchMapOp*, int perr);
   void* context;
   pin_i* cancelPin;
      //
   pt_iobufv_t* buf;
};

struct/*interface*/ FsrList
{
   virtual void PT_CCALL DynaCast( void* v, PT_SZC_T typeId) = 0;
   virtual void PT_CCALL Release() = 0;
   virtual void PT_CCALL List( FsrListOp* op, void* mem) = 0;
};

struct/*interface*/ FsrFile
{
   virtual void PT_CCALL DynaCast( void* v, PT_SZC_T typeId) = 0;
   virtual void PT_CCALL Release() = 0;
   virtual FsrList* /*list*/ PT_CCALL ListFactory() = 0;
   virtual void PT_CCALL Replace( FsrReplaceOp* op, void* mem) = 0;
   virtual void PT_CCALL Move( FsrMoveOp* op, void* mem) = 0;
   virtual void PT_CCALL MoveReplace( FsrMoveReplaceOp* op, void* mem) = 0;
   virtual void PT_CCALL Delete( FsrDeleteOp* op, void* mem) = 0;
   virtual void PT_CCALL Access( FsrAccessOp* op, void* mem) = 0;
   virtual void PT_CCALL Flush( FsrFlushOp* op, void* mem) = 0;
   virtual void PT_CCALL Control( FsrControlOp* op, void* mem) = 0;
   virtual void PT_CCALL MediaInfo( FsrMediaInfoOp* op, void* mem) = 0;
   virtual void PT_CCALL Capacity( FsrCapacityOp* op, void* mem) = 0;
   virtual void PT_CCALL Read( FsrReadOp* op, void* mem) = 0;
   virtual void PT_CCALL Write( FsrWriteOp* op, void* mem) = 0;
   virtual void PT_CCALL SetSize( FsrSetSizeOp* op, void* mem) = 0;
   virtual void PT_CCALL ReadXattr( FsrReadXattrOp* op, void* mem) = 0;
   virtual void PT_CCALL WriteXattr( FsrWriteXattrOp* op, void* mem) = 0;
};

struct FsrFormatterWork
{
   void (PT_CCALL*handler)( FsrFormatterWork*);
   FsrFormatterWork* next;
};

struct/*interface*/ FsrFormatterOwner
{
   virtual void PT_CCALL Retain() = 0;
   virtual void PT_CCALL Release() = 0;
   virtual void PT_CCALL Cancel() = 0;
   virtual void PT_CCALL QueueWork( FsrFormatterWork* work) = 0;
};

struct FsrFormatterConfig
{
   FsrFormatterOwner* owner;
   PT_SIZE_T fileExtensionSize;
   PT_SIZE_T listExtensionSize;
   PT_SIZE_T touchMapSize;
   PT_SIZE_T maxIoSize;
   PT_SIZE_T dataAlign;
   PT_SIZE_T reserved2[2];
   PT_SIZE_T opContextSize[32];
};

struct/*interface*/ FsrFormatter
{
   virtual void PT_CCALL DynaCast( void* v, PT_SZC_T typeId) = 0;
   virtual void PT_CCALL Release() = 0;
   virtual void PT_CCALL Cancel() = 0;
   virtual void PT_CCALL Configure( FsrFormatterConfig* config) = 0;
   virtual int /*perr*/ PT_CCALL FileFactory( FsrFile** file) = 0;
   virtual void PT_CCALL Control( FsrControlOp* op, void* mem) = 0;
   virtual void PT_CCALL MediaInfo( FsrMediaInfoOp* op, void* mem) = 0;
   virtual void PT_CCALL Capacity( FsrCapacityOp* op, void* mem) = 0;
   virtual void PT_CCALL FlushMedia( FsrFlushMediaOp* op, void* mem) = 0;
   virtual void PT_CCALL ReadTouchMap( FsrReadTouchMapOp* op, void* mem) = 0;
   virtual void PT_CCALL Open( FsrOpenOp* op, void* mem) = 0;
};


#define FsrTouchMapFileName ".$touch_map_v1"
   // Larger touch maps reduce collisions so namespace caching
   // on client is more effective. Smaller touch maps reduce
   // latency and bandwidth overhead when clients read touch map.
PT_STATIC_CONST( PT_SIZE_T, FsrTouchMapMinSize,   0x1000);
PT_STATIC_CONST( PT_SIZE_T, FsrTouchMapDefaultSize,  0x10000);
PT_STATIC_CONST( PT_SIZE_T, FsrTouchMapMaxSize, 0x100000);
   // File id hash function based on Bob Jenkins lookup3.c,
   // for use in converting file id to touch map index.
#ifdef BITOPS_H
#define FSR_ROL_(v,c) bits_rol(v,c)
#else
#define FSR_ROL_(v,c) (((v)<<(c))|((v)>>(32U-(c))))
#endif
PT_INLINE unsigned FsrTouchMapIndex( PT_INT64 fileId, PT_SIZE_T mapMask)
{
   unsigned a = PT_SCAST( unsigned, fileId & 0xFFFFFFFFu);
   unsigned b = PT_SCAST( unsigned, PT_SCAST( PT_UINT64, fileId) >> 32);
   unsigned c = 0;
   c ^= b; c -= FSR_ROL_( b, 14);
   a ^= c; a -= FSR_ROL_( c, 11);
   b ^= a; b -= FSR_ROL_( a, 25);
   c ^= b; c -= FSR_ROL_( b, 16);
   a ^= c; a -= FSR_ROL_( c, 4);
   b ^= a; b -= FSR_ROL_( a, 14);
   c ^= b; c -= FSR_ROL_( b, 24);
   return c & PT_SCAST( unsigned, mapMask);
}
#undef FSR_ROL_

struct/*interface*/ FsrFlowMonitor
{
   virtual void PT_CCALL FlowRecvStart() = 0;
   virtual void PT_CCALL FlowRecvComplete() = 0;
   virtual void PT_CCALL FlowSendStart() = 0;
   virtual void PT_CCALL FlowSendComplete() = 0;
};

struct/*interface*/ FsrClient
{
   virtual void PT_CCALL Retain() = 0;
   virtual void PT_CCALL Release() = 0;
   virtual void PT_CCALL Cancel() = 0;
   virtual int /*perr*/ PT_CCALL Connect( malloc_i* ma, pin_i* cancelPin, FsrFormatter** formatter, int* serverVersion, int* volumeFlags, PT_SZ_T* formatterName) = 0;
   virtual int /*perr*/ PT_CCALL MsgFlushMedia( pin_i* cancelPin, PT_BOOL async) = 0;
};

struct/*interface*/ FsrServer
{
   virtual void PT_CCALL Release() = 0;
   virtual void PT_CCALL Cancel() = 0;
   virtual int /*err*/ PT_CCALL Connect( pin_i* cancelPin, int* clientVersion, int* clientFlags, int* clientFileNameType, FsrFormatter* formatter) = 0;
   virtual void PT_CCALL Serve( pin_i* cancelPin, FsrFlowMonitor* flow, FsrFormatter* formatter) = 0;
};

static const int fsrPolicyFlagRead = 0x00000001;
static const int fsrPolicyFlagWrite = 0x00000002;
static const int fsrPolicyFlagCreate = 0x00000004;
static const int fsrPolicyFlagDelete = 0x00000008;
static const int fsrPolicyFlagTraverse = 0x00000010;
static const int fsrPolicyFlagUndelete = 0x00000020;
static const int fsrPolicyFlagTemp = 0x00000040;
static const int fsrPolicyFlagTrash = 0x00000080;
static const int fsrPolicyFlagAuditRead = 0x00000100;
static const int fsrPolicyFlagAuditWrite = 0x00000200;
static const int fsrPolicyFlagAuditCreate = 0x00000400;
static const int fsrPolicyFlagAuditDelete = 0x00000800;
static const int fsrPolicyFlagReserved9 = 0x00400000;
static const int fsrPolicyFlagReserved8 = 0x00800000;
static const int fsrPolicyFlagReserved7 = 0x01000000;
static const int fsrPolicyFlagReserved6 = 0x02000000;
static const int fsrPolicyFlagReserved5 = 0x04000000;
static const int fsrPolicyFlagReserved4 = 0x08000000;
static const int fsrPolicyFlagReserved3 = 0x10000000;
static const int fsrPolicyFlagReserved2 = 0x20000000;
static const int fsrPolicyFlagReserved1 = 0x40000000;

#define fsrDeletedFilesFolderName "_Deleted_Files_"

struct/*interface*/ FsrPolicyFormatterOwner
{
   virtual void PT_CCALL FsrPolicyFormatterOwner_Retain() = 0;
   virtual void PT_CCALL FsrPolicyFormatterOwner_Release() = 0;
   virtual PT_INT64 /*inst*/ PT_CCALL GetNamePolicyInstance() = 0;
   virtual int /*flags*/ PT_CCALL GetNamePolicy( PT_SZC_T*const nameParts, PT_SIZE_T namePartCount, int fileType) = 0;
   virtual void PT_CCALL AuditPolicy( int flags, PT_SZC_T*const nameParts, PT_SIZE_T namePartCount, int fileType) = 0;
};

}
#ifdef __cplusplus_cli
#pragma managed(pop)
#endif
#endif
