home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
disks
/
misc
/
device-handler
/
source
/
device-handler.c
< prev
next >
Wrap
C/C++ Source or Header
|
1981-06-29
|
28KB
|
966 lines
/*
** $VER: device-handler.c 1.6 (03 Jun 1995)
**
** device-handler - raw device access
**
** (C) Copyright 1995 Marius Gröger
** All Rights Reserved.
*/
/*F*/ /* history */
/* $HISTORY:
**
** 03 Jun 1995 : 001.006 : + locyl was broken
** + dot conversion starts after first slash
** + source code ANSIfied
** + added some macros for compiler abstraction
** + didn't remove task correctly
** 24 Apr 1995 : 001.005 : at the end of a media Write()/Read() returned wrong res1,
** so multi-volume tar archives shouldn't be a problem any
** longer
** 22 Feb 1995 : 001.004 : some bug-fixing
** 18 Feb 1995 : 001.003 : made Write() working...
** 20 Dec 1994 : 001.002 : + one task/multiple FileHandles
** + source-code rework
** + better stream name scanning by ReadArgs()
** + new option MAXLENGTH
** + new options LOCYL, HICYL
** + highly improved read/write operation
** 18 Dec 1994 : 001.001 : changed stream name convention
** 08 Dec 1994 : 001.000 : took over from Matthias Scheler
*/
/*E*/
/*F*/ /* includes */
/* system protoypes and pragmas */
/* ensure to use the symbol SysBase and not the hardcoded AbsExecBase */
#define __USE_SYSBASE
#include <clib/exec_protos.h>
#include <pragmas/exec_pragmas.h>
#include <clib/dos_protos.h>
#include <pragmas/dos_pragmas.h>
#include <clib/utility_protos.h>
#include <pragmas/utility_pragmas.h>
/* system header files */
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <devices/trackdisk.h>
#include <dos/dosextens.h>
#include <dos/filehandler.h>
#include <dos/dos.h>
/* compiler header files */
#include <string.h>
/* fix include files (anyawy I'm not yet using them:
** what about sending me a diff-file ?)
*/
#ifndef ACTION_GET_DISK_FSSM
#define ACTION_GET_DISK_FSSM 4201
#endif
#ifndef ACTION_FREE_DISK_FSSM
#define ACTION_FREE_DISK_FSSM 4202
#endif
#include "device-handler_rev.h"
/*E*/
/*F*/ /* debug */
extern void KPrintF(char *, ...);
/*#define d(x) do { KPrintF("%s:%ld: ", __FUNC__, __LINE__); KPrintF x; } while(0)*/
#define d(x)
/*E*/
/*F*/ /* compiler abstraction */
#ifdef __SASC
# define ASM __asm
# define REG(x) register __ ## x
# define INLINE __inline
# define REGARGS __regargs
# define SAVEDS __saveds
# define FAR __far
# define MIN __builtin_min
# define MAX __builtin_max
#else
# error Please define the above macros for your compiler
#endif
/*E*/
/*F*/ /* global static storage */
typedef struct GlobalData
{
struct Library *gd_SysBase;
struct Library *gd_DOSBase;
struct Library *gd_UtilityBase;
struct MsgPort *gd_Port;
struct DosList *gd_DosList;
struct Process *gd_We;
} *GD;
#ifdef __SASC
/* redirect all shared library bases to our device base */
# define SysBase gd->gd_SysBase
# define DOSBase gd->gd_DOSBase
# define UtilityBase gd->gd_UtilityBase
/* This macro declares a local variable which temporary gets
SysBase directly from AbsExecBase. */
# define LOCALSYSBASE struct { VOID *gd_SysBase; } *gd = (VOID*)0x4
#else
# error Please define library bases for your compiler
#endif
/*E*/
/*F*/ /* handler declarations */
#define STREAMNAME_TEMPLATE "DOSNAME/A,MAXLENGTH,LOCYL/K,HICYL/K"
struct StreamOpts
{
UBYTE *so_DOSName;
UBYTE *so_MaxLength;
UBYTE *so_LoCyl;
UBYTE *so_HiCyl;
};
#define BCPL_MAXNAME 256
struct PrivateStreamData
{
struct IOStdReq *psd_IO; /* Exec I/O Block */
UBYTE psd_DOSName[BCPL_MAXNAME]; /* Name of AmigaDOS handler */
UBYTE psd_Device[32]; /* OpenDevice()-name */
ULONG psd_Unit; /* OpenDevice()-unit */
ULONG psd_Flags; /* OpenDevice()-flags */
ULONG psd_BufMemType; /* memory type needed */
LONG psd_LoCyl, psd_HiCyl; /* cylinder boundaries */
LONG psd_SectorSize; /* length of a sector */
LONG psd_Offset; /* starting sector */
LONG psd_MaxLength; /* max-length of "file" */
LONG psd_Pos; /* current pos. in "file" */
LONG psd_Len; /* actual length of "file" */
UBYTE *psd_Buffer; /* r/w buffer */
LONG psd_Left; /* bytes left in r/w buffer */
UBYTE *psd_Ptr; /* current pos in buffer */
BOOL psd_Write; /* file is in write mode */
struct StreamOpts psd_Param; /* ReadArgs() argument */
};
/*E*/
/*F*/ /* prototypes */
STATIC struct DosPacket *WaitDosPacket(GD gd, struct MsgPort *port);
STATIC VOID ReplyDosPacket(GD gd, struct MsgPort *port, struct DosPacket *Packet,LONG Res1,LONG Res2);
STATIC BOOL GetXDULONG(GD gd, UBYTE *s, LONG *number);
STATIC VOID Stream2RDArgs(UBYTE *buffer);
STATIC BOOL StreamSpecs(GD gd, struct PrivateStreamData *psd, BPTR streamname, LONG *res);
STATIC BOOL FindDevice(GD gd, struct PrivateStreamData *psd);
STATIC VOID OpenDH(GD gd, struct DosPacket *Pkt,ULONG *OpenCnt);
STATIC VOID CloseDH(GD gd, struct PrivateStreamData *psd,ULONG *OpenCnt);
STATIC LONG REGARGS RawRead(GD gd, struct PrivateStreamData *psd, UBYTE *Buffer, LONG Bytes, LONG *res2);
STATIC LONG REGARGS RawWrite(GD gd, struct PrivateStreamData *psd,UBYTE *Buffer,LONG Bytes, LONG *res2);
STATIC GD creategd(VOID);
STATIC BOOL openres(GD gd);
STATIC VOID closeres(GD gd);
GLOBAL LONG main(VOID);
/*E*/
/*F*/ GLOBAL LONG SAVEDS main(VOID)
/*
** don't remove GLOBAL, if you don't want to the complete
** source to get optimized out of existence :-)
*/
{
GD gd;
struct DosPacket *Pkt;
BOOL Done;
ULONG OpenCnt;
LONG rc = RETURN_OK;
d(("this is the DEV handler, compiled on "__DATE__"\n"));
if (gd = creategd())
{
if ((gd->gd_We = (struct Process *)FindTask(NULL))->pr_CLI) return RETURN_FAIL;
d(("waiting for startup-packet...\n"));
Pkt = WaitDosPacket(gd, &gd->gd_We->pr_MsgPort);
if (openres(gd))
{
gd->gd_DosList = (struct DosList *)BADDR(Pkt->dp_Arg3);
gd->gd_DosList->dol_Task = gd->gd_Port;
d(("replying startup-packet...\n"));
ReplyDosPacket(gd, gd->gd_Port, Pkt, DOSTRUE, Pkt->dp_Res2);
Done=FALSE;
OpenCnt=0L;
d(("entering mainloop\n"));
while (!Done)
{
Pkt=WaitDosPacket(gd, gd->gd_Port);
d(("got packet %ld\n",Pkt->dp_Type));
Pkt->dp_Res1 = DOSFALSE;
Pkt->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
switch (Pkt->dp_Type)
{
case ACTION_FINDINPUT:
case ACTION_FINDOUTPUT:
OpenDH (gd, Pkt, &OpenCnt);
ReplyDosPacket(gd, gd->gd_Port,Pkt, Pkt->dp_Res1, Pkt->dp_Res2);
break;
case ACTION_READ:
{
struct PrivateStreamData *psd = (struct PrivateStreamData *)Pkt->dp_Arg1;
if (psd && !psd->psd_Write)
{
LONG Bytes, error;
Bytes = RawRead(gd, (struct PrivateStreamData *)Pkt->dp_Arg1,
(UBYTE *)Pkt->dp_Arg2,Pkt->dp_Arg3, &error);
ReplyDosPacket(gd, gd->gd_Port,Pkt, Bytes, error);
}
}
break;
case ACTION_WRITE:
{
struct PrivateStreamData *psd = (struct PrivateStreamData *)Pkt->dp_Arg1;
if (psd && psd->psd_Write)
{
LONG Bytes, error;
Bytes = RawWrite(gd, (struct PrivateStreamData *)Pkt->dp_Arg1,
(UBYTE *)Pkt->dp_Arg2, Pkt->dp_Arg3, &error);
ReplyDosPacket(gd, gd->gd_Port,Pkt, Bytes, error);
}
}
break;
case ACTION_IS_FILESYSTEM:
ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE, 0);
break;
case ACTION_SEEK:
case ACTION_SET_FILE_SIZE:
ReplyDosPacket(gd, gd->gd_Port,Pkt, -1,ERROR_ACTION_NOT_KNOWN);
break;
case ACTION_END:
CloseDH (gd, (struct PrivateStreamData *)Pkt->dp_Arg1,&OpenCnt);
ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSTRUE, 0);
/* FALLTHROUGH */
case ACTION_DIE:
if (OpenCnt==0L)
{
d(("opencnt = 0\n"));
if (IsListEmpty(&gd->gd_Port->mp_MsgList))
{
gd->gd_DosList->dol_Task = NULL;
if (Pkt->dp_Type == ACTION_DIE)
ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSTRUE, 0);
Done=TRUE;
}
else
{
if (Pkt->dp_Type == ACTION_DIE)
ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE,ERROR_OBJECT_IN_USE);
}
}
else
{
if (Pkt->dp_Type == ACTION_DIE)
ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE,ERROR_OBJECT_IN_USE);
}
break;
default:
ReplyDosPacket(gd, gd->gd_Port, Pkt, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
break;
}
}
}
else
{
ReplyDosPacket(gd, &gd->gd_We->pr_MsgPort, Pkt, DOSFALSE, ERROR_NO_FREE_STORE);
rc = RETURN_FAIL;
}
closeres(gd);
d(("returning\n"));
}
else rc = RETURN_FAIL;
return rc;
}
const STATIC UBYTE version[]=VERSTAG;
/*E*/
/*F*/ STATIC struct DosPacket *WaitDosPacket(GD gd, struct MsgPort *port)
{
WaitPort(port);
return (struct DosPacket *)(GetMsg(port)->mn_Node.ln_Name);
}
/*E*/
/*F*/ STATIC VOID ReplyDosPacket(GD gd, struct MsgPort *port, struct DosPacket *Packet,LONG Res1,LONG Res2)
{
struct MsgPort *reply = Packet->dp_Port;
Packet->dp_Port = port;
Packet->dp_Link->mn_Node.ln_Name = (char *)Packet;
Packet->dp_Res1 = Res1;
Packet->dp_Res2 = Res2;
PutMsg (reply, Packet->dp_Link);
}
/*E*/
/*F*/ STATIC BOOL GetXDULONG(GD gd, UBYTE *s, LONG *number)
{
#define IsDigit(c) ((c) >= '0' && (c) <= '9'))
#define IsXDigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F'))
BOOL hex, rc = TRUE;
ULONG num;
UBYTE c;
WORD len;
if (len = strlen(s))
{
if (!Strnicmp(s, "0x", 2))
{
hex = TRUE;
s += 2;
}
else if (!Strnicmp(s, "$", 2))
{
hex = TRUE;
s++;
}
else hex = FALSE;
for(num=0;*s;s++)
{
c = ToUpper((ULONG)*s);
if (hex)
{
if (c >= '0' && c <= '9') num = num * 16 + c - '0';
else if (c >= 'A' && c <= 'F') num = num * 16 + c - '0';
else break;
}
else
{
if (c >= '0' && c <= '9') num = num * 10 + c - '0';
else break;
}
}
if (*s)
{
if (c == 'K') num *= 1024;
else if (c == 'M') num *= 1024*1024;
else rc = FALSE;
}
}
else rc = FALSE;
if (rc) *number = num;
return rc;
}
/*E*/
/*F*/ STATIC VOID Stream2RDArgs(UBYTE *buffer)
{
UBYTE *p;
enum { s_start, s_conv, s_esc, s_quote } s, sb;
for (p = buffer, sb = s = s_start; *p; p++)
switch(s)
{
case s_start: /* no convertion 'til 1st slash */
if (*p == '"')
{
s = s_quote;
break;
}
else if (*p != '/')
break;
sb = s = s_conv;
/* FALLTHROUGH */
case s_conv: /* conversion state */
if (*p == '.') *p = '=';
else if (*p == '/') *p = '\040';
else if (*p == '"') s = s_quote;
break;
case s_esc: /* (asterisk-)escape state */
s = s_quote;
break;
case s_quote: /* quotation state */
if (*p == '*') s = s_esc;
if (*p == '"') s = sb;
break;
}
}
/*E*/
/*F*/ STATIC BOOL StreamSpecs(GD gd, struct PrivateStreamData *psd, BPTR streamname, LONG *res)
{
UBYTE *temp, *bstr, *start;
BOOL rc = FALSE;
struct RDArgs *inrda, *rda;
memset(&psd->psd_Param, '\0', (int)sizeof(psd->psd_Param));
bstr = (UBYTE *)BADDR(streamname);
if (temp = AllocVec((ULONG)bstr[0]+2, MEMF_ANY))
{
if (inrda = AllocDosObject(DOS_RDARGS, NULL))
{
strncpy(temp, bstr+1, bstr[0]);
temp[bstr[0]] = '\n';
temp[bstr[0]+1] = '\0';
if (start = (UBYTE*)strchr((char*)temp, ':'))
{
Stream2RDArgs(++start);
inrda->RDA_Source.CS_Buffer = start;
inrda->RDA_Source.CS_Length = strlen(start);
inrda->RDA_Source.CS_CurChr = 0;
psd->psd_MaxLength = 0x7fffffff;
psd->psd_LoCyl = 0;
psd->psd_HiCyl = 0x7fffffff;
d(("readargs(%s)\n",start));
if (rda = ReadArgs((UBYTE*)STREAMNAME_TEMPLATE, (LONG*)&psd->psd_Param, inrda))
{
rc = TRUE;
strcpy(psd->psd_DOSName, (char*)psd->psd_Param.so_DOSName);
if (psd->psd_Param.so_MaxLength)
rc = GetXDULONG(gd,psd->psd_Param.so_MaxLength, &psd->psd_MaxLength);
if (rc && psd->psd_Param.so_LoCyl)
rc = GetXDULONG(gd,psd->psd_Param.so_LoCyl, &psd->psd_LoCyl);
if (rc && psd->psd_Param.so_HiCyl)
rc = GetXDULONG(gd,psd->psd_Param.so_HiCyl, &psd->psd_HiCyl);
d(("after ReadArgs(): doshandler %s maxlen %lu locyl %lu hicyl %lu\n",
psd->psd_DOSName,psd->psd_MaxLength,psd->psd_LoCyl,psd->psd_HiCyl));
FreeArgs(rda);
}
else
{
d(("ReadArgs() failed\n"));
*res = ERROR_BAD_STREAM_NAME;
}
}
else
{
d(("no proper name\n"));
*res = ERROR_BAD_STREAM_NAME;
}
FreeDosObject(DOS_RDARGS, inrda);
}
else
{
d(("no RDArgs\n"));
*res = ERROR_NO_FREE_STORE;
}
FreeVec(temp);
}
else
{
d(("no more memory\n"));
*res = ERROR_NO_FREE_STORE;
}
return rc;
}
/*E*/
/*F*/ STATIC BOOL FindDevice(GD gd, struct PrivateStreamData *psd)
{
struct DosList *dol;
struct FileSysStartupMsg *fssm;
BOOL rc = FALSE;
UBYTE *name;
UBYTE n;
UBYTE pat[40];
d(("entered: %s\n", psd->psd_DOSName));
n = strlen(psd->psd_DOSName);
if (dol = LockDosList(LDF_READ | LDF_DEVICES))
{
while(dol = NextDosEntry(dol, LDF_DEVICES))
{
name = (UBYTE*)BADDR(dol->dol_Name);
memset(pat,0,40);
strncpy(pat,name+1,name[0]);
d(("%s\n",pat));
if ((n == name[0]) && !Strnicmp((char*)(name+1), psd->psd_DOSName, (LONG)n))
{
d(("found\n"));
fssm = (struct FileSysStartupMsg*)BADDR(dol->dol_misc.dol_handler.dol_Startup);
if (fssm)
{
struct DosEnvec *de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
d(("found fssm\n"));
/* note: fssm->fssm_Device is a NUL-terminated BSTR!! :-) */
strcpy((char*)psd->psd_Device, (char*)BADDR(fssm->fssm_Device)+1);
psd->psd_Flags = fssm->fssm_Flags;
psd->psd_Unit = fssm->fssm_Unit;
psd->psd_BufMemType = de->de_BufMemType;
psd->psd_SectorSize = 4 * de->de_SizeBlock;
if (!psd->psd_Param.so_HiCyl) psd->psd_HiCyl = de->de_HighCyl;
if (!psd->psd_Param.so_LoCyl) psd->psd_LoCyl = de->de_LowCyl;
psd->psd_LoCyl = (LONG)MIN((int)psd->psd_LoCyl, (int)psd->psd_HiCyl);
d(("de->de_BlocksPerTrack %ld, psd->psd_LoCyl %ld, psd->psd_HiCyl %ld, de->de_Surfaces %ld, psd->psd_SectorSize %ld\n",
de->de_BlocksPerTrack, psd->psd_LoCyl, psd->psd_HiCyl, de->de_Surfaces, psd->psd_SectorSize));
psd->psd_Offset = de->de_BlocksPerTrack * psd->psd_LoCyl * de->de_Surfaces * psd->psd_SectorSize;
psd->psd_Len = de->de_BlocksPerTrack * psd->psd_SectorSize * (psd->psd_HiCyl - psd->psd_LoCyl + 1) * de->de_Surfaces;
psd->psd_Len = (LONG)MIN((int)psd->psd_MaxLength, (int)psd->psd_Len);
d(("len %lu\n",psd->psd_Len));
d(("device %s, unit %ld, flags %ld, secsiz %ld, off %ld\n",
psd->psd_Device,psd->psd_Unit,psd->psd_Flags,psd->psd_SectorSize,psd->psd_Offset));
rc = TRUE;
}
else
d(("no fssm\n"));
break;
}
}
UnLockDosList(LDF_READ | LDF_DEVICES);
}
return(rc);
}
/*E*/
/*F*/ STATIC VOID OpenDH(GD gd, struct DosPacket *Pkt,ULONG *OpenCnt)
{
struct FileHandle *FH;
struct PrivateStreamData *psd;
struct MsgPort *IOPort;
BOOL ok = FALSE;
Pkt->dp_Res1 = DOSFALSE;
FH = (struct FileHandle *)BADDR(Pkt->dp_Arg1);
FH->fh_Port = (struct MsgPort *)FALSE;
FH->fh_Arg1 = 0L;
d(("allocing psd\n"));
if (psd = AllocVec(sizeof(*psd),MEMF_PUBLIC|MEMF_CLEAR))
{
if (StreamSpecs(gd, psd, (BPTR)Pkt->dp_Arg3, &Pkt->dp_Res2))
{
d(("creating msgport\n"));
if (IOPort=CreateMsgPort())
{
if (psd->psd_IO=CreateIORequest(IOPort, sizeof(struct IOStdReq)))
{
if (FindDevice(gd, psd))
{
if (OpenDevice(psd->psd_Device, psd->psd_Unit, (struct IORequest *)psd->psd_IO, psd->psd_Flags)==0L)
{
if (psd->psd_Buffer = AllocVec(psd->psd_SectorSize, psd->psd_BufMemType))
{
if (Pkt->dp_Type == ACTION_FINDOUTPUT)
{
psd->psd_Write = TRUE;
}
else
{
psd->psd_Write = FALSE;
psd->psd_IO->io_Command = CMD_READ;
}
psd->psd_Ptr = psd->psd_Buffer;
psd->psd_Pos = 0;
psd->psd_Left = 0;
FH->fh_Arg1 = (LONG)psd;
Pkt->dp_Res1 = DOSTRUE;
Pkt->dp_Res2 = 0L;
(*OpenCnt)++;
ok = TRUE;
}
else Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
if (!ok) CloseDevice ((struct IORequest *)psd->psd_IO);
}
else
{
d(("could not open device >%s<\n",psd->psd_Device));
Pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
}
}
else
{
d(("no device\n"));
Pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
}
if (!ok) DeleteIORequest(psd->psd_IO);
}
else
{
d(("no iorequest\n"));
Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
}
if (!ok) DeleteMsgPort (IOPort);
}
else
{
d(("no msgport\n"));
Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
}
}
else
{
d(("no StreamSpecs()\n"));
}
if (!ok) FreeVec (psd);
}
else
{
d(("no psd\n"));
Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
}
d(("leaving OpenDH() with Res2 = %ld\n",Pkt->dp_Res2));
}
/*E*/
/*F*/ STATIC VOID CloseDH(GD gd, struct PrivateStreamData *psd,ULONG *OpenCnt)
{
d(("CloseDH()\n"));
if (psd->psd_Write)
{
if (psd->psd_Left < psd->psd_SectorSize)
{
d(("DoIO(CMD_WRITE)\n"));
memset(psd->psd_Ptr,'\0',(size_t)psd->psd_Left);
psd->psd_IO->io_Length = psd->psd_SectorSize;
psd->psd_IO->io_Data = psd->psd_Buffer;
psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Left-psd->psd_SectorSize;
psd->psd_IO->io_Command = CMD_WRITE;
DoIO((struct IORequest *)psd->psd_IO);
}
psd->psd_IO->io_Command=CMD_UPDATE;
d(("DoIO(CMD_UPDATE)\n"));
DoIO((struct IORequest *)psd->psd_IO);
}
d(("FreeVec() buffer\n"));
FreeVec(psd->psd_Buffer);
d(("stopping motor off\n"));
psd->psd_IO->io_Command = TD_MOTOR;
psd->psd_IO->io_Length = 0L;
DoIO((struct IORequest *)psd->psd_IO);
d(("closing device\n"));
CloseDevice ((struct IORequest *)psd->psd_IO);
d(("deleting msg port\n"));
DeleteMsgPort (psd->psd_IO->io_Message.mn_ReplyPort);
d(("deleting stdio\n"));
DeleteIORequest (psd->psd_IO);
d(("FreeVec() rh\n"));
FreeVec (psd);
(*OpenCnt)--;
d(("leaving closedh()\n"));
}
/*E*/
/*F*/ STATIC LONG REGARGS RawRead(GD gd, struct PrivateStreamData *psd, UBYTE *Buffer, LONG Bytes, LONG *res2)
{
LONG LatchBytes, RDBytes;
BOOL error = FALSE;
/* check bouunds */
if ((psd->psd_Pos + Bytes) > psd->psd_Len) Bytes = psd->psd_Len - psd->psd_Pos;
LatchBytes = Bytes;
d(("read %ld bytes\n",Bytes));
/*
** first, read what's left in buffer
*/
if (psd->psd_Left)
{
RDBytes = (LONG)MIN((int)psd->psd_Left, (int)Bytes);
CopyMem(psd->psd_Ptr, Buffer, RDBytes);
Buffer += RDBytes;
Bytes -= RDBytes;
psd->psd_Pos += RDBytes; /* incr. position in file */
psd->psd_Ptr += RDBytes;
psd->psd_Left -= RDBytes;
}
/*
** second, try to read as much blocks as possible directly to
** user buffer, aVOIDing CopyMem()
*/
if (!error && (Bytes > psd->psd_SectorSize))
{
RDBytes = (Bytes / psd->psd_SectorSize) * psd->psd_SectorSize;
psd->psd_IO->io_Data = Buffer;
psd->psd_IO->io_Length = RDBytes;
psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
if (DoIO((struct IORequest *)psd->psd_IO))
{
RDBytes = psd->psd_IO->io_Actual;
error = TRUE;
*res2 = psd->psd_IO->io_Error;
}
Buffer += RDBytes;
Bytes -= RDBytes;
psd->psd_Pos += RDBytes; /* incr. position in file */
psd->psd_Left = 0; /* for safety, initialise buffer */
psd->psd_Ptr = psd->psd_Buffer;
}
if (!error && Bytes)
{
/*
** now there are only some bytes < SectorSize left, so they fit into one buffer
** So, read a buffer and copy some bytes from it to user-buffer.
*/
RDBytes = Bytes;
psd->psd_IO->io_Length = psd->psd_SectorSize;
psd->psd_IO->io_Data = psd->psd_Buffer;
psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
if (DoIO((struct IORequest *)psd->psd_IO))
{
*res2 = psd->psd_IO->io_Error;
RDBytes = psd->psd_IO->io_Actual;
}
CopyMem(psd->psd_Buffer, Buffer, RDBytes);
psd->psd_Pos += RDBytes;
psd->psd_Ptr = psd->psd_Buffer + RDBytes;
psd->psd_Left = psd->psd_SectorSize - RDBytes;
Bytes -= RDBytes;
}
return LatchBytes - Bytes;
}
/*E*/
/*F*/ STATIC LONG REGARGS RawWrite(GD gd, struct PrivateStreamData *psd,UBYTE *Buffer,LONG Bytes, LONG *res2)
{
LONG LatchBytes,WRBytes;
BOOL error = FALSE;
/* check bounds */
if ((psd->psd_Pos + Bytes) > psd->psd_Len) Bytes = psd->psd_Len-psd->psd_Pos;
LatchBytes = Bytes;
d(("write %ld bytes\n",Bytes));
/*
** first, take care for outstanding data
*/
if (Bytes && psd->psd_Left)
{
WRBytes = (LONG)MIN((int)psd->psd_Left, (int)Bytes);
CopyMem(Buffer, psd->psd_Ptr, WRBytes);
psd->psd_Ptr += WRBytes; /* incr. position in buffer */
psd->psd_Left -= WRBytes; /* decr. number of unused bytes */
if (psd->psd_Left == 0) /* Buffer full ? */
{ /* then write it out */
psd->psd_IO->io_Data = psd->psd_Buffer;
psd->psd_IO->io_Length = psd->psd_SectorSize;
psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
psd->psd_IO->io_Command = CMD_WRITE;
if (DoIO((struct IORequest *)psd->psd_IO))
{
*res2 = psd->psd_IO->io_Error;
WRBytes = psd->psd_IO->io_Actual;
error = TRUE;
d(("td-error %ld\n",psd->psd_IO->io_Error));
}
psd->psd_Ptr = psd->psd_Buffer; /* reset buffer pointers */
psd->psd_Left = 0;
}
Buffer += WRBytes;
Bytes -= WRBytes;
psd->psd_Pos += WRBytes; /* incr. position in file */
}
if (!error && Bytes)
{
/*
** second, try to write as much blocks as possible directly from
** user buffer in one go, aVOIDing CopyMem() and multiple I/O-Requests
*/
if (Bytes > psd->psd_SectorSize)
{
/* I don't like to use bit masking at this point */
WRBytes = (Bytes / psd->psd_SectorSize) * psd->psd_SectorSize;
d(("chunk %ld/%lx bytes\n",WRBytes,WRBytes));
psd->psd_IO->io_Data = Buffer;
psd->psd_IO->io_Length = WRBytes;
psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
psd->psd_IO->io_Command = CMD_WRITE;
if (DoIO((struct IORequest *)psd->psd_IO))
{
*res2 = psd->psd_IO->io_Error;
WRBytes = psd->psd_IO->io_Actual;
error = TRUE;
d(("td-error %ld\n",psd->psd_IO->io_Error));
}
Buffer += WRBytes;
Bytes -= WRBytes;
psd->psd_Pos += WRBytes; /* incr. position in file */
psd->psd_Ptr = psd->psd_Buffer; /* for safety, reset buffer pointers */
psd->psd_Left = 0;
}
}
if (!error && Bytes)
{
/*
** now there are only some bytes < SectorSize left, and they fit into one
** buffer.
** NOTE: the actual writing is delayed to Close() or further Write()'s
*/
WRBytes = Bytes;
CopyMem(Buffer, psd->psd_Buffer, WRBytes);
psd->psd_Pos += WRBytes; /* incr. position in file */
Bytes -= WRBytes;
psd->psd_Ptr = psd->psd_Buffer + WRBytes; /* set position in buffer */
psd->psd_Left = psd->psd_SectorSize - WRBytes; /* set number of unused bytes */
}
return LatchBytes - Bytes;
}
/*E*/
/*F*/ STATIC GD creategd(VOID)
{
GD new;
LOCALSYSBASE;
if (new = AllocVec(sizeof(struct GlobalData), MEMF_ANY | MEMF_CLEAR))
new->gd_SysBase = SysBase;
return new;
}
/*E*/
/*F*/ STATIC BOOL openres(GD gd)
{
BOOL rc = FALSE;
d(("entered\n"));
DOSBase = NULL;
UtilityBase = NULL;
gd->gd_Port = NULL;
if (SysBase->lib_Version >= 37)
{
if (DOSBase = OpenLibrary("dos.library", 37))
{
if (UtilityBase = OpenLibrary("utility.library", 37))
{
if (gd->gd_Port = CreateMsgPort())
{
rc = TRUE;
}
else d(("no handler port\n"));
}
else d(("no utility V37\n"));
}
else d(("no dos V37\n"));
}
else d(("no exec V37\n"));
d(("left: %ld\n",rc));
return rc;
}
/*E*/
/*F*/ STATIC VOID closeres(GD gd)
{
d(("freeing port\n"));
if (gd->gd_Port) DeleteMsgPort(gd->gd_Port);
d(("closing dos\n"));
if (DOSBase) CloseLibrary(DOSBase);
d(("closing utility\n"));
if (UtilityBase) CloseLibrary(UtilityBase);
FreeVec(gd);
}
/*E*/