/* CFS.h - common definitions for XFH.
   Copyright (C) 1991, 1992, 1993 Kristian Nielsen.

   This file is part of XFH, the compressing file system handler.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            */


#include "version.h"

#include <dos/dosextens.h>
#include <dos/exall.h>
#include <dos/notify.h>
#include <dos/filehandler.h>

#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/xpkmaster_lib.h>

extern struct DosLibrary *DOSBase;

#include <clib/alib_protos.h>

#define MAXFILENAME 30        /* Maximum length of file names. */
#define XROOTNAME "XFH"       /* Unit number and ':' will be appended. */
#define XROOTNAMESIZE 15      /* Max. size of root assign (unit 2^32-1) */

#define ALTOPTIONPATH ".xfhrc"

#define TMPNAMETEMPLATE "%lx.%lx_XFH"   /* Used in SPrintF(..,task,num) */
#define TMPNAMEMAXSIZE  (8+ 1+8+4+  1)

#define AREXXPORTTEMPLATE "%s"         /* %s will be device name (XHx:) */
#define AREXXPORTMAXLEN 1              /* Plus device name size. */
#define AREXXPORTPRI 1

#define OUTOFMEM glob -> ioerr = ERROR_NO_FREE_STORE
#define DECLIOERR LONG saveioerr;
#define PUTIOERR saveioerr = glob->ioerr
#define SAVEIOERR LONG saveioerr = glob->ioerr
#define RESTIOERR glob->ioerr = saveioerr

#define XFH_ID "XFH A"

#define MAXSTRING 256   /* Maximum length of some strings (like a path). */
#ifdef DEBUG
extern void KPrintF(char *,...);
#define debug(a) KPrintF a
#else
#define debug(a)
#endif


/* This is the structure used internally to represent a file/directory
 * lock. All locks we return contain the address of this structure in their
 * lock->fl_Key field.
 *
 * The CFSLock.refcount field is a sad hack nessesary to overcome a
 * problem with exclusive directory locks when compressing files. The
 * problem is that we need a copy of the parent lock used in RawCFSOpen()
 * when the file is Close()'d. However, if the parent lock is exclusive,
 * it cannot be DupLock()'ed, and so we must store a reference to it.
 * The refcount counts the number of such references, and prevents the
 * lock from going away until after the Close().
 */

struct CFSLock
 {
  LONG objtype;
  struct cfsfunctions *f;
  LONG mode;
  struct FileLock *xlock;
  LONG refcount;            /* Currently valid only for XOBJECT's. */
 };


/* Structure for file handles. */
struct CFSFH
 {
  LONG objtype;
  struct cfsfunctions *f;
  LONG mode;
  struct FileHandle *xfh;
  char *filename;            /* Used when compressing file at Close(). */
  struct CFSLock *parent;   /* Used when compressing file at Close(). */
  /* A non-null 'filename' field means (for xobj's) that Close() will
   * attempt to compress the file. */
 };

/* CFSLock filetypes. */
#define XOBJECTB  1      /* A simple handle on an object in ufs. */
/* #define NUKEOBJECTB 2 */   /* The NUKE format (U. Mueller). */
/* #define PPACKOBJB 3   */   /* Files packed with powerpacker. */
#define XPKOBJECTB 4     /* Xpk.library files. */

#define XOBJECT     (1 << XOBJECTB)
/* #define NUKEOBJECT  (1 << NUKEOBJECTB) */
/* #define PPACKOBJ    (1 << PPACKOBJB)   */
#define XPKOBJECT   (1 << XPKOBJECTB)


/* Blocksize to fake in Examine()/ExNext(). */
#define BLOCKSIZE glob->bytesperblock    

/* Global datastructure. This allow us to use global variables and still
 * be reentrant without using any kind of short addressing (no need for
 * any __saveds keywords or startup code).
 */
