/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1987 The Software Distillery.  All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of   */
/* | .  | || the authors:                                          BBS:      */
/* | o  | ||   John Toebes     Dave Baker     John Mainwaring                */
/* |  . |//                                                                  */
/* ======                                                                    */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <exec/libraries.h>
#include <exec/devices.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <devices/console.h>
#include <devices/timer.h>
#include <devices/trackdisk.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/filehandler.h>
#include <string.h>
#include <stdlib.h>
#ifdef MANX
#define U_ARGS(a) ()    /* No support for prototypes - oh well */
#else
#define U_ARGS(a) a     /* prototype checking to ensure all is well */
#include <proto/exec.h>
#include <proto/dos.h>
#endif

/* Unfortunately the 4.1 memcmp doesn't seem to work correctly so just */
/* tell the compiler not to use the builtin function                   */
#ifdef memcmp
#undef memcmp
int memcmp(char *, char *, int);
#endif

#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif

#undef GLOBAL
/* my version of BADDR() has no problems with casting */
#undef  BADDR
#define BADDR(x)        ((APTR)((long)x << 2))
#define MKBADDR(x)      ((BPTR)((long)x >> 2))

#define ACTION_FIND_WRITE       1004L
#define ACTION_FIND_INPUT       1005L /* please refer to DOS Tech. Ref. */
#define ACTION_FIND_OUTPUT      1006L
#define ACTION_END              1007L
#define ACTION_SEEK             1008L
#ifndef ACTION_MORE_CACHE
#define ACTION_MORE_CACHE       18L
#endif
#ifndef ACTION_FLUSH
#define ACTION_FLUSH            27L
#endif
#define ACTION_SET_FILE_DATE    34L
#define ACTION_SET_RAW_MODE     994L

#define DOS_FALSE        0L
#define DOS_TRUE        -1L           /* BCPL "TRUE" */

typedef long KEY;
typedef int (*fptr)();

/* handler support routines */

#define BUFSIZE  488
#define BLOCKSIZE 488

/* We define this because the AmigaDos one is so deficient in types         */
struct EFileHandle {
   struct EFileHandle *efh_Next; /* Next efh in system.                  */
   long efh_CurPos;              /* Current position in block               */
   KEY efh_CurKey;               /* Key of current block                    */
   long efh_CurBlock;            /* Sequence number of current block        */
   struct FileLock *efh_Lock;    /* Lock of file to be accessed             */
   long efh_CurExtBlock;         /* Current extension block number          */
   KEY  efh_ExtBlockKey;         /* Key of current extension block          */
   long efh_Protect;             /* Current protection attributes           */
   };

typedef struct EFileHandle *EFH;

/* We define this because the AmigaDos one is so deficient in types         */
struct XFileHandle {
   struct Message *fh_Link;      /* Not used - for user to link on his list */
   struct MsgPort *fh_Port;      /* Reply port for packet                   */
   struct MsgPort *fh_Type;      /* Process ID of handler process           */
   char *fh_Buf;                 /* Buffer for file I/O                     */
   char *fh_Pos;                 /* Current position in buffer              */
   char *fh_End;                 /* Pointer to end of buffer                */
   fptr fh_Funcs;                /* Function to call to fill buffer         */
   fptr fh_Func2;                /* Function to call to empty buffer        */
   fptr fh_Func3;                /* Function to call when file is closed    */
   EFH fh_Args;  /* For Internal Use - Root of file         */
   LONG fh_Arg2;                 /* For Internal Use - Block of Current pos */
   };

#define FileHandle XFileHandle

#define BLOCKSPERENTRY 72
#define HASHTABLESIZE 72
#define COMMENTSIZE   23
#define NAMESIZE      16*4
#define VOLNAMESIZE   13*4
#define BITMAPSIZE    26

