#ifndef __OFS_API_H__
#define __OFS_API_H__
/******************************************************************************/
/*                                                                            */
/*                             X r d O f s . h h                              */
/*                                                                            */
/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University  */
/*   Produced by Andrew Hanushevsky for Stanford University under contract    */
/*              DE-AC02-76-SFO0515 with the Department of Energy              */
/*                                                                            */
/* This file is part of the XRootD software suite.                            */
/*                                                                            */
/* XRootD is free software: you can redistribute it and/or modify it under    */
/* the terms of the GNU Lesser General Public License as published by the     */
/* Free Software Foundation, either version 3 of the License, or (at your     */
/* option) any later version.                                                 */
/*                                                                            */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT      */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or      */
/* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public       */
/* License for more details.                                                  */
/*                                                                            */
/* You should have received a copy of the GNU Lesser General Public License   */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file  */
/* COPYING (GPL license).  If not, see <http://www.gnu.org/licenses/>.        */
/*                                                                            */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without  */
/* specific prior written permission of the institution or contributor.       */
/******************************************************************************/

#include <cstring>
#include <dirent.h>
#include <sys/types.h>

#include "XrdOfs/XrdOfsEvr.hh"
#include "XrdOfs/XrdOfsHandle.hh"
#include "XrdOuc/XrdOucCloneSeg.hh"
#include "XrdSys/XrdSysPthread.hh"
#include "XrdSfs/XrdSfsInterface.hh"
#include "XrdCms/XrdCmsClient.hh"

class XrdNetIF;
class XrdOfsEvs;
class XrdOfsPocq;
class XrdOfsPrepare;
class XrdOss;
class XrdOssDF;
class XrdOssDir;
class XrdOucEnv;
class XrdOucPListAnchor;
class XrdSysError;
class XrdSysLogger;
class XrdOucStream;
class XrdSfsAio;

struct XrdVersionInfo;

/******************************************************************************/
/*                       X r d O f s D i r e c t o r y                        */
/******************************************************************************/

class XrdOfsDirectory : public XrdSfsDirectory
{
public:

        int         open(const char              *dirName,
                         const XrdSecEntity      *client,
                         const char              *opaque = 0);

        const char *nextEntry();

        int         close();

inline  void        copyError(XrdOucErrInfo &einfo) {einfo = error;}

const   char       *FName() {return (const char *)fname;}

        int         autoStat(struct stat *buf);

                    XrdOfsDirectory(XrdOucErrInfo &eInfo, const char *user)
                          : XrdSfsDirectory(eInfo), tident(user ? user : ""),
                            fname(0), dp(0), atEOF(0) {}

virtual            ~XrdOfsDirectory() {if (dp) close();}

protected:
const char    *tident;
char          *fname;
XrdOssDF      *dp;
int            atEOF;
char           dname[MAXNAMLEN];
};

class XrdOfsDirFull : public XrdOfsDirectory
{
public:
                    XrdOfsDirFull(const char *user, int MonID)
                          : XrdOfsDirectory(myEInfo, user), myEInfo(user, MonID)
                          {}

virtual            ~XrdOfsDirFull() {}

private:
XrdOucErrInfo  myEInfo; // Accessible only by reference error
};

/******************************************************************************/
/*                            X r d O f s F i l e                             */
/******************************************************************************/

class XrdOfsTPC;
class XrdOucChkPnt;

class XrdOfsFile : public XrdSfsFile
{
public:

        int            open(const char                *fileName,
                                  XrdSfsFileOpenMode   openMode,
                                  mode_t               createMode,
                            const XrdSecEntity        *client,
                            const char                *opaque = 0);

        int            checkpoint(XrdSfsFile::cpAct act,
                                  struct iov *range=0, int n=0);

        int            Clone(XrdSfsFile& srcFile);

        int            Clone(const std::vector<XrdOucCloneSeg> &cVec);

        int            close();

        using          XrdSfsFile::fctl;