struct glob
 {
  /* Shared data buffers to save on dalloc()'s.*/
  /* Note that care should be taken when using these, since they are*/
  /* shared between a number of functions. A rule of thumb is that a*/
  /* lower level (dosfunc.c) shouldn't use something owned by a*/
  /* higher level (lock.c). This way, a call in lock.c to a function*/
  /* in dosfunc.c won't change your buffer, while a call to another*/
  /* lock.c-function potentially may.*/
	
  char stringbuf[MAXSTRING];        /* Buffer for dosfunctions (bstr conv.) */
  char stringbuf2[MAXSTRING];       /* Buffer for dosfunctions (bstr conv.) */
  char pktstringbuf[MAXSTRING];     /* Buffer for packet bstr->cstr. */
  char pktstringbuf2[MAXSTRING];    /* Buffer for packet bstr->cstr. */
  struct FileInfoBlock fib1;        /* Used during Lock(). */
  struct FileInfoBlock fib2;        /* General high-level in dosfunc.c */
  struct StandardPacket iopkt;      /* This will be long alligned. */
  struct InfoData infodata;
  
  struct MsgPort *dosport,          /* Dos Port (ProcId) of this handler. */
                 *ioport,           /* Port to use for DOS IO. */
                 *xpkport;          /* Port for calling Xpk in KS1.3. */
  struct Task *mytask;              /* Copy of FindTask(0L) */
  struct Process *myproc;
  void *DOSBase;
  struct Library *XpkBase;
  struct Library *IconBase;
  struct DeviceNode *devnode;
  char *devname;
  struct DeviceList *volnode;       /* Pointer to our volumenode. */
  BSTR bcplstartup;                 /* Copy of BPTR to startup string. */
  struct CFSLock *rootlock;         /* Our rootlock. */
  struct FileLock *xrootlock;       /* Rootlock for underlying fs. */
  struct MsgPort *xprocid;          /* ProcID of the underlying fs. */
  LONG ioerr;
  short opencnt;
  BOOL done;                        /* Flag for main packet loop. */
  LONG tmpfilecount;                /* used for tmpfile generation. */
  LONG bytesperblock;               /* Blocksize in the UFS. */
  struct MsgPort *arexxport;
  char *arexxportname;

  /* These are options handled by 'options.c'. */
  /* Also read by SetConfigSem() in gui.c. */
  char *badoption;                  /* Name of errorneous option. */
  BOOL optionsset;                  /* True when options has been set. */
  
  BOOL stepdown;                    /* Flag for XpkPack(). */
  BOOL autocompress;                /* Whether to compress on Write(). */
  BOOL xscan;                       /* Whether to create xScan comments. */
  BOOL truncateonpack;              /* Use SetFileSize() when packing? */
  char *packmode;                   /* Packmode for XpkPack(). */
  char *xRootName;                  /* 'True' name of our root dir. */
  char *uservolname;                /* User requested volume name. ONLY
                                     * accessed by createvolnode(). */
  char *xpkpassword;                /* Password used in Xpk(Un)Pack(). */
  BOOL xpksetpri;                   /* Change taskpri when (un)packing? */
  LONG xpkpri;                      /* priority to use if xpksetpri. */
  BOOL createvolnode;               /* Whether se have a volume. *NOTE*: */
                                    /* DON'T CHANGE AFTER createvolnode().*/
  BOOL FailOnExNext;                /* Silently gobble ModifyFIB() errors.*/
  BOOL compressreadwrite;           /* Whether to compress MODE_READWRITE.*/
  BOOL allowappend;                 /* Whether to support MODE_READWRITE.*/
  char *userarexxportname;          /* User requested name of AREXX port. */
  BOOL EnvoyKludge;                 /* Use Kludge for Envoy FS            */

#ifdef DEBUG
  /* Extra fields for debug code. */
  char debugbuf1[MAXSTRING];
  char debugbuf2[MAXSTRING];        /* Used to print bcpl strings. */
#endif
 };

typedef struct glob *glb;