struct DirBlock
   {
   long  db_Type;
   long  db_OwnKey;
   long  db_HighSeq;             /* Highest Sequence number */
   long  db_HashTableSize;
   long  db_FirstData;
   long  db_CheckSum;
   long  db_HashTable[HASHTABLESIZE];
   long  db_Spare1;               /* Start of bitmap pages on root */
   long  db_Spare2;
   long  db_Protect;             /* Protection bits */
   long  db_Size;
   long  db_Comment[COMMENTSIZE];
   long  db_Days;
   long  db_Minutes;
   long  db_Ticks;
   char  db_Name[NAMESIZE];
   long  db_HashChain;
   long  db_Parent;
   long  db_Extension;
   long  db_SecondaryType;
   };

struct FileBlock
   {
   long  fb_Type;
   long  fb_OwnKey;
   long  fb_HighSeq;
   long  fb_DataBlockCount;
   long  fb_FirstData;
   long  fb_CheckSum;
   long  fb_DataBlock[BLOCKSPERENTRY];
   long  fb_Spare1;
   long  fb_Spare2;
   long  fb_Protect;
   long  fb_Size;
   long  fb_Comment[COMMENTSIZE];
   long  fb_Days;
   long  fb_Minutes;
   long  fb_Ticks;
   char  fb_Name[NAMESIZE];
   long  fb_HashChain;
   long  fb_Parent;
   long  fb_Extension;
   long  fb_SecondaryType;
   };

struct RootBlock
   {
   long  rb_Type;
   long  rb_OwnKey;              /* Always Zero */
   long  rb_HighSeq;             /* Highest Sequence number */
   long  rb_HashTableSize;
   long  rb_fill1;
   long  rb_CheckSum;
   long  rb_HashTable[HASHTABLESIZE];
   long  rb_BitMapFlag;
   long  rb_BitMapPages[BITMAPSIZE];
   long  rb_AltDays;
   long  rb_AltMinutes;
   long  rb_AltTicks;
   char  rb_Name[VOLNAMESIZE];
   long  rb_CreateDays;
   long  rb_CreateMinutes;
   long  rb_CreateTicks;
   long  rb_HashChain;
   long  rb_Parent;
   long  rb_Extension;
   long  rb_SecondaryType;
   };

struct DataBlock
   {
   long  db_Type;
   long  db_Header;
   long  db_SeqNum;
   long  db_DataSize;
   long  db_NextData;
   long  db_CheckSum;
   long  db_Data[122];
   };

/* Primary types that appear as first longword in a block */
#define T_SHORT       2    /* Primary type - Root, UserDir, FileHeader blocks */
#define T_LONG        4    /* Unused - indicates long files */
#define T_DATA        8    /* Primary type for Data blocks */
#define T_LIST       16    /* Primary type for file list blocks */
#define T_DELETED     1    /* Bit to indicate a deleted block */

/* Secondary types that appear as the last longword in a block */
#define ST_ROOT       1    /* Secondary type for root block */
#define ST_USERDIR    2    /* Secondary type for a user directory */
#define ST_FILE      -3    /* Secondary type for a file */
#define ST_BITMAP    99    /* Bitmap type for checksum */

#define OLDFILE      8
#define NEWFILE      16

#ifdef DEBUG
/* Debugging routines */
void myputbstr U_ARGS((char *,));
void myputlstr U_ARGS((char *,));
void myprintf U_ARGS((char *,));
void xwrite U_ARGS((char *, int));
int sprintf U_ARGS((char *, char *,));
#define BUG(a) myprintf a;
#define BUGBSTR(a,b) myputbstr(a,b);
#define BUGLSTR(a,b,c) myputlstr(a,b,c);
#else
#define BUG(a)
#define BUGBSTR(a,b)
#define BUGLSTR(a,b,c)
#endif

extern struct DosLibrary *DOSBase;
#define alloc(a,b) DosAllocMem(a,b)
#define free(p) DosFreeMem(p)

typedef struct TimerPacket {
   struct timerequest tm_req;
   struct DosPacket   tm_pkt;
};