        int            fctl(const int               cmd,
                            const char             *args,
                                  XrdOucErrInfo    &out_error);

        int            fctl(const int               cmd,
                                  int               alen,
                                  const char       *args,
                            const XrdSecEntity     *client = 0);

        const char    *FName() {return (oh ? oh->Name() : "?");}

        int            getMmap(void **Addr, off_t &Size);

        XrdSfsXferSize pgRead(XrdSfsFileOffset   offset,
                              char              *buffer,
                              XrdSfsXferSize     rdlen,
                              uint32_t          *csvec,
                              uint64_t           opts=0);

        int            pgRead(XrdSfsAio *aioparm, uint64_t opts=0);


        XrdSfsXferSize pgWrite(XrdSfsFileOffset   offset,
                               char              *buffer,
                               XrdSfsXferSize     wrlen,
                               uint32_t          *csvec,
                               uint64_t           opts=0);

        int            pgWrite(XrdSfsAio *aioparm, uint64_t opts=0);


        int            read(XrdSfsFileOffset   fileOffset,   // Preread only
                            XrdSfsXferSize     amount);

        XrdSfsXferSize read(XrdSfsFileOffset   fileOffset,
                            char              *buffer,
                            XrdSfsXferSize     buffer_size);

        XrdSfsXferSize readv(XrdOucIOVec      *readV,
                             int               readCount);

        int            read(XrdSfsAio *aioparm);

        XrdSfsXferSize write(XrdSfsFileOffset   fileOffset,
                             const char        *buffer,
                             XrdSfsXferSize     buffer_size);

        int            write(XrdSfsAio *aioparm);

        int            sync();

        int            sync(XrdSfsAio *aiop);

        int            stat(struct stat *buf);

        int            truncate(XrdSfsFileOffset   fileOffset);

        int            getCXinfo(char cxtype[4], int &cxrsz);

                       XrdOfsFile(XrdOucErrInfo &eInfo, const char *user);

                      ~XrdOfsFile() {viaDel = true; if (oh) close();}

protected:

const char    *tident;
XrdOfsHandle  *oh;
XrdOfsTPC     *myTPC;
XrdOucChkPnt  *myCKP;
int            dorawio;
bool           viaDel;
bool           ckpBad;

private:

void           GenFWEvent();
int            CreateCKP();
};

class XrdOfsFileFull : public XrdOfsFile
{
public:
                    XrdOfsFileFull(const char *user, int MonID)
                          : XrdOfsFile(myEInfo, user), myEInfo(user, MonID)
                          {}

virtual            ~XrdOfsFileFull() {}

private:
XrdOucErrInfo  myEInfo; // Accessible only by reference error
};

/******************************************************************************/
/*                          C l a s s   X r d O f s                           */
/******************************************************************************/

class XrdAccAuthorize;
class XrdCks;
class XrdCksCalc;
class XrdCmsClient;
class XrdOfsConfigPI;
class XrdOfsFSctl_PI;
class XrdOfsPoscq;
struct XrdSfsFACtl;

class XrdOfs : public XrdSfsFileSystem
{
friend class XrdOfsDirectory;
friend class XrdOfsFile;

public:

// Object allocation
//
        XrdSfsDirectory *newDir(char *user=0, int MonID=0)
                        {return new XrdOfsDirFull(user, MonID);}

        XrdSfsDirectory *newDir(XrdOucErrInfo &eInfo)
                        {return new XrdOfsDirectory(eInfo, eInfo.getErrUser());}

        XrdSfsFile      *newFile(char *user=0,int MonID=0)
                        {return new XrdOfsFileFull(user, MonID);}

        XrdSfsFile      *newFile(XrdOucErrInfo &eInfo)
                        {return new XrdOfsFile(eInfo, eInfo.getErrUser());}

// Other functions
//
        int            chksum(      csFunc            Func,
                              const char             *csName,
                              const char             *Path,
                                    XrdOucErrInfo    &out_error,
                              const XrdSecEntity     *client = 0,
                              const char             *opaque = 0);