/* For each of the supported file formats, there is an instance of this
 * structure. It holds pointers to fuctions that performs tasks such as
 * Read(), Lock(), etc.
 */
struct cfsfunctions
 {
/*********************** Input/Output functions. ************************/
      /* Open file from parent lock of this type and a simple filename
       * (no path specification). This will determine file type and
       * fetch the correct function to actually do the open.
       */
  struct CFSFH * (*Open)(glb, struct CFSLock *, char *, LONG);
     /* Read(), Write(), Seek(), Close() functions. */
  LONG (*Read)(glb, struct CFSFH *, UBYTE *, LONG );
  LONG (*Write)(glb, struct CFSFH *, UBYTE *, LONG );
  LONG (*Seek)(glb, struct CFSFH *, LONG, LONG );
  LONG (*Close)(glb, struct CFSFH *);
  BOOL (*SetFileSize)(glb, struct CFSFH *, LONG, LONG);
  BOOL (*LockRecord)(glb, struct CFSFH *, LONG, LONG, LONG, LONG);
  BOOL (*UnLockRecord)(glb, struct CFSFH *, LONG, LONG);
/*********************** Input/Output functions. ************************/
     /* Lock function. As with Open, the type refers to the parent lock. */
  struct CFSLock * (*Lock)(glb, struct CFSLock *, char *, LONG);
     /* Other functions related to locks. */
  struct CFSLock * (*DupLock)(glb, struct CFSLock *);
  BOOL (*UnLock)(glb, struct CFSLock *);   /* Always succesful. */
  BOOL (*Examine)(glb, struct CFSLock *, struct FileInfoBlock *);
  BOOL (*ExNext)(glb, struct CFSLock *, struct FileInfoBlock *);
  struct CFSLock * (*CreateDir)(glb, struct CFSLock *, char *);
  BOOL (*DeleteFile)(glb, struct CFSLock *, char *);
     /* Rename() is a bit tricky. As an example, how is a Rename()
      * from a powerpacked file to an archive to be handled?
		 * The correct Rename() function to call is determined from
		 * the type of the FROM directory. Each function must then
		 * check the type of the destination directory themselves.
      */
  BOOL (*Rename)(glb, struct CFSLock *, char *, struct CFSLock *, char *);
  struct CFSLock * (*Parent)(glb, struct CFSLock *);
  BOOL (*SetProtection)(glb, struct CFSLock *, char *, LONG);
  BOOL (*SetComment)(glb, struct CFSLock *, char *, char *);
  BOOL (*SetFileDate)(glb, struct CFSLock *, char *, struct DateStamp *);
  struct CFSFH *(*OpenFromLock)(glb, struct CFSLock *);
     /* ToDo: What is SameLock() really supposed to do, packet level?
      * In the CFS, internally, each filetype has a SameLock() that
      * expects two locks of the same type, and returns a bool.
      */
  BOOL (*SameLock)(glb, struct CFSLock *, struct CFSLock *);
     /* ToDo: Support for links also really needs some work... */
  BOOL (*MakeLink)(glb, struct CFSLock *, char *, LONG, LONG);
  LONG (*ReadLink)(glb, struct CFSLock *, char *, char *, ULONG);
  BOOL (*ChangeMode)(glb, LONG, void *, LONG);
  struct CFSLock * (*DupLockFromFH)(glb, struct CFSFH *);
  struct CFSLock * (*ParentOfFH)(glb, struct CFSFH *);
     /* The new 2.0 Examine..() type functions. ExAll() will be
      * simulated if NULL.
      */
  LONG (*ExAll)(glb, struct CFSLock *, char *, LONG, LONG, struct ExAllControl *);
  BOOL (*ExamineFH)(glb, struct CFSFH *, struct FileInfoBlock *);
     /* ToDo: The notify functions still need some thought. Remember,
      * a notify is on an absolute path, not relative to a Lock.
      */
  BOOL (*StartNotify)(glb, struct NotifyRequest *);
  BOOL (*EndNotify)(glb, struct NotifyRequest *);
 };

extern struct cfsfunctions Xfunc,Xpkfunc;

/* Prototypes. */
/* CFS.c */
struct DosPacket *getpkt(glb);
ULONG getpktsigmask(glb);
struct DosPacket *checkpkt(glb);
void returnpkt(struct DosPacket *,LONG,LONG,glb);
struct MsgPort *DoDeviceProc(LONG *,char *,glb);
BPTR getfile(char *,glb);
void closefile(BPTR,glb);
void addvolnode(glb,struct DeviceList *);
BOOL removevolnode(glb,struct DeviceList *);
void DevNode_Stuff_Startup_String(glb,BSTR);
BOOL createvolnode(glb,BOOL,struct FileInfoBlock *);
BOOL SetVolumeNameVolNode(glb,char *);
BOOL freevolnode(glb);
BOOL diskinfo(glb,struct InfoData *);
void SPrintF(char *,char *,...);

/* Packet.c */
void putpkt(struct StandardPacket *,struct MsgPort *,struct MsgPort *,LONG,int,...);
LONG dopkt(struct StandardPacket *,struct MsgPort *,struct MsgPort *,LONG *,LONG,int,...);


/* dosfunc.c */
struct FileLock *xLock(glb,struct FileLock *, char *name, LONG);
BOOL xExists1(glb,struct FileLock *, char *);
BOOL xExamine(glb, struct FileLock *,struct FileInfoBlock *);
BOOL xExamineNext(glb,struct FileLock *,struct FileInfoBlock *);
BOOL xExamineFH(glb,struct FileHandle *,struct FileInfoBlock *);
struct FileLock *xCreateDir(glb,struct FileLock *, char *);
BOOL xDeleteFile(glb,struct FileLock *, char *);
BOOL xRename(glb,struct FileLock *,char *,struct FileLock *, char *);
struct FileLock *xParentDir(glb,struct FileLock *);
struct FileLock *xParentFH(glb,struct FileHandle *);
BOOL xSetProtection(glb,struct FileLock *,char *,LONG);
BOOL xSetComment(glb,struct FileLock *,char *,char *);
BOOL xSetFileDate(glb,struct FileLock *,char *,struct DateStamp *);
struct FileLock *xDupLock(glb,struct FileLock *);
BOOL xUnLock(glb,struct FileLock *lock);
struct FileHandle *xOpen(glb,struct FileLock *,char *,LONG);
struct FileHandle *xOpenFromLock(glb,struct FileLock *);
struct FileHandle *xOpenFromCopyOfLock(glb,struct FileLock *);
BOOL xClose(glb,struct FileHandle *);
LONG xRead(glb,struct FileHandle *,void *,LONG);
LONG xWrite(glb,struct FileHandle *,void *,LONG);
LONG xSeek(glb,struct FileHandle *,LONG,LONG);
BOOL xChangeMode(glb,ULONG,void *obj,ULONG);
BOOL xInfo(glb,struct FileLock *,struct InfoData *);
BOOL xMakeLink(glb,struct FileLock *,char *,LONG,LONG);
BOOL xReadLink(glb,struct FileLock *,char *,char *,ULONG);
LONG xSameLock(glb,struct FileLock *, struct FileLock *);
BOOL xgetpath(glb,struct FileLock *,char *,int);
BOOL TransformXFH(glb,struct FileHandle *,struct FileLock *,char *,BOOL (*f)(glb,struct FileHandle *,struct FileHandle *,void *),void *userdata);
BOOL TransformFile(glb,struct FileLock *,char *,BOOL (*f)(glb,struct FileHandle *,struct FileHandle *,void *), void *userdata);
LONG xGetFileSize(glb,struct FileHandle *);
BOOL xWriteStr(glb,struct FileHandle *,char *);