typedef struct DskChngPacket {
   struct IOExtTD     dc_req;
   struct Interrupt   dc_int;
}; 

typedef struct DiskEnvironment {
   ULONG  de_sizeblock;
   ULONG  de_blkspertrk;
   ULONG  de_reservedblks;
   ULONG  de_numblks;
   ULONG  de_lowcyl;
   ULONG  de_uppercyl;
   ULONG  de_numbufs;
   ULONG  de_membuftype;
};

typedef struct BlockBuffer{
   char   *bb_blk;     /* ptr to data buffer associated  */ 
   UBYTE  bb_used;     /* used flag                      */
   UBYTE  bb_priority; /* blk priority                   */
   UBYTE  bb_dirty;    /* dirty minded blk               */          
   ULONG  bb_key;      /* key associated with this block */
};

typedef struct Bitmap {
   SHORT bm_blocks;                  /* number of disk blocks required      */
   SHORT bm_dirty;                   /* bitmap modification flag            */
   ULONG *bm_bitmap;                 /* pointer to bitmap in memory         */
};

typedef struct global
   {
   struct DosPacket     *pkt;        /* the packet we are processing        */
   struct TimerPacket   *timerpkt;   /* pkt used for timer request          */
   struct timerequest   *systimepkt; /* pkt for getting the current time    */
   struct DskChngPacket *dskchngpkt; /* pkt used for diskchange             */
   struct DeviceNode    *node;       /* our device node                     */
   struct DeviceList    *volume;     /* currently mounted volume            */
   struct Process       *self;       /* my process                          */
   struct MsgPort       *port;       /* our message port                    */
   struct DiskEnvironment dskenv;    /* stuff need for the device           */
   struct BlockBuffer   *blkbuf;     /* ptr to allocated blks for buffers   */
   struct Bitmap        bitmap;      /* ptr to bitmap data                  */
   struct IOExtTD       *devreq;     /* device io request pointer           */
   struct MsgPort       *devport;    /* msg port for device io              */
   EFH    AllHandles;                /* Chain of all known file handles     */
   char   *devname;                  /* pointer to device name              */
   long   ErrorCount;                /* Error count for current volume      */
   long   DiskChange;                /* Current disk change number          */
   long   Root;                      /* Root block on current volume        */
   KEY    prevkey;                   /* Previous key in a search            */
   int    run;                       /* flag to continue running            */
   int    reply;                     /* flag to inhibit replying to message */
   long   diskstatus;                /* Status of disk in the drive         */
   long   diskstate;                 /* Status of disk in the drive         */
   long   unitnum;                   /* Unit number of drive                */
   long   changedisk;                /* Flag to indicate a disk change      */
   UBYTE  deviotimeout;              /* device io timeout for r/w           */  
   /* These are the fields of the autorequest structure we want to create   */
   struct IntuiText line1;           /* Top Line of requester               */
   struct IntuiText line2;           /* Second Line of requester            */
   struct IntuiText line3;           /* Bottom Line of requester            */
   struct IntuiText retrytxt;        /* Retry information                   */
   struct IntuiText canceltxt;       /* CANCEL information                  */
   char   buf3[16];                  /* Buffer to hold unit information     */
   }* GLOBAL;

/* Routines in buff.c called directly from io.c */
int initbuf  U_ARGS((GLOBAL, int, int));
void termbuf U_ARGS((GLOBAL, EFH));

/* Bitmap.c */
int  AllocBitMap   U_ARGS((GLOBAL));
int  FreeBitMap    U_ARGS((GLOBAL));
int  CountBlocks   U_ARGS((GLOBAL));
void DoCheckSum    U_ARGS((GLOBAL,char *));
void WriteBitMap   U_ARGS((GLOBAL));
void SetBlock      U_ARGS((GLOBAL,KEY));
void FreeBlock     U_ARGS((GLOBAL, KEY));
KEY  AllocateBlock U_ARGS((GLOBAL, KEY, int /* type */));

