home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / disks / misc / device-handler / source / device-handler.c < prev    next >
C/C++ Source or Header  |  1981-06-29  |  28KB  |  966 lines

  1. /*
  2. ** $VER: device-handler.c 1.6 (03 Jun 1995)
  3. **
  4. ** device-handler - raw device access
  5. **
  6. ** (C) Copyright 1995 Marius Gröger
  7. **     All Rights Reserved.
  8. */
  9.  
  10. /*F*/ /* history */
  11. /* $HISTORY:
  12. **
  13. ** 03 Jun 1995 : 001.006 :  + locyl was broken
  14. **                          + dot conversion starts after first slash
  15. **                          + source code ANSIfied
  16. **                          + added some macros for compiler abstraction
  17. **                          + didn't remove task correctly
  18. ** 24 Apr 1995 : 001.005 :  at the end of a media Write()/Read() returned wrong res1,
  19. **                          so multi-volume tar archives shouldn't be a problem any
  20. **                          longer
  21. ** 22 Feb 1995 : 001.004 :  some bug-fixing
  22. ** 18 Feb 1995 : 001.003 :  made Write() working...
  23. ** 20 Dec 1994 : 001.002 :  + one task/multiple FileHandles
  24. **                          + source-code rework
  25. **                          + better stream name scanning by ReadArgs()
  26. **                          + new option MAXLENGTH
  27. **                          + new options LOCYL, HICYL
  28. **                          + highly improved read/write operation
  29. ** 18 Dec 1994 : 001.001 :  changed stream name convention
  30. ** 08 Dec 1994 : 001.000 :  took over from Matthias Scheler
  31. */
  32. /*E*/
  33.  
  34. /*F*/ /* includes */
  35.  
  36.    /* system protoypes and pragmas */
  37.    /* ensure to use the symbol SysBase and not the hardcoded AbsExecBase */
  38. #define __USE_SYSBASE
  39. #include <clib/exec_protos.h>
  40. #include <pragmas/exec_pragmas.h>
  41. #include <clib/dos_protos.h>
  42. #include <pragmas/dos_pragmas.h>
  43. #include <clib/utility_protos.h>
  44. #include <pragmas/utility_pragmas.h>
  45.  
  46.    /* system header files */
  47. #include <exec/types.h>
  48. #include <exec/memory.h>
  49. #include <exec/execbase.h>
  50. #include <devices/trackdisk.h>
  51. #include <dos/dosextens.h>
  52. #include <dos/filehandler.h>
  53. #include <dos/dos.h>
  54.  
  55.    /* compiler header files */
  56. #include <string.h>
  57.  
  58. /* fix include files (anyawy I'm not yet using them:
  59. ** what about sending me a diff-file ?)
  60. */
  61. #ifndef ACTION_GET_DISK_FSSM
  62. #define ACTION_GET_DISK_FSSM 4201
  63. #endif
  64. #ifndef ACTION_FREE_DISK_FSSM
  65. #define ACTION_FREE_DISK_FSSM 4202
  66. #endif
  67.  
  68. #include "device-handler_rev.h"
  69.  
  70. /*E*/
  71.  
  72. /*F*/ /* debug */
  73. extern void KPrintF(char *, ...);
  74. /*#define d(x) do { KPrintF("%s:%ld: ", __FUNC__, __LINE__); KPrintF x; } while(0)*/
  75. #define d(x)
  76. /*E*/
  77. /*F*/ /* compiler abstraction */
  78.  
  79. #ifdef __SASC
  80. #  define ASM     __asm
  81. #  define REG(x)  register __ ## x
  82. #  define INLINE  __inline
  83. #  define REGARGS __regargs
  84. #  define SAVEDS  __saveds
  85. #  define FAR     __far
  86. #  define MIN     __builtin_min
  87. #  define MAX     __builtin_max
  88. #else
  89. #  error Please define the above macros for your compiler
  90. #endif
  91.  
  92. /*E*/
  93.  
  94. /*F*/ /* global static storage */
  95.  
  96. typedef struct GlobalData
  97. {
  98.    struct Library   *gd_SysBase;
  99.    struct Library   *gd_DOSBase;
  100.    struct Library   *gd_UtilityBase;
  101.    struct MsgPort   *gd_Port;
  102.    struct DosList   *gd_DosList;
  103.    struct Process   *gd_We;
  104. } *GD;
  105.  
  106. #ifdef __SASC
  107.      /* redirect all shared library bases to our device base */
  108. #  define SysBase      gd->gd_SysBase
  109. #  define DOSBase      gd->gd_DOSBase
  110. #  define UtilityBase  gd->gd_UtilityBase
  111.      /* This macro declares a local variable which temporary gets
  112.         SysBase directly from AbsExecBase. */
  113. #  define LOCALSYSBASE struct { VOID *gd_SysBase; } *gd = (VOID*)0x4
  114. #else
  115. #  error Please define library bases for your compiler
  116. #endif
  117. /*E*/
  118. /*F*/ /* handler declarations */
  119.  
  120. #define STREAMNAME_TEMPLATE "DOSNAME/A,MAXLENGTH,LOCYL/K,HICYL/K"
  121.  
  122. struct StreamOpts
  123. {
  124.    UBYTE    *so_DOSName;
  125.    UBYTE    *so_MaxLength;
  126.    UBYTE    *so_LoCyl;
  127.    UBYTE    *so_HiCyl;
  128. };
  129.  
  130. #define BCPL_MAXNAME 256
  131. struct PrivateStreamData
  132. {
  133.    struct IOStdReq  *psd_IO;                    /* Exec I/O Block */
  134.    UBYTE             psd_DOSName[BCPL_MAXNAME]; /* Name of AmigaDOS handler */
  135.    UBYTE             psd_Device[32];            /* OpenDevice()-name */
  136.    ULONG             psd_Unit;                  /* OpenDevice()-unit */
  137.    ULONG             psd_Flags;                 /* OpenDevice()-flags */
  138.    ULONG             psd_BufMemType;            /* memory type needed */
  139.    LONG              psd_LoCyl, psd_HiCyl;      /* cylinder boundaries */
  140.    LONG              psd_SectorSize;            /* length of a sector */
  141.    LONG              psd_Offset;                /* starting sector */
  142.    LONG              psd_MaxLength;             /* max-length of "file" */
  143.    LONG              psd_Pos;                   /* current pos. in "file" */
  144.    LONG              psd_Len;                   /* actual length of "file" */
  145.    UBYTE            *psd_Buffer;                /* r/w buffer */
  146.    LONG              psd_Left;                  /* bytes left in r/w buffer */
  147.    UBYTE            *psd_Ptr;                   /* current pos in buffer */
  148.    BOOL              psd_Write;                 /* file is in write mode */
  149.    struct StreamOpts psd_Param;                 /* ReadArgs() argument */
  150. };
  151.  
  152.  
  153. /*E*/
  154.  
  155. /*F*/ /* prototypes */
  156. STATIC struct DosPacket *WaitDosPacket(GD gd, struct MsgPort *port);
  157. STATIC VOID ReplyDosPacket(GD gd, struct MsgPort *port, struct DosPacket *Packet,LONG Res1,LONG Res2);
  158. STATIC BOOL GetXDULONG(GD gd, UBYTE *s, LONG *number);
  159. STATIC VOID Stream2RDArgs(UBYTE *buffer);
  160. STATIC BOOL StreamSpecs(GD gd, struct PrivateStreamData *psd, BPTR streamname, LONG *res);
  161. STATIC BOOL FindDevice(GD gd, struct PrivateStreamData *psd);
  162. STATIC VOID OpenDH(GD gd, struct DosPacket *Pkt,ULONG *OpenCnt);
  163. STATIC VOID CloseDH(GD gd, struct PrivateStreamData *psd,ULONG *OpenCnt);
  164. STATIC LONG REGARGS RawRead(GD gd, struct PrivateStreamData *psd, UBYTE *Buffer, LONG Bytes, LONG *res2);
  165. STATIC LONG REGARGS RawWrite(GD gd, struct PrivateStreamData *psd,UBYTE *Buffer,LONG Bytes, LONG *res2);
  166. STATIC GD creategd(VOID);
  167. STATIC BOOL openres(GD gd);
  168. STATIC VOID closeres(GD gd);
  169. GLOBAL LONG main(VOID);
  170. /*E*/
  171.  
  172. /*F*/ GLOBAL LONG SAVEDS main(VOID)
  173. /*
  174. ** don't remove GLOBAL, if you don't want to the complete
  175. ** source to get optimized out of existence :-)
  176. */
  177. {
  178.    GD gd;
  179.    struct DosPacket *Pkt;
  180.    BOOL Done;
  181.    ULONG OpenCnt;
  182.    LONG rc = RETURN_OK;
  183.  
  184.    d(("this is the DEV handler, compiled on "__DATE__"\n"));
  185.  
  186.    if (gd = creategd())
  187.    {
  188.       if ((gd->gd_We = (struct Process *)FindTask(NULL))->pr_CLI) return RETURN_FAIL;
  189.  
  190.       d(("waiting for startup-packet...\n"));
  191.       Pkt = WaitDosPacket(gd, &gd->gd_We->pr_MsgPort);
  192.  
  193.       if (openres(gd))
  194.       {
  195.          gd->gd_DosList = (struct DosList *)BADDR(Pkt->dp_Arg3);
  196.          gd->gd_DosList->dol_Task = gd->gd_Port;
  197.  
  198.          d(("replying startup-packet...\n"));
  199.          ReplyDosPacket(gd, gd->gd_Port, Pkt, DOSTRUE, Pkt->dp_Res2);
  200.  
  201.          Done=FALSE;
  202.          OpenCnt=0L;
  203.  
  204.          d(("entering mainloop\n"));
  205.  
  206.          while (!Done)
  207.          {
  208.             Pkt=WaitDosPacket(gd, gd->gd_Port);
  209.  
  210.             d(("got packet %ld\n",Pkt->dp_Type));
  211.  
  212.             Pkt->dp_Res1 = DOSFALSE;
  213.             Pkt->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  214.  
  215.             switch (Pkt->dp_Type)
  216.             {
  217.                case ACTION_FINDINPUT:
  218.                case ACTION_FINDOUTPUT:
  219.                   OpenDH (gd, Pkt, &OpenCnt);
  220.                   ReplyDosPacket(gd, gd->gd_Port,Pkt, Pkt->dp_Res1, Pkt->dp_Res2);
  221.                break;
  222.  
  223.                case ACTION_READ:
  224.                {
  225.                   struct PrivateStreamData *psd = (struct PrivateStreamData *)Pkt->dp_Arg1;
  226.  
  227.                   if (psd && !psd->psd_Write)
  228.                   {
  229.                      LONG Bytes, error;
  230.  
  231.                      Bytes = RawRead(gd, (struct PrivateStreamData *)Pkt->dp_Arg1,
  232.                                          (UBYTE *)Pkt->dp_Arg2,Pkt->dp_Arg3, &error);
  233.  
  234.                      ReplyDosPacket(gd, gd->gd_Port,Pkt, Bytes, error);
  235.                   }
  236.                }
  237.                break;
  238.  
  239.                case ACTION_WRITE:
  240.                {
  241.                   struct PrivateStreamData *psd = (struct PrivateStreamData *)Pkt->dp_Arg1;
  242.  
  243.                   if (psd && psd->psd_Write)
  244.                   {
  245.                      LONG Bytes, error;
  246.  
  247.                      Bytes = RawWrite(gd, (struct PrivateStreamData *)Pkt->dp_Arg1,
  248.                                           (UBYTE *)Pkt->dp_Arg2, Pkt->dp_Arg3, &error);
  249.  
  250.                      ReplyDosPacket(gd, gd->gd_Port,Pkt, Bytes, error);
  251.                   }
  252.                }
  253.                break;
  254.  
  255.                case ACTION_IS_FILESYSTEM:
  256.                   ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE, 0);
  257.                break;
  258.  
  259.                case ACTION_SEEK:
  260.                case ACTION_SET_FILE_SIZE:
  261.                   ReplyDosPacket(gd, gd->gd_Port,Pkt, -1,ERROR_ACTION_NOT_KNOWN);
  262.                break;
  263.  
  264.                case ACTION_END:
  265.                   CloseDH (gd, (struct PrivateStreamData *)Pkt->dp_Arg1,&OpenCnt);
  266.                   ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSTRUE, 0);
  267.                   /* FALLTHROUGH */
  268.                case ACTION_DIE:
  269.                   if (OpenCnt==0L)
  270.                   {
  271.                      d(("opencnt = 0\n"));
  272.  
  273.                      if (IsListEmpty(&gd->gd_Port->mp_MsgList))
  274.                      {
  275.                         gd->gd_DosList->dol_Task = NULL;
  276.  
  277.                         if (Pkt->dp_Type == ACTION_DIE)
  278.                            ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSTRUE, 0);
  279.  
  280.                         Done=TRUE;
  281.                      }
  282.                      else
  283.                      {
  284.                         if (Pkt->dp_Type == ACTION_DIE)
  285.                            ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE,ERROR_OBJECT_IN_USE);
  286.                      }
  287.                   }
  288.                   else
  289.                   {
  290.                      if (Pkt->dp_Type == ACTION_DIE)
  291.                         ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE,ERROR_OBJECT_IN_USE);
  292.                   }
  293.                break;
  294.  
  295.                default:
  296.                   ReplyDosPacket(gd, gd->gd_Port, Pkt, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
  297.                break;
  298.             }
  299.          }
  300.       }
  301.       else
  302.       {
  303.          ReplyDosPacket(gd, &gd->gd_We->pr_MsgPort, Pkt, DOSFALSE, ERROR_NO_FREE_STORE);
  304.          rc = RETURN_FAIL;
  305.       }
  306.       closeres(gd);
  307.  
  308.       d(("returning\n"));
  309.    }
  310.    else rc = RETURN_FAIL;
  311.  
  312.  
  313.    return rc;
  314. }
  315. const STATIC UBYTE version[]=VERSTAG;
  316. /*E*/
  317.  
  318. /*F*/ STATIC struct DosPacket *WaitDosPacket(GD gd, struct MsgPort *port)
  319.  
  320. {
  321.    WaitPort(port);
  322.    return (struct DosPacket *)(GetMsg(port)->mn_Node.ln_Name);
  323. }
  324. /*E*/
  325. /*F*/ STATIC VOID ReplyDosPacket(GD gd, struct MsgPort *port, struct DosPacket *Packet,LONG Res1,LONG Res2)
  326. {
  327.    struct MsgPort *reply = Packet->dp_Port;
  328.  
  329.    Packet->dp_Port = port;
  330.    Packet->dp_Link->mn_Node.ln_Name = (char *)Packet;
  331.    Packet->dp_Res1 = Res1;
  332.    Packet->dp_Res2 = Res2;
  333.  
  334.    PutMsg (reply, Packet->dp_Link);
  335. }
  336. /*E*/
  337.  
  338. /*F*/ STATIC BOOL GetXDULONG(GD gd, UBYTE *s, LONG *number)
  339. {
  340.  
  341. #define IsDigit(c) ((c) >= '0' && (c) <= '9'))
  342. #define IsXDigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F'))
  343.  
  344.    BOOL hex, rc = TRUE;
  345.    ULONG num;
  346.    UBYTE c;
  347.    WORD len;
  348.  
  349.    if (len = strlen(s))
  350.    {
  351.       if (!Strnicmp(s, "0x", 2))
  352.       {
  353.          hex = TRUE;
  354.          s += 2;
  355.       }
  356.       else if (!Strnicmp(s, "$", 2))
  357.       {
  358.          hex = TRUE;
  359.          s++;
  360.       }
  361.       else hex = FALSE;
  362.  
  363.       for(num=0;*s;s++)
  364.       {
  365.          c = ToUpper((ULONG)*s);
  366.          if (hex)
  367.          {
  368.             if (c >= '0' && c <= '9') num = num * 16 + c - '0';
  369.             else if (c >= 'A' && c <= 'F') num = num * 16 + c - '0';
  370.             else break;
  371.          }
  372.          else
  373.          {
  374.             if (c >= '0' && c <= '9') num = num * 10 + c - '0';
  375.             else break;
  376.          }
  377.       }
  378.  
  379.       if (*s)
  380.       {
  381.          if (c == 'K') num *= 1024;
  382.          else if (c == 'M') num *= 1024*1024;
  383.          else rc = FALSE;
  384.       }
  385.    }
  386.    else rc = FALSE;
  387.  
  388.    if (rc) *number = num;
  389.  
  390.    return rc;
  391. }
  392. /*E*/
  393. /*F*/ STATIC VOID Stream2RDArgs(UBYTE *buffer)
  394. {
  395.    UBYTE *p;
  396.    enum { s_start, s_conv, s_esc, s_quote } s, sb;
  397.  
  398.    for (p = buffer, sb = s = s_start; *p; p++)
  399.       switch(s)
  400.       {
  401.          case s_start:                     /* no convertion 'til 1st slash */
  402.             if (*p == '"')
  403.             {
  404.                s = s_quote;
  405.                break;
  406.             }
  407.             else if (*p != '/')
  408.                break;
  409.             sb = s = s_conv;
  410.             /* FALLTHROUGH */
  411.          case s_conv:                      /* conversion state */
  412.             if (*p == '.') *p = '=';
  413.             else if (*p == '/') *p = '\040';
  414.             else if (*p == '"') s = s_quote;
  415.          break;
  416.          case s_esc:                       /* (asterisk-)escape state */
  417.             s = s_quote;
  418.          break;
  419.          case s_quote:                     /* quotation state */
  420.             if (*p == '*') s = s_esc;
  421.             if (*p == '"') s = sb;
  422.          break;
  423.       }
  424. }
  425. /*E*/
  426. /*F*/ STATIC BOOL StreamSpecs(GD gd, struct PrivateStreamData *psd, BPTR streamname, LONG *res)
  427. {
  428.    UBYTE *temp, *bstr, *start;
  429.    BOOL rc = FALSE;
  430.    struct RDArgs *inrda, *rda;
  431.  
  432.    memset(&psd->psd_Param, '\0', (int)sizeof(psd->psd_Param));
  433.  
  434.    bstr = (UBYTE *)BADDR(streamname);
  435.  
  436.    if (temp = AllocVec((ULONG)bstr[0]+2, MEMF_ANY))
  437.    {
  438.       if (inrda = AllocDosObject(DOS_RDARGS, NULL))
  439.       {
  440.          strncpy(temp, bstr+1, bstr[0]);
  441.          temp[bstr[0]] = '\n';
  442.          temp[bstr[0]+1] = '\0';
  443.  
  444.          if (start = (UBYTE*)strchr((char*)temp, ':'))
  445.          {
  446.             Stream2RDArgs(++start);
  447.  
  448.             inrda->RDA_Source.CS_Buffer = start;
  449.             inrda->RDA_Source.CS_Length = strlen(start);
  450.             inrda->RDA_Source.CS_CurChr = 0;
  451.  
  452.             psd->psd_MaxLength = 0x7fffffff;
  453.             psd->psd_LoCyl = 0;
  454.             psd->psd_HiCyl = 0x7fffffff;
  455.  
  456.             d(("readargs(%s)\n",start));
  457.             if (rda = ReadArgs((UBYTE*)STREAMNAME_TEMPLATE, (LONG*)&psd->psd_Param, inrda))
  458.             {
  459.                rc = TRUE;
  460.  
  461.                strcpy(psd->psd_DOSName, (char*)psd->psd_Param.so_DOSName);
  462.  
  463.                if (psd->psd_Param.so_MaxLength)
  464.                   rc = GetXDULONG(gd,psd->psd_Param.so_MaxLength, &psd->psd_MaxLength);
  465.  
  466.                if (rc && psd->psd_Param.so_LoCyl)
  467.                   rc = GetXDULONG(gd,psd->psd_Param.so_LoCyl, &psd->psd_LoCyl);
  468.  
  469.                if (rc && psd->psd_Param.so_HiCyl)
  470.                   rc = GetXDULONG(gd,psd->psd_Param.so_HiCyl, &psd->psd_HiCyl);
  471.  
  472.                d(("after ReadArgs(): doshandler %s maxlen %lu locyl %lu hicyl %lu\n",
  473.                   psd->psd_DOSName,psd->psd_MaxLength,psd->psd_LoCyl,psd->psd_HiCyl));
  474.  
  475.                FreeArgs(rda);
  476.             }
  477.             else
  478.             {
  479.                d(("ReadArgs() failed\n"));
  480.                *res = ERROR_BAD_STREAM_NAME;
  481.             }
  482.          }
  483.          else
  484.          {
  485.             d(("no proper name\n"));
  486.             *res = ERROR_BAD_STREAM_NAME;
  487.          }
  488.  
  489.          FreeDosObject(DOS_RDARGS, inrda);
  490.       }
  491.       else
  492.       {
  493.          d(("no RDArgs\n"));
  494.          *res = ERROR_NO_FREE_STORE;
  495.       }
  496.  
  497.       FreeVec(temp);
  498.    }
  499.    else
  500.    {
  501.       d(("no more memory\n"));
  502.       *res = ERROR_NO_FREE_STORE;
  503.    }
  504.  
  505.    return rc;
  506. }
  507. /*E*/
  508.  
  509. /*F*/ STATIC BOOL FindDevice(GD gd, struct PrivateStreamData *psd)
  510. {
  511.    struct DosList *dol;
  512.    struct FileSysStartupMsg *fssm;
  513.    BOOL rc = FALSE;
  514.    UBYTE *name;
  515.    UBYTE n;
  516.    UBYTE pat[40];
  517.  
  518.    d(("entered: %s\n", psd->psd_DOSName));
  519.  
  520.    n = strlen(psd->psd_DOSName);
  521.  
  522.    if (dol = LockDosList(LDF_READ | LDF_DEVICES))
  523.    {
  524.       while(dol = NextDosEntry(dol, LDF_DEVICES))
  525.       {
  526.          name = (UBYTE*)BADDR(dol->dol_Name);
  527.  
  528.          memset(pat,0,40);
  529.          strncpy(pat,name+1,name[0]);
  530.          d(("%s\n",pat));
  531.  
  532.          if ((n == name[0]) && !Strnicmp((char*)(name+1), psd->psd_DOSName, (LONG)n))
  533.          {
  534.             d(("found\n"));
  535.  
  536.             fssm = (struct FileSysStartupMsg*)BADDR(dol->dol_misc.dol_handler.dol_Startup);
  537.  
  538.             if (fssm)
  539.             {
  540.                struct DosEnvec *de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
  541.  
  542.                d(("found fssm\n"));
  543.  
  544.                   /* note: fssm->fssm_Device is a NUL-terminated BSTR!! :-) */
  545.                strcpy((char*)psd->psd_Device, (char*)BADDR(fssm->fssm_Device)+1);
  546.  
  547.                psd->psd_Flags = fssm->fssm_Flags;
  548.                psd->psd_Unit = fssm->fssm_Unit;
  549.                psd->psd_BufMemType = de->de_BufMemType;
  550.                psd->psd_SectorSize = 4 * de->de_SizeBlock;
  551.                if (!psd->psd_Param.so_HiCyl) psd->psd_HiCyl = de->de_HighCyl;
  552.                if (!psd->psd_Param.so_LoCyl) psd->psd_LoCyl = de->de_LowCyl;
  553.                psd->psd_LoCyl = (LONG)MIN((int)psd->psd_LoCyl, (int)psd->psd_HiCyl);
  554.                d(("de->de_BlocksPerTrack %ld, psd->psd_LoCyl %ld, psd->psd_HiCyl %ld, de->de_Surfaces %ld, psd->psd_SectorSize %ld\n",
  555.                    de->de_BlocksPerTrack,     psd->psd_LoCyl,     psd->psd_HiCyl,     de->de_Surfaces,     psd->psd_SectorSize));
  556.                psd->psd_Offset = de->de_BlocksPerTrack * psd->psd_LoCyl * de->de_Surfaces * psd->psd_SectorSize;
  557.  
  558.                psd->psd_Len = de->de_BlocksPerTrack * psd->psd_SectorSize * (psd->psd_HiCyl - psd->psd_LoCyl + 1) * de->de_Surfaces;
  559.                psd->psd_Len = (LONG)MIN((int)psd->psd_MaxLength, (int)psd->psd_Len);
  560.                d(("len %lu\n",psd->psd_Len));
  561.  
  562.                d(("device %s, unit %ld, flags %ld, secsiz %ld, off %ld\n",
  563.                   psd->psd_Device,psd->psd_Unit,psd->psd_Flags,psd->psd_SectorSize,psd->psd_Offset));
  564.  
  565.                rc = TRUE;
  566.             }
  567.             else
  568.                d(("no fssm\n"));
  569.  
  570.             break;
  571.          }
  572.       }
  573.  
  574.       UnLockDosList(LDF_READ | LDF_DEVICES);
  575.    }
  576.  
  577.    return(rc);
  578. }
  579. /*E*/
  580.  
  581. /*F*/ STATIC VOID OpenDH(GD gd, struct DosPacket *Pkt,ULONG *OpenCnt)
  582. {
  583.    struct FileHandle *FH;
  584.    struct PrivateStreamData *psd;
  585.    struct MsgPort *IOPort;
  586.    BOOL ok = FALSE;
  587.  
  588.    Pkt->dp_Res1 = DOSFALSE;
  589.    FH = (struct FileHandle *)BADDR(Pkt->dp_Arg1);
  590.    FH->fh_Port = (struct MsgPort *)FALSE;
  591.    FH->fh_Arg1 = 0L;
  592.  
  593.    d(("allocing psd\n"));
  594.    if (psd = AllocVec(sizeof(*psd),MEMF_PUBLIC|MEMF_CLEAR))
  595.    {
  596.       if (StreamSpecs(gd, psd, (BPTR)Pkt->dp_Arg3, &Pkt->dp_Res2))
  597.       {
  598.          d(("creating msgport\n"));
  599.          if (IOPort=CreateMsgPort())
  600.          {
  601.             if (psd->psd_IO=CreateIORequest(IOPort, sizeof(struct IOStdReq)))
  602.             {
  603.                if (FindDevice(gd, psd))
  604.                {
  605.                   if (OpenDevice(psd->psd_Device, psd->psd_Unit, (struct IORequest *)psd->psd_IO, psd->psd_Flags)==0L)
  606.                   {
  607.                      if (psd->psd_Buffer = AllocVec(psd->psd_SectorSize, psd->psd_BufMemType))
  608.                      {
  609.                         if (Pkt->dp_Type == ACTION_FINDOUTPUT)
  610.                         {
  611.                            psd->psd_Write = TRUE;
  612.                         }
  613.                         else
  614.                         {
  615.                            psd->psd_Write = FALSE;
  616.                            psd->psd_IO->io_Command = CMD_READ;
  617.                         }
  618.                         psd->psd_Ptr = psd->psd_Buffer;
  619.                         psd->psd_Pos = 0;
  620.                         psd->psd_Left = 0;
  621.  
  622.                         FH->fh_Arg1 = (LONG)psd;
  623.  
  624.                         Pkt->dp_Res1 = DOSTRUE;
  625.                         Pkt->dp_Res2 = 0L;
  626.  
  627.                         (*OpenCnt)++;
  628.                         ok = TRUE;
  629.                      }
  630.                      else Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
  631.  
  632.                      if (!ok) CloseDevice ((struct IORequest *)psd->psd_IO);
  633.                   }
  634.                   else
  635.                   {
  636.                      d(("could not open device >%s<\n",psd->psd_Device));
  637.                      Pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  638.                   }
  639.                }
  640.                else
  641.                {
  642.                   d(("no device\n"));
  643.                   Pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  644.                }
  645.  
  646.                if (!ok) DeleteIORequest(psd->psd_IO);
  647.             }
  648.             else
  649.             {
  650.                d(("no iorequest\n"));
  651.                Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
  652.             }
  653.  
  654.             if (!ok) DeleteMsgPort (IOPort);
  655.          }
  656.          else
  657.          {
  658.             d(("no msgport\n"));
  659.             Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
  660.          }
  661.       }
  662.       else
  663.       {
  664.          d(("no StreamSpecs()\n"));
  665.       }
  666.       if (!ok) FreeVec (psd);
  667.    }
  668.    else
  669.    {
  670.        d(("no psd\n"));
  671.        Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
  672.    }
  673.  
  674.    d(("leaving OpenDH() with Res2 = %ld\n",Pkt->dp_Res2));
  675. }
  676. /*E*/
  677. /*F*/ STATIC VOID CloseDH(GD gd, struct PrivateStreamData *psd,ULONG *OpenCnt)
  678. {
  679.    d(("CloseDH()\n"));
  680.    if (psd->psd_Write)
  681.    {
  682.       if (psd->psd_Left < psd->psd_SectorSize)
  683.       {
  684.          d(("DoIO(CMD_WRITE)\n"));
  685.  
  686.          memset(psd->psd_Ptr,'\0',(size_t)psd->psd_Left);
  687.          psd->psd_IO->io_Length  = psd->psd_SectorSize;
  688.          psd->psd_IO->io_Data    = psd->psd_Buffer;
  689.          psd->psd_IO->io_Offset  = psd->psd_Pos + psd->psd_Left-psd->psd_SectorSize;
  690.          psd->psd_IO->io_Command = CMD_WRITE;
  691.          DoIO((struct IORequest *)psd->psd_IO);
  692.       }
  693.       psd->psd_IO->io_Command=CMD_UPDATE;
  694.  
  695.       d(("DoIO(CMD_UPDATE)\n"));
  696.       DoIO((struct IORequest *)psd->psd_IO);
  697.    }
  698.  
  699.    d(("FreeVec() buffer\n"));
  700.  
  701.    FreeVec(psd->psd_Buffer);
  702.  
  703.    d(("stopping motor off\n"));
  704.    psd->psd_IO->io_Command = TD_MOTOR;
  705.    psd->psd_IO->io_Length = 0L;
  706.    DoIO((struct IORequest *)psd->psd_IO);
  707.    d(("closing device\n"));
  708.    CloseDevice ((struct IORequest *)psd->psd_IO);
  709.  
  710.    d(("deleting msg port\n"));
  711.    DeleteMsgPort (psd->psd_IO->io_Message.mn_ReplyPort);
  712.  
  713.    d(("deleting stdio\n"));
  714.    DeleteIORequest (psd->psd_IO);
  715.  
  716.    d(("FreeVec() rh\n"));
  717.    FreeVec (psd);
  718.  
  719.    (*OpenCnt)--;
  720.  
  721.    d(("leaving closedh()\n"));
  722.  
  723. }
  724. /*E*/
  725.  
  726. /*F*/ STATIC LONG REGARGS RawRead(GD gd, struct PrivateStreamData *psd, UBYTE *Buffer, LONG Bytes, LONG *res2)
  727. {
  728.    LONG LatchBytes, RDBytes;
  729.    BOOL error = FALSE;
  730.  
  731.       /* check bouunds */
  732.    if ((psd->psd_Pos + Bytes) > psd->psd_Len) Bytes = psd->psd_Len - psd->psd_Pos;
  733.  
  734.    LatchBytes = Bytes;
  735.  
  736.    d(("read %ld bytes\n",Bytes));
  737.  
  738.    /*
  739.    ** first, read what's left in buffer
  740.    */
  741.    if (psd->psd_Left)
  742.    {
  743.       RDBytes = (LONG)MIN((int)psd->psd_Left, (int)Bytes);
  744.       CopyMem(psd->psd_Ptr, Buffer, RDBytes);
  745.  
  746.       Buffer += RDBytes;
  747.       Bytes -= RDBytes;
  748.  
  749.       psd->psd_Pos += RDBytes;   /* incr. position in file */
  750.       psd->psd_Ptr += RDBytes;
  751.       psd->psd_Left -= RDBytes;
  752.    }
  753.  
  754.    /*
  755.    ** second, try to read as much blocks as possible directly to
  756.    ** user buffer, aVOIDing CopyMem()
  757.    */
  758.    if (!error && (Bytes > psd->psd_SectorSize))
  759.    {
  760.       RDBytes = (Bytes / psd->psd_SectorSize) * psd->psd_SectorSize;
  761.  
  762.       psd->psd_IO->io_Data = Buffer;
  763.       psd->psd_IO->io_Length = RDBytes;
  764.       psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  765.       if (DoIO((struct IORequest *)psd->psd_IO))
  766.       {
  767.          RDBytes = psd->psd_IO->io_Actual;
  768.          error = TRUE;
  769.          *res2 = psd->psd_IO->io_Error;
  770.       }
  771.       Buffer += RDBytes;
  772.       Bytes -= RDBytes;
  773.  
  774.       psd->psd_Pos += RDBytes;         /* incr. position in file */
  775.       psd->psd_Left = 0;               /* for safety, initialise buffer */
  776.       psd->psd_Ptr = psd->psd_Buffer;
  777.    }
  778.  
  779.    if (!error && Bytes)
  780.    {
  781.       /*
  782.       ** now there are only some bytes < SectorSize left, so they fit into one buffer
  783.       ** So, read a buffer and copy some bytes from it to user-buffer.
  784.       */
  785.       RDBytes = Bytes;
  786.       psd->psd_IO->io_Length = psd->psd_SectorSize;
  787.       psd->psd_IO->io_Data = psd->psd_Buffer;
  788.       psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  789.  
  790.       if (DoIO((struct IORequest *)psd->psd_IO))
  791.       {
  792.          *res2 = psd->psd_IO->io_Error;
  793.          RDBytes = psd->psd_IO->io_Actual;
  794.       }
  795.  
  796.       CopyMem(psd->psd_Buffer, Buffer, RDBytes);
  797.  
  798.       psd->psd_Pos += RDBytes;
  799.       psd->psd_Ptr = psd->psd_Buffer + RDBytes;
  800.       psd->psd_Left = psd->psd_SectorSize - RDBytes;
  801.  
  802.       Bytes -= RDBytes;
  803.    }
  804.  
  805.    return LatchBytes - Bytes;
  806. }
  807. /*E*/
  808. /*F*/ STATIC LONG REGARGS RawWrite(GD gd, struct PrivateStreamData *psd,UBYTE *Buffer,LONG Bytes, LONG *res2)
  809. {
  810.    LONG LatchBytes,WRBytes;
  811.    BOOL error = FALSE;
  812.  
  813.       /* check bounds */
  814.    if ((psd->psd_Pos + Bytes) > psd->psd_Len) Bytes = psd->psd_Len-psd->psd_Pos;
  815.  
  816.    LatchBytes = Bytes;
  817.  
  818.    d(("write %ld bytes\n",Bytes));
  819.  
  820.    /*
  821.    ** first, take care for outstanding data
  822.    */
  823.    if (Bytes && psd->psd_Left)
  824.    {
  825.       WRBytes = (LONG)MIN((int)psd->psd_Left, (int)Bytes);
  826.       CopyMem(Buffer, psd->psd_Ptr, WRBytes);
  827.  
  828.       psd->psd_Ptr += WRBytes;      /* incr. position in buffer */
  829.       psd->psd_Left -= WRBytes;     /* decr. number of unused bytes */
  830.  
  831.       if (psd->psd_Left == 0)       /* Buffer full ? */
  832.       {                             /* then write it out */
  833.          psd->psd_IO->io_Data = psd->psd_Buffer;
  834.          psd->psd_IO->io_Length = psd->psd_SectorSize;
  835.          psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  836.          psd->psd_IO->io_Command = CMD_WRITE;
  837.          if (DoIO((struct IORequest *)psd->psd_IO))
  838.          {
  839.             *res2 = psd->psd_IO->io_Error;
  840.             WRBytes = psd->psd_IO->io_Actual;
  841.             error = TRUE;
  842.             d(("td-error %ld\n",psd->psd_IO->io_Error));
  843.          }
  844.  
  845.          psd->psd_Ptr = psd->psd_Buffer;  /* reset buffer pointers */
  846.          psd->psd_Left = 0;
  847.       }
  848.  
  849.       Buffer += WRBytes;
  850.       Bytes -= WRBytes;
  851.       psd->psd_Pos += WRBytes;      /* incr. position in file */
  852.    }
  853.  
  854.    if (!error && Bytes)
  855.    {
  856.       /*
  857.       ** second, try to write as much blocks as possible directly from
  858.       ** user buffer in one go, aVOIDing CopyMem() and multiple I/O-Requests
  859.       */
  860.       if (Bytes > psd->psd_SectorSize)
  861.       {
  862.             /* I don't like to use bit masking at this point */
  863.          WRBytes = (Bytes / psd->psd_SectorSize) * psd->psd_SectorSize;
  864.          d(("chunk %ld/%lx bytes\n",WRBytes,WRBytes));
  865.          psd->psd_IO->io_Data = Buffer;
  866.          psd->psd_IO->io_Length = WRBytes;
  867.          psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  868.          psd->psd_IO->io_Command = CMD_WRITE;
  869.          if (DoIO((struct IORequest *)psd->psd_IO))
  870.          {
  871.             *res2 = psd->psd_IO->io_Error;
  872.             WRBytes = psd->psd_IO->io_Actual;
  873.             error = TRUE;
  874.             d(("td-error %ld\n",psd->psd_IO->io_Error));
  875.          }
  876.  
  877.          Buffer += WRBytes;
  878.          Bytes -= WRBytes;
  879.          psd->psd_Pos += WRBytes;   /* incr. position in file */
  880.  
  881.          psd->psd_Ptr = psd->psd_Buffer;  /* for safety, reset buffer pointers */
  882.          psd->psd_Left = 0;
  883.       }
  884.    }
  885.  
  886.    if (!error && Bytes)
  887.    {
  888.       /*
  889.       ** now there are only some bytes < SectorSize left, and they fit into one
  890.       ** buffer.
  891.       ** NOTE: the actual writing is delayed to Close() or further Write()'s
  892.       */
  893.       WRBytes = Bytes;
  894.       CopyMem(Buffer, psd->psd_Buffer, WRBytes);
  895.  
  896.       psd->psd_Pos += WRBytes;     /* incr. position in file */
  897.       Bytes -= WRBytes;
  898.  
  899.       psd->psd_Ptr = psd->psd_Buffer + WRBytes;     /* set position in buffer */
  900.       psd->psd_Left = psd->psd_SectorSize - WRBytes; /* set number of unused bytes */
  901.    }
  902.  
  903.    return LatchBytes - Bytes;
  904. }
  905. /*E*/
  906.  
  907. /*F*/ STATIC GD creategd(VOID)
  908. {
  909.    GD new;
  910.    LOCALSYSBASE;
  911.  
  912.    if (new = AllocVec(sizeof(struct GlobalData), MEMF_ANY | MEMF_CLEAR))
  913.       new->gd_SysBase = SysBase;
  914.  
  915.    return new;
  916. }
  917. /*E*/
  918. /*F*/ STATIC BOOL openres(GD gd)
  919. {
  920.    BOOL rc = FALSE;
  921.  
  922.    d(("entered\n"));
  923.  
  924.    DOSBase = NULL;
  925.    UtilityBase = NULL;
  926.    gd->gd_Port = NULL;
  927.  
  928.    if (SysBase->lib_Version >= 37)
  929.    {
  930.       if (DOSBase = OpenLibrary("dos.library", 37))
  931.       {
  932.          if (UtilityBase = OpenLibrary("utility.library", 37))
  933.          {
  934.             if (gd->gd_Port = CreateMsgPort())
  935.             {
  936.                rc = TRUE;
  937.             }
  938.             else d(("no handler port\n"));
  939.          }
  940.          else d(("no utility V37\n"));
  941.       }
  942.       else d(("no dos V37\n"));
  943.    }
  944.    else d(("no exec V37\n"));
  945.  
  946.    d(("left: %ld\n",rc));
  947.  
  948.    return rc;
  949. }
  950. /*E*/
  951. /*F*/ STATIC VOID closeres(GD gd)
  952. {
  953.    d(("freeing port\n"));
  954.    if (gd->gd_Port) DeleteMsgPort(gd->gd_Port);
  955.  
  956.    d(("closing dos\n"));
  957.    if (DOSBase) CloseLibrary(DOSBase);
  958.  
  959.    d(("closing utility\n"));
  960.    if (UtilityBase) CloseLibrary(UtilityBase);
  961.  
  962.    FreeVec(gd);
  963. }
  964. /*E*/
  965.  
  966.