/* misc.c */
char *copybstr(BSTR bstr);
char *copystr(char *str);
void freestr(char *str);
char *safebstr2cinplace(UBYTE *,int);
BSTR safecstr2binplace(char *,int);
LONG ank(glb,...);
LONG ank_fail(glb,...);
LONG owt(glb,...);
LONG abs_seek_pos(LONG,LONG,LONG,LONG);
LONG xFileSizeXfh(glb,struct FileHandle *);


/* lock.c */
struct CFSLock *RawCFSLock(glb,struct CFSLock *,char *,LONG);
struct FileLock * CreateFileLock(glb,struct CFSLock *);
struct CFSLock *CFSLockParent(glb,struct CFSLock *,char **);
struct CFSLock * CFSLock(glb,struct CFSLock *,char *,LONG);
struct CFSLock *makerootlockdayone(glb);
struct CFSLock *CFSDupLock(glb,struct CFSLock *);
struct CFSLock *CFSParentDir(glb,struct CFSLock *);
struct CFSLock *CFSParentFH(glb,struct CFSFH *);
BOOL CFSUnLock(glb,struct CFSLock *);
BOOL CFSExamine(glb,struct CFSLock *,struct FileInfoBlock *);
BOOL CFSExamineNext(glb,struct CFSLock *,struct FileInfoBlock *);
BOOL CFSExamineFH(glb,struct CFSFH *,struct FileInfoBlock *);
struct CFSLock *CFSCreateDir(glb,struct CFSLock *,char *);
BOOL CFSDeleteFile(glb,struct CFSLock *, char *);
BOOL CFSRename(glb,struct CFSLock *,char *,struct CFSLock *,char *);
BOOL CFSSetProtection(glb,struct CFSLock *,char *,LONG);
BOOL CFSSetComment(glb,struct CFSLock *,char *name,char *comment);
BOOL CFSSetDate(glb,struct CFSLock *,char *,struct DateStamp *);
BOOL CFSMakeLink(glb,struct CFSLock *,char *,LONG,LONG);
BOOL CFSReadLink(glb,struct CFSLock *,char *,char *,ULONG);
BOOL CFSSameLock(glb,struct CFSLock *,struct CFSLock *);


/* file.c */
struct CFSFH *RawCFSOpen(glb,struct CFSLock *,char *,LONG mode);
struct CFSFH *CFSOpen(glb,struct CFSLock *,char *,LONG);
BOOL CFSClose(glb,struct CFSFH *);
LONG CFSRead(glb,struct CFSFH *,void *,LONG);
LONG CFSWrite(glb,struct CFSFH *,void *,LONG);
LONG CFSSeek(glb,struct CFSFH *,LONG,LONG);

/* pack.c */
LONG xFileType(glb,struct FileHandle *);