/* file.c */
void ActDelete        U_ARGS((GLOBAL, struct DosPacket *));
void ActRename        U_ARGS((GLOBAL, struct DosPacket *));
void ActSetComment    U_ARGS((GLOBAL, struct DosPacket *));
void ActSetProtection U_ARGS((GLOBAL, struct DosPacket *));

/* io.c */
void ActFindwrite U_ARGS((GLOBAL, struct DosPacket *));
void ActFindin    U_ARGS((GLOBAL, struct DosPacket *));
void ActFindout   U_ARGS((GLOBAL, struct DosPacket *));
void ActEnd       U_ARGS((GLOBAL, struct DosPacket *));
void ActRead      U_ARGS((GLOBAL, struct DosPacket *));
void ActWrite     U_ARGS((GLOBAL, struct DosPacket *));
void ActSeek      U_ARGS((GLOBAL, struct DosPacket *));
int  unsafe       U_ARGS((GLOBAL, EFH, int));

/* dir.c */
void ActCreateDir U_ARGS((GLOBAL, struct DosPacket *));
void ActExamine   U_ARGS((GLOBAL, struct DosPacket *));
void ActExNext    U_ARGS((GLOBAL, struct DosPacket *));
void ActParent    U_ARGS((GLOBAL, struct DosPacket *));

/* databuff.c */
char *GetBlock     U_ARGS((GLOBAL, KEY));
char *ModBlock     U_ARGS((GLOBAL, KEY));
int  FindBuffer    U_ARGS((GLOBAL,KEY, long));
int  AllocBlkBuffs U_ARGS((GLOBAL, long));
void FreeBlkBuffs  U_ARGS((GLOBAL));
void FlushOne      U_ARGS((GLOBAL,long));
void FlushBuffers  U_ARGS((GLOBAL,KEY));

/* Subs.c */
struct DosPacket   *taskwait     U_ARGS((GLOBAL));
void initdebug    U_ARGS((void));
void retpkt       U_ARGS((GLOBAL, struct DosPacket *));
char *DosAllocMem U_ARGS((GLOBAL, long));
void DosFreeMem   U_ARGS((char *));

/* Disk.c */
int  AddDskChngInt U_ARGS((GLOBAL));
void RemDskChngInt U_ARGS((GLOBAL));
int  Motor      U_ARGS((GLOBAL, int));
int  ResetDrive U_ARGS((GLOBAL));
int  ReadPhy    U_ARGS((GLOBAL, char *, KEY));
int  WritePhy   U_ARGS((GLOBAL, char *, KEY));
void demanddisk U_ARGS((GLOBAL));

/* mount.c */
void DisMount U_ARGS((GLOBAL));
void Mount    U_ARGS((GLOBAL));

/* lock.c */
long GetKey     U_ARGS((struct global *,struct FileLock *));
struct FileLock *CreateLock U_ARGS((GLOBAL, KEY, long));
void freelock   U_ARGS((GLOBAL, struct FileLock *));
void ActLock    U_ARGS((GLOBAL, struct DosPacket *));
void ActDupLock U_ARGS((GLOBAL, struct DosPacket *));
void ActUnLock  U_ARGS((GLOBAL, struct DosPacket *));

/* Process.c */
void ActDie     U_ARGS((GLOBAL, struct DosPacket *));
void ActInhibit U_ARGS((GLOBAL, struct DosPacket *));
void ActFlush   U_ARGS((GLOBAL, struct DosPacket *));
void ActTimer   U_ARGS((GLOBAL, struct DosPacket *));

/* volume.c */
void ActCurentVol  U_ARGS((GLOBAL, struct DosPacket *));
void ActRenameDisk U_ARGS((GLOBAL, struct DosPacket *));
void ActDiskInfo   U_ARGS((GLOBAL, struct DosPacket *));
void ActInfo       U_ARGS((GLOBAL, struct DosPacket *));
void GetVolInfo    U_ARGS((GLOBAL, struct InfoData *));