        int            chmod(const char             *Name,
                                   XrdSfsMode        Mode,
                                   XrdOucErrInfo    &out_error,
                             const XrdSecEntity     *client,
                             const char             *opaque = 0);

        void           Connect(const XrdSecEntity     *client = 0);

        void           Disc(const XrdSecEntity *client = 0);

        int            exists(const char                *fileName,
                                    XrdSfsFileExistence &exists_flag,
                                    XrdOucErrInfo       &out_error,
                              const XrdSecEntity        *client,
                              const char                *opaque = 0);

        int            FAttr(      XrdSfsFACtl      *faReq,
                                   XrdOucErrInfo    &eInfo,
                             const XrdSecEntity     *client = 0);

        int            FSctl(const int               cmd,
                                   XrdSfsFSctl      &args,
                                   XrdOucErrInfo    &eInfo,
                             const XrdSecEntity     *client = 0);

        int            fsctl(const int               cmd,
                             const char             *args,
                                   XrdOucErrInfo    &out_error,
                             const XrdSecEntity     *client = 0);

        int            getStats(char *buff, int blen);

const   char          *getVersion();

        int            mkdir(const char             *dirName,
                                   XrdSfsMode        Mode,
                                   XrdOucErrInfo    &out_error,
                             const XrdSecEntity     *client,
                             const char             *opaque = 0);

        int            prepare(      XrdSfsPrep       &pargs,
                                     XrdOucErrInfo    &out_error,
                               const XrdSecEntity     *client = 0);

        int            rem(const char             *path,
                                 XrdOucErrInfo    &out_error,
                           const XrdSecEntity     *client,
                           const char             *info = 0)
                          {return remove('f', path, out_error, client, info);}

        int            remdir(const char             *dirName,
                                    XrdOucErrInfo    &out_error,
                              const XrdSecEntity     *client,
                              const char             *info = 0)
                             {return remove('d',dirName,out_error,client,info);}

        int            rename(const char             *oldFileName,
                              const char             *newFileName,
                                    XrdOucErrInfo    &out_error,
                              const XrdSecEntity     *client,
                              const char             *infoO = 0,
                               const char            *infoN = 0);

        int            stat(const char             *Name,
                                  struct stat      *buf,
                                  XrdOucErrInfo    &out_error,
                            const XrdSecEntity     *client,
                            const char             *opaque = 0);

        int            stat(const char             *Name,
                                  mode_t           &mode,
                                  XrdOucErrInfo    &out_error,
                            const XrdSecEntity     *client,
                            const char             *opaque = 0);

        int            truncate(const char             *Name,
                                      XrdSfsFileOffset fileOffset,
                                      XrdOucErrInfo    &out_error,
                                const XrdSecEntity     *client = 0,
                                const char             *opaque = 0);
// Management functions
//
virtual int            Configure(XrdSysError &); // Backward Compatibility

virtual int            Configure(XrdSysError &, XrdOucEnv *);

        void           Config_Cluster(XrdOss *);

        void           Config_Display(XrdSysError &);

        int            SetupCksRT(XrdCksCalc*&, XrdOucEnv&, const char*&);

        bool           WantCksRT() {return (CksRTCgi || CksRTCalc != 0);}