/* xobj.c */
struct XpkFH *XpkOpenOldFile(glb,struct FileHandle *);
LONG XObjClose(glb,struct CFSFH *);
LONG XObjRead(glb,struct CFSFH *,UBYTE *,LONG);
LONG XObjWrite(glb,struct CFSFH *,UBYTE *,LONG);
LONG XObjSeek(glb,struct CFSFH *,LONG,LONG);
void XObjStealXpkFH(glb,struct CFSFH *);
BOOL XObjStuffFH(glb,struct CFSFH *,char *,struct CFSLock *);
void XObjUnStuffFH(glb,struct CFSFH *);
void XObjFreeFH(glb,struct CFSFH *);
struct CFSFH *XObjCreateFH(glb,struct FileHandle *,LONG,char *,struct CFSLock *);
struct CFSLock *XObjMakeLock(glb,struct FileLock *,LONG);
struct CFSLock *XObjDupLock(glb,struct CFSLock *);
void XObjAddReferenceToLock(glb,struct CFSLock *);
struct CFSLock *XObjParentDir(glb,struct CFSLock *);
struct CFSLock *XObjParentFH(glb,struct CFSFH *);
BOOL XObjUnLock(glb,struct CFSLock *);
BOOL XObjSameLock(glb,struct CFSLock *,struct CFSLock *);
BOOL XObjMakeLink(glb,struct CFSLock *,char *,LONG,LONG);
BOOL XObjReadLink(glb,struct CFSLock *,char *,char *,ULONG);
BOOL XObjExamine(glb,struct CFSLock *,struct FileInfoBlock *);
BOOL XObjExNext(glb,struct CFSLock *,struct FileInfoBlock *);
BOOL XObjExamineFH(glb,struct CFSFH *,struct FileInfoBlock *);
BOOL ModifyFIB(glb,struct CFSLock *,struct FileInfoBlock *);
BOOL XObjModifyFIB(glb,struct CFSLock *,struct FileInfoBlock *,struct FileHandle *);
struct CFSLock *XObjCreateDir(glb,struct CFSLock *,char *);
BOOL XObjSetProtection(glb,struct CFSLock *,char *,LONG);
BOOL XObjSetComment(glb,struct CFSLock *,char *,char *);
BOOL XObjSetFileDate(glb,struct CFSLock *,char *,struct DateStamp *);
BOOL XObjDeleteFile(glb,struct CFSLock *,char *);
BOOL XObjRename(glb,struct CFSLock *,char *,struct CFSLock *,char *);


/* xpk.c */
struct XpkLock;

struct XpkFH *XpkOpenOldFile(glb,struct FileHandle *);
struct XpkFH *XpkOpenOldFileFromCopyOfLock(glb,struct XpkLock *);
BOOL IsXpkFile(glb,struct FileHandle *);
BOOL PackFile2File(glb,struct FileHandle *,struct FileHandle *,void *);
BOOL UnPackFile2File(glb,struct FileHandle *,struct FileHandle *,void *);
BOOL XpkExamine_FH(glb,struct FileHandle *,struct XpkFib *);
LONG Xpk_Read(glb,struct XpkFH *,UBYTE *buf,LONG);
LONG Xpk_Write(glb,struct XpkFH *,UBYTE *buf,LONG);
LONG Xpk_Seek(glb,struct XpkFH *,LONG pos,LONG offset );
BOOL Xpk_Close(glb,struct XpkFH *);
struct XpkLock *XpkMakeLock(glb,struct FileLock *,LONG);
struct XpkLock *XpkDupLock(glb,struct XpkLock *);
struct CFSLock *XpkParentDir(glb,struct XpkLock *);
struct CFSLock *XpkParentFH(glb,struct XpkFH *);
BOOL XpkUnLock(glb,struct XpkLock *);
BOOL XpkSameLock(glb,struct XpkLock *,struct XpkLock *);
BOOL XpkObjExamine(glb,struct XpkLock *,struct FileInfoBlock *);
BOOL XpkObjExamineFH(glb,struct XpkFH *,struct FileInfoBlock *);
BOOL XpkModifyFIB(glb,struct XpkLock *,struct FileInfoBlock *,struct FileHandle *);
BOOL XpkFastModifyFIB(struct FileInfoBlock *);
BOOL InitXpk(glb);
void CleanupXpk(glb);
void xScan(glb,struct FileLock *,char *);

/* packfunc.c */
BOOL ModifyFIB_type(glb,LONG,struct CFSLock *,struct FileInfoBlock *,struct FileHandle *);


/* options.c */
BOOL set_option(glb,char *);
BOOL InitOptions(glb);
void CleanupOptions(glb);
BOOL SetOptionPermanent(glb,char *,char *);
BOOL SetOptionsFromFile(glb,struct FileLock *,char *);


/* arexx.c */
void checkarexxmsg(glb);
ULONG arexxsigmask(glb);
BOOL InitArexx(glb);
void CleanupArexx(glb);


/* gui.c */
BOOL UpdateXFHNode(glb);
ULONG guisigmask(glb);


/* End of CFS.h */