/* device.c */
int GetDevice  U_ARGS((GLOBAL, struct FileSysStartupMsg *));
int InitDevice U_ARGS((GLOBAL));
int TermDevice U_ARGS((GLOBAL));

/* inhibit.c */
int inhibit  U_ARGS((struct MsgPort *, long));
long sendpkt U_ARGS((struct MsgPort *, long, long*, long));

/* timer.c */
int  OpenTimer     U_ARGS((GLOBAL));
void PostTimerReq  U_ARGS((GLOBAL));
void GetDateStamp  U_ARGS((GLOBAL, struct DateStamp *));
void MakeDateStamp U_ARGS((struct timeval *, struct DateStamp *));

/* dos1_2.c */
int  IsSameName      U_ARGS((char *, char *, int));
KEY  NextKey         U_ARGS((GLOBAL, KEY, struct FileInfoBlock *, KEY));
KEY  ParentKey       U_ARGS((GLOBAL, KEY));
int  hash            U_ARGS((char *, int));
int  parse           U_ARGS((char **, int *, char *));
long GetProtect      U_ARGS((GLOBAL, KEY));
int  SetProtect      U_ARGS((GLOBAL, KEY, long /*Protection*/));
int  GetType         U_ARGS((GLOBAL, KEY));
int  SetCommentStr   U_ARGS((GLOBAL, KEY, char *));
int  GetInfo         U_ARGS((GLOBAL, KEY, struct FileInfoBlock *));
KEY  FindDir         U_ARGS((GLOBAL, KEY, char **, int *));
KEY  FindEntry       U_ARGS((GLOBAL, KEY, char *, int));
KEY  MakeEntry       U_ARGS((GLOBAL, KEY, char *, int, int));
KEY  LocateEntry     U_ARGS((GLOBAL, KEY, char * /* Name */));
KEY  CreateEntry     U_ARGS((GLOBAL, KEY, char * /* Name */, 
                                     int /* Mode */, int /* Type */));
int  FreeDataChain   U_ARGS((GLOBAL, KEY));
KEY  SeekDataChain   U_ARGS((GLOBAL, EFH, long));
KEY  AppendDataChain U_ARGS((GLOBAL, EFH, long));
long GetFileSize     U_ARGS((GLOBAL, EFH));
int  UpdateFile      U_ARGS((GLOBAL, EFH, long, long));
void GETDATA         U_ARGS((char *, long, char *, long));
void PUTDATA         U_ARGS((char *, long, char *, long));
KEY  BlockKey        U_ARGS((GLOBAL, EFH, long, int));
void SetDateInfo     U_ARGS((GLOBAL, struct DirBlock *));
KEY  GetParent       U_ARGS((GLOBAL, KEY));
int  GetExtInfo      U_ARGS((GLOBAL, KEY, struct ExtInfoBlock *));
int  SetExtInfo      U_ARGS((GLOBAL, KEY, struct ExtInfoBlock *));
int  FreeDirEntry    U_ARGS((GLOBAL, KEY));
int  RenameDisk      U_ARGS((GLOBAL, char *));
int  DeleteEntry     U_ARGS((GLOBAL, KEY, char *));
int  RenameEntry     U_ARGS((GLOBAL, KEY, KEY, char *, char *));
KEY  LinkDir         U_ARGS((GLOBAL, KEY, KEY, int));
/* Directory/File level maintainence */
KEY  MakeEntry       U_ARGS((GLOBAL,KEY, char *, int, int));
KEY  NextDataBlock   U_ARGS((GLOBAL, KEY));

/* Requester routine */
int  request         U_ARGS((GLOBAL, int, char *));
#define REQ_MUST    0
#define REQ_ERROR   1
#define REQ_GENERAL 2