                       XrdOfs();
virtual               ~XrdOfs() {}  // Too complicate to delete :-)

/******************************************************************************/
/*                  C o n f i g u r a t i o n   V a l u e s                   */
/******************************************************************************/

// Configuration values for this filesystem
//
enum {Authorize = 0x0001,    // Authorization wanted
      XAttrPlug = 0x0002,    // Extended Attribute Plugin
      isPeer    = 0x0050,    // Role peer
      isProxy   = 0x0020,    // Role proxy
      isManager = 0x0040,    // Role manager
      isServer  = 0x0080,    // Role server
      isSuper   = 0x00C0,    // Role supervisor
      isMeta    = 0x0100,    // Role meta + above
      haveRole  = 0x01F0,    // A role is present
      Forwarding= 0x1000,    // Fowarding wanted
      ThirdPC   = 0x2000,    // This party copy wanted
      SubCluster= 0x4000,    // all.subcluster directive encountered
      RdrTPC    = 0x8000
     };                      // These are set in Options below

int   Options;               // Various options
int   myPort;                // Port number being used

// Directory and file creation mode controls
//
mode_t            dMask[2];  // Min/Max directory mode
mode_t            fMask[2];  // Min/Max file      mode

// TPC related things
//
char             *tpcRdrHost[2];  // TPC redirect target or null if none
int               tpcRdrPort[2];  // TPC redirect target port number

// Networking
//
XrdNetIF *myIF;

// Forward options
//
struct fwdOpt
      {const char *Cmd;
             char *Host;
             int   Port;
             void  Reset() {Cmd = 0; Port = 0;
                            if (Host) {free(Host); Host = 0;}
                           }
                   fwdOpt() : Cmd(0), Host(0), Port(0) {}
                  ~fwdOpt() {}
      };

struct fwdOpt fwdCHMOD;
struct fwdOpt fwdMKDIR;
struct fwdOpt fwdMKPATH;
struct fwdOpt fwdMV;
struct fwdOpt fwdRM;
struct fwdOpt fwdRMDIR;
struct fwdOpt fwdTRUNC;

static int MaxDelay;  //    Max delay imposed during staging
static int OSSDelay;  //    Delay to impose when oss interface times out

char *ConfigFN;       //    ->Configuration filename

/******************************************************************************/
/*                       P r o t e c t e d   I t e m s                        */
/******************************************************************************/

protected:

XrdOfsEvr     evrObject;      // Event receiver
XrdCmsClient *Finder;         // ->Cluster Management Service

virtual int   ConfigXeq(char *var, XrdOucStream &, XrdSysError &);
static  int   Emsg(const char *, XrdOucErrInfo  &, int, const char *x,
                   XrdOfsHandle *hP, bool posChk=false, bool chktype=true);
static  int   Emsg(const char *, XrdOucErrInfo  &, int, const char *x,
                   const char *y="", const char* xtra=0, bool chktype=true);
static  int   EmsgType(int ecode);
static  int   fsError(XrdOucErrInfo &myError, int rc);
const char   *Split(const char *Args, const char **Opq, char *Path, int Plen);
        int   Stall(XrdOucErrInfo  &, int, const char *);
        void  Unpersist(XrdOfsHandle *hP, int xcev=1);
        bool  ValidCST(const char* cst);
        char *WaitTime(int, char *, int);

/******************************************************************************/
/*                 P r i v a t e   C o n f i g u r a t i o n                  */
/******************************************************************************/

private:

char             *myRole;
XrdOfsFSctl_PI   *FSctl_PC;       //    ->FSctl plugin (cache specific)
XrdOfsFSctl_PI   *FSctl_PI;       //    ->FSctl plugin
XrdAccAuthorize  *Authorization;  //    ->Authorization   Service
XrdCmsClient     *Balancer;       //    ->Cluster Local   Interface
XrdOfsEvs        *evsObject;      //    ->Event Notifier
XrdOucPListAnchor*ossRPList;      //    ->Oss exoprt list

XrdOfsPoscq      *poscQ;          //    -> poscQ if  persist on close enabled
char             *poscLog;        //    -> Directory for posc recovery log
int               poscHold;       //       Seconds to hold a forced close
short             poscSync;       //       Number of requests before sync
signed char       poscAuto;       //  1 -> Automatic persist on close

char              ossRW;          // The oss r/w capability

XrdOfsConfigPI   *ofsConfig;      // Plugin   configurator
XrdOfsPrepare    *prepHandler;    // Plugin   prepare
XrdCks           *Cks;            // Checksum manager
XrdCksCalc       *CksRTCalc;      // Automatic realtime checksum calculator
char             *CksRTName;      // Automatic realtime checksum cipher
bool              CksPfn;         // Checksum needs a pfn
bool              CksRdr;         // Checksum may be redirected (i.e. not local)
bool              prepAuth;       // Prepare requires authorization
char              OssIsProxy;     // !0 if we detect the oss plugin is a proxy
char              myRType[4];     // Role type for consistency with the cms

uint64_t          ossFeatures;    // The oss features

int               usxMaxNsz;      // Maximum length of attribute name
int               usxMaxVsz;      // Maximum length of attribute value

static XrdOfsHandle     *dummyHandle;
XrdSysMutex              ocMutex; // Global mutex for open/close

bool              DirRdr;         // Opendir() can be redirected.
bool              reProxy;        // Reproxying required for TPC
bool              OssHasPGrw;     // True: oss implements full rgRead/Write
bool              tryXERT;        // Try using extended error text from OSS
bool              CksRTCgi;       // True -> allow CGI spec

/******************************************************************************/
/*                            O t h e r   D a t a                             */
/******************************************************************************/

// Internal file attribute methods
//
int ctlFADel(XrdSfsFACtl &faCtl, XrdOucEnv &faEnv, XrdOucErrInfo &einfo);
int ctlFAGet(XrdSfsFACtl &faCtl, XrdOucEnv &faEnv, XrdOucErrInfo &einfo);
int ctlFALst(XrdSfsFACtl &faCtl, XrdOucEnv &faEnv, XrdOucErrInfo &einfo);
int ctlFASet(XrdSfsFACtl &faCtl, XrdOucEnv &faEnv, XrdOucErrInfo &einfo);

// Common functions
//
int   remove(const char type, const char *path, XrdOucErrInfo &out_error,
             const XrdSecEntity *client, const char *opaque);

// Function used during Configuration
//
int           ConfigCksRT(XrdSysError &Eroute, XrdOucEnv *EnvInfo);
int           ConfigDispFwd(char *buff, struct fwdOpt &Fwd);
int           ConfigPosc(XrdSysError &Eroute);
int           ConfigRedir(XrdSysError &Eroute, XrdOucEnv *EnvInfo);
int           ConfigTPC(XrdSysError &Eroute, XrdOucEnv *EnvInfo);
int           ConfigTPC(XrdSysError &Eroute);
char         *ConfigTPCDir(XrdSysError &Eroute, const char *sfx,
                                                const char *xPath=0);
const char   *Fname(const char *);
int           Forward(int &Result, XrdOucErrInfo &Resp, struct fwdOpt &Fwd,
                      const char *arg1=0, const char *arg2=0,
                      XrdOucEnv  *Env1=0, XrdOucEnv  *Env2=0);
int           FSctl(XrdOfsFile &file, int cmd, int alen, const char *args,
                    const XrdSecEntity *client);
int           Reformat(XrdOucErrInfo &);
const char   *theRole(int opts);
int           xcksrt(XrdOucStream &, XrdSysError &);
int           xcrds(XrdOucStream &, XrdSysError &);
int           xcrm(XrdOucStream &, XrdSysError &);
int           xdirl(XrdOucStream &, XrdSysError &);
int           xexp(XrdOucStream &, XrdSysError &, bool);
int           xforward(XrdOucStream &, XrdSysError &);
int           xmaxd(XrdOucStream &, XrdSysError &);
int           xnmsg(XrdOucStream &, XrdSysError &);
int           xnot(XrdOucStream &, XrdSysError &);
int           xpers(XrdOucStream &, XrdSysError &);
int           xrole(XrdOucStream &, XrdSysError &);
int           xtpc(XrdOucStream &, XrdSysError &);
int           xtpcal(XrdOucStream &, XrdSysError &);
int           xtpcr(XrdOucStream &, XrdSysError &);
int           xtrace(XrdOucStream &, XrdSysError &);
int           xatr(XrdOucStream &, XrdSysError &);
};
#endif
