home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / disk / misc / dev_handler1_5.lha / Device-Handler / Device-Handler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-24  |  29.8 KB  |  1,035 lines

  1. ;/* "C:Execute" me to compile me with SAS/C 6
  2. Set file Device-Handler
  3.  
  4. sc:c/sc MOD NOICON VERBOSE STRMERGE UNSCHAR NOSTKCHK IGNORE=73 MOD CSRC $file.c
  5. sc:c/slink NOICONS FROM $file.o TO $file LIB lib:amiga.lib,lib:sc.lib,lib:debug.lib VERBOSE SMALLCODE SMALLDATA NODEBUG
  6. protect $file +p
  7.  
  8. UnSet opt
  9. UnSet file
  10. Quit
  11. */
  12.  
  13. /*F*/ /* autodoc */
  14. #if 0
  15. AUTODOC Device-Handler
  16. **
  17. ** $VER: Device-Handler 1.5 (24 Apr 1995)
  18. **
  19. ** Original code was written by Matthias Scheler. The original
  20. ** distribution archive of Matthias has been included.
  21. **
  22. **
  23. ** NAME
  24. **    Device-Handler - UNIX-like raw device access
  25. **
  26. ** WARNING
  27. **    This software is intended for advanced users only. I *strongly*
  28. **    recommend all people who do not understand every detail given
  29. **    herein to obtain further information about ->AmigaDOS-Devices
  30. **    and ->Handlers and their implementation on top of ->Exec
  31. **    device drivers.
  32. **
  33. **    ** WRONG USAGE OF THIS SOFTWARE WILL MOST LIKELY RESULT IN **
  34. **    ** SEVERE LOSS OF DATA!                                    **
  35. **
  36. **    As this software is freeware in cases of data disruption you
  37. **    will find _nobody_ being responsible except yourself. Especially
  38. **    Matthias and me reject any liability.
  39. **
  40. ** FUNCTION
  41. **    Amiga Users often put a jealous glance to the UNIX world, were
  42. **    raw device access is as simple as nowhere else. Several solutions
  43. **    to fix this for Amigas have been provided in the past. One of these,
  44. **    the DEV: handler by Matthias Scheler, has been taken to base this
  45. **    software on.
  46. **
  47. **    Specifically, the original DEV: has the considerable drawback that it
  48. **    only worked with devices that supported the ->TD_GETGEOMETRY
  49. **    ->IORequest. Unfortunatly a lot of harddisk- (and other) drivers don't
  50. **    implement this command.
  51. **
  52. **    So I decided to derive the Exec-device selection from on the AmigaDOS
  53. **    stream name in such way, that the user provides the Name of an
  54. **    AmigaDOS Handler instead of the Exec-Device. There are system conform
  55. **    ways to find out on top of which Exec-device an AmigaDOS handler is
  56. **    running, so why not leaving this job to the DEV:-Handler ?
  57. **
  58. **    With my DEV: enhancement, you may type things like "DEV:df0" or
  59. **    "DEV:dh0", you get the general idea. Further improvements include the
  60. **    ability to limit the total size which is allowed to read or write, and
  61. **    to specify the low- and high cylinders to be used.
  62. **
  63. **    Note that the physical definition is completely retrieved from the
  64. **    given handler name (e.g. dh0), so there are some implications:
  65. **
  66. **       * Exec-device will be always correct
  67. **       * Exec-device unit will be allways correspond to the unit
  68. **         the AmigaDOS handler works on, releasing you from dealing whith
  69. **         it and thus making the usage of DEV: _much_ safer!
  70. **       * Exec-device OpenDevice() flags are always correct
  71. **       * Exec-device buffer memory type is always correct
  72. **       * Most often you will want to use DEV: for ->UNIX tar and will want
  73. **         to start writing exactly at block 0. For most floppy-base devices
  74. **         this will be correct automatically. In contrast, nearly every
  75. **         harddisk contains a ->RigidDiskBlock and the actual partitions
  76. **         are located behind this, usually having a low-cylinder of about 3.
  77. **         To archieve the intended bahaviour, you should create a special
  78. **         DOSDriver/mountlist entry, such as:
  79. **
  80. **           RDH0:                       /* raw dh0 */
  81. **              Device = scsi.device     /* change this accordingly */
  82. **              Unit = 1
  83. **              Flags = 0
  84. **              Surfaces = 5
  85. **              BlocksPerTrack = 17
  86. **              LowCyl = 0 ;             /* specify here full range */
  87. **              HighCyl = 1023           /* of cylinders */
  88. **              Stacksize = 4000
  89. **              Priority = 5
  90. **              GlobVec = -1
  91. **              BufMemType = 0
  92. **           #
  93. **
  94. **         Another way is to use the LOCYL stream name option. Again note:
  95. **         Playing around with LOCYL or HICYL is a pretty dangerous thing.
  96. **         It is always advised to write a dedicated mountlist/DOSDriver.
  97. **
  98. **    Plead read also the original documentation of the DEV:-handler.
  99. **
  100. ** STREAM NAME
  101. **
  102. **    The stream name is constructed as following:
  103. **
  104. **       DEV:<DOSHANDLER>[/<MAXLEN>][/LOCYL=<NUM>][/HICYL=<NUM>]
  105. **
  106. **    During stream name processing, all slashes are removed, thus creating
  107. **    a standard AmigaDOS ReadArgs()-style text line, as you know it from
  108. **    all CLI-Programs (I suppose you deleted all those that don't use
  109. **    ReadArgs() ;).
  110. **
  111. **    Additionally, all dots ('.') which are not part of a quoted text, are
  112. **    substituted by an equation symbol ('='). That comes in handy when using
  113. **    the LOCYL or HICYL options. AmigaDOS strips all equations that are not
  114. **    quoted. Thus, the command "type dev:df0/locyl=3" would lead to an error,
  115. **    as the handler would get the text "dev:df0/locyl" instead of
  116. **    "dev:df0/locyl=3". So, either use the dot or quote the whole stream spec.
  117. **
  118. **    *Any* number which is to pass to the handler may start with '$' or '0x'
  119. **    or '0X' to indicate hexadecimal notation (default is decimal). A
  120. **    trailing 'M' tells the handler to interprete it as a mega-value,
  121. **    (i.e. multiply by 1024^2) and 'K' to signal a kilo value (factor 1024).
  122. **    All charactes are case-insensitive.
  123. **
  124. **    The complete convenience of ReadArgs() applies to stream name
  125. **    construction:
  126. **
  127. **       The template is "DOSHANDLER/A,MAXLEN,LOCYL/K,HICYL/K"
  128. **
  129. **       DOSNAME
  130. **          A valid, AmigaDOS-device name such as DH0, df0, ... The device has
  131. **          to be mounted, though.
  132. **
  133. **       MAXLEN
  134. **          optional: maximum length of bytes to read or write. The (final)
  135. **          lo/hicyl may enclose a smaller space: the smallest space is always
  136. **          used. This value _must_ appear anywhere behind DOSHANDLER.
  137. **
  138. **       LOCYL
  139. **          Starting cylinder read from/write to. If higher than the (final)
  140. **          high cylinder, low cylinder is casted to high cylinder.
  141. **
  142. **       HICYL
  143. **          Ending cylinder. If higher than physical, physical is used.
  144. **
  145. **    Some example stream names:
  146. **
  147. **       DEV:df0
  148. **       DEV:dh0/1024
  149. **       DEV:dh0/1k
  150. **       DEV:dh0/LOCYL=0
  151. **       DEV:dh1/HICYL=1k/LOCYL=0M/20M
  152. **       DEV:df0/$1000
  153. **       DEV:df0/0x2000/LOCYL.4
  154. **       "DEV:df0/0X200/LOCYL=4"
  155. **
  156. ** AUTHOR
  157. **
  158. **    Marius Gröger,
  159. **    Bärstadter Str. 4
  160. **    D-65307 Bad Schwalbach
  161. **    email: mag@sysgo.de
  162. **
  163. ** SOURCE
  164. **
  165. **    The source code of "Device-Handler" has been written with the GoldED
  166. **    text editor (© Dietmar Eilert). Text folds start with "/*F*/"
  167. **    and end with "/*E*/".
  168. **
  169. **    You may make any changes to the source for your own use.
  170. **    If you consider them useful for everybody, tell me so I can
  171. **    include them to the next public release.
  172. **
  173. **    The documentation has been extracted with makedoc (© Stefan Ruppert).
  174. **
  175. ** $HISTORY:
  176. **
  177. ** 24 Apr 1995 : 001.005 :  at the end of a media Write()/Read() returned wrong res1,
  178. **                          so multi-volume tar archives shouldn't be a problem any
  179. **                          longer
  180. ** 22 Feb 1995 : 001.004 :  some bug-fixing
  181. ** 18 Feb 1995 : 001.003 :  made Write() working...
  182. ** 20 Dec 1994 : 001.002 :  + one task/multiple FileHandles
  183. **                          + source-code rework
  184. **                          + better stream name scanning by ReadArgs()
  185. **                          + new option MAXLENGTH
  186. **                          + new options LOCYL, HICYL
  187. **                          + highly improved read/write operation
  188. ** 18 Dec 1994 : 001.001 :  changed stream name convention
  189. ** 08 Dec 1994 : 001.000 :  took over from Matthias Scheler
  190. **
  191. ENDDOC
  192. **
  193. #endif
  194. /*E*/
  195.  
  196. /*F*/ /* debug */
  197. extern void KPrintF(char *, ...);
  198. /*#define d(x) { KPrintF("%s:%ld: ", __FUNC__, __LINE__); KPrintF x; }*/
  199. #define d(x) ;
  200. /*E*/
  201.  
  202. /*F*/ /* includes */
  203. #include <exec/memory.h>
  204. #include <exec/execbase.h>
  205. #include <devices/trackdisk.h>
  206. #include <dos/dosextens.h>
  207. #include <dos/filehandler.h>
  208. #include <dos/dos.h>
  209.  
  210. #define __USE_SYSBASE
  211.  
  212. #include <clib/exec_protos.h>
  213. #include <pragmas/exec_pragmas.h>
  214.  
  215. #include <clib/dos_protos.h>
  216. #include <pragmas/dos_pragmas.h>
  217.  
  218. #include <clib/utility_protos.h>
  219. #include <pragmas/utility_pragmas.h>
  220.  
  221. #include <string.h>
  222.  
  223. /* fix include files (anyawy I'm not yet using them:
  224. ** what about sending me a diff-file ?)
  225. */
  226.  
  227. #ifndef ACTION_GET_DISK_FSSM
  228. #define ACTION_GET_DISK_FSSM 4201
  229. #endif
  230.  
  231. #ifndef ACTION_FREE_DISK_FSSM
  232. #define ACTION_FREE_DISK_FSSM 4202
  233. #endif
  234.  
  235. /*E*/
  236.  
  237. /*F*/ /* declarations */
  238.  
  239. typedef struct GlobalData {
  240.    struct Library *gd_SysBase, *gd_DOSBase, *gd_UtilityBase;
  241.    struct MsgPort *gd_Port;
  242.    struct DosList *gd_DosList;
  243.    struct Process *gd_We;
  244. } *GD;
  245.  
  246. #define SysBase (gd->gd_SysBase)
  247. #define DOSBase (gd->gd_DOSBase)
  248. #define UtilityBase (gd->gd_UtilityBase)
  249.  
  250. #define BCPL_MAXNAME 256
  251. struct PrivateStreamData
  252. {
  253.    struct IOStdReq *psd_IO;
  254.    UBYTE  psd_DOSName[BCPL_MAXNAME];
  255.    UBYTE  psd_Device[32];
  256.    ULONG  psd_Unit;
  257.    ULONG  psd_Flags;
  258.    ULONG  psd_BufMemType;
  259.    LONG  psd_LoCyl, psd_HiCyl;
  260.    LONG  psd_SectorSize;
  261.    LONG  psd_Offset;
  262.    LONG  psd_MaxLength;
  263.  
  264.    LONG  psd_Pos;
  265.    LONG  psd_Len;
  266.    LONG  psd_Left;
  267.    UBYTE *psd_Buffer;
  268.    UBYTE *psd_Ptr;
  269.    BOOL   psd_Write;
  270. };
  271.  
  272. #define MIN __builtin_min
  273. #define MAX __builtin_min
  274.  
  275. #define STREAMNAME_TEMPLATE "DOSNAME/A,MAXLENGTH,LOCYL/K,HICYL/K"
  276. enum { ARG_DOSNAME=0, ARG_MAXLENGTH, ARG_LOCYL, ARG_HICYL, ARG_COUNT };
  277.  
  278. /*E*/
  279.  
  280. /*F*/ /* entry */
  281. static ULONG main(void);
  282. static ULONG __saveds __asm entry(register __a0 UBYTE *line, register __d0 ULONG len)
  283. {
  284.    return(main());
  285. }
  286.  
  287. const static UBYTE version[]= "\0$VER: Device-Handler 1.5 "__AMIGADATE__;
  288.  
  289. /*E*/
  290.  
  291. /*F*/ static struct DosPacket *WaitDosPacket(GD gd, struct MsgPort *port)
  292.  
  293. {
  294.    WaitPort(port);
  295.    return (struct DosPacket *)(GetMsg(port)->mn_Node.ln_Name);
  296. }
  297. /*E*/
  298. /*F*/ static void ReplyDosPacket(GD gd, struct MsgPort *port, struct DosPacket *Packet,LONG Res1,LONG Res2)
  299. {
  300.    struct MsgPort *reply = Packet->dp_Port;
  301.  
  302.    Packet->dp_Port = port;
  303.    Packet->dp_Link->mn_Node.ln_Name = (char *)Packet;
  304.    Packet->dp_Res1 = Res1;
  305.    Packet->dp_Res2 = Res2;
  306.  
  307.    PutMsg (reply, Packet->dp_Link);
  308. }
  309. /*E*/
  310.  
  311. /*F*/ static BOOL openres(GD gd)
  312. {
  313.    BOOL rc = FALSE;
  314.  
  315.    d(("entered\n"))
  316.  
  317.    DOSBase = NULL;
  318.    UtilityBase = NULL;
  319.    gd->gd_Port = NULL;
  320.  
  321.    if (SysBase->lib_Version >= 37)
  322.    {
  323.       if (DOSBase = OpenLibrary("dos.library", 37))
  324.       {
  325.          if (UtilityBase = OpenLibrary("utility.library", 37))
  326.          {
  327.             if (gd->gd_Port = CreateMsgPort())
  328.             {
  329.                rc = TRUE;
  330.             }
  331.             else d(("no handler port\n"))
  332.          }
  333.          else d(("no utility V37\n"))
  334.       }
  335.       else d(("no dos V37\n"))
  336.    }
  337.    else d(("no exec V37\n"))
  338.  
  339.    d(("left: %ld\n",rc))
  340.  
  341.    return rc;
  342. }
  343. /*E*/
  344. /*F*/ static void closeres(GD gd)
  345. {
  346.    d(("freeing port\n"))
  347.    if (gd->gd_Port) DeleteMsgPort(gd->gd_Port);
  348.  
  349.    d(("closing dos\n"))
  350.    if (DOSBase) CloseLibrary(DOSBase);
  351.  
  352.    d(("closing utility\n"))
  353.    if (UtilityBase) CloseLibrary(UtilityBase);
  354. }
  355. /*E*/
  356.  
  357. /*F*/ BOOL getul(GD gd, UBYTE *s, LONG *number)
  358. {
  359.  
  360. #define IsDigit(c) ((c) >= '0' && (c) <= '9'))
  361. #define IsXDigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F'))
  362.  
  363.    BOOL hex, rc = TRUE;
  364.    ULONG num;
  365.    UBYTE c;
  366.    WORD len;
  367.  
  368.    if (len = strlen(s))
  369.    {
  370.       if (!Strnicmp(s, "0x", 2))
  371.       {
  372.          hex = TRUE;
  373.          s += 2;
  374.       }
  375.       else if (!Strnicmp(s, "$", 2))
  376.       {
  377.          hex = TRUE;
  378.          s++;
  379.       }
  380.       else hex = FALSE;
  381.  
  382.       for(num=0;*s;s++)
  383.       {
  384.          c = ToUpper(*s);
  385.          if (hex)
  386.          {
  387.             if (c >= '0' && c <= '9') num = num * 16 + c - '0';
  388.             else if (c >= 'A' && c <= 'F') num = num * 16 + c - '0';
  389.             else break;
  390.          }
  391.          else
  392.          {
  393.             if (c >= '0' && c <= '9') num = num * 10 + c - '0';
  394.             else break;
  395.          }
  396.       }
  397.  
  398.       if (*s)
  399.       {
  400.          if (c == 'K') num *= 1024;
  401.          else if (c == 'M') num *= 1024*1024;
  402.          else rc = FALSE;
  403.       }
  404.    }
  405.    else rc = FALSE;
  406.  
  407.    if (rc) *number = num;
  408.  
  409.    return rc;
  410. }
  411. /*E*/
  412. /*F*/ static void stream2rdargs(UBYTE *buffer)
  413. {
  414.    UBYTE *p;
  415.    enum { s_norm, s_esc, s_quote } s;
  416.  
  417.    for (p = buffer, s = s_norm; *p; p++)
  418.       switch(s)
  419.       {
  420.          case s_norm:
  421.             if (*p == '.') *p = '=';
  422.             if (*p == '/') *p = '\040';
  423.             else if (*p == '"') s = s_quote;
  424.          break;
  425.          case s_esc:
  426.             s = s_quote;
  427.          break;
  428.          case s_quote:
  429.             if (*p == '*') s = s_esc;
  430.             if (*p == '"') s = s_norm;
  431.          break;
  432.       }
  433. }
  434. /*E*/
  435. /*F*/ static BOOL streamspecs(GD gd, struct PrivateStreamData *psd, BPTR streamname, LONG *res)
  436. {
  437.    UBYTE *temp, *bstr, *start;
  438.    BOOL rc = FALSE;
  439.    LONG rdparam[ARG_COUNT];
  440.    struct RDArgs *inrda, *rda;
  441.  
  442.    bstr = (UBYTE *)BADDR(streamname);
  443.  
  444.    if (temp = AllocVec(bstr[0]+2, MEMF_ANY))
  445.    {
  446.       if (inrda = AllocDosObject(DOS_RDARGS, NULL))
  447.       {
  448.          strncpy(temp, bstr+1, bstr[0]);
  449.          temp[bstr[0]] = '\n';
  450.          temp[bstr[0]+1] = '\0';
  451.  
  452.          if (start = (UBYTE*)strchr((char*)temp, ':'))
  453.          {
  454.             stream2rdargs(++start);
  455.  
  456.             inrda->RDA_Source.CS_Buffer = start;
  457.             inrda->RDA_Source.CS_Length = strlen(start);
  458.             inrda->RDA_Source.CS_CurChr = 0;
  459.  
  460.             psd->psd_MaxLength = 0x7fffffff;
  461.             psd->psd_LoCyl = 0;
  462.             psd->psd_HiCyl = 0x7fffffff;
  463.             memset(rdparam, 0, ARG_COUNT*sizeof(LONG));
  464.             d(("readargs(%s)\n",start))
  465.             if (rda = ReadArgs((UBYTE*)STREAMNAME_TEMPLATE, rdparam, inrda))
  466.             {
  467.                rc = TRUE;
  468.  
  469.                strcpy(psd->psd_DOSName, (UBYTE*)rdparam[ARG_DOSNAME]);
  470.                if (rdparam[ARG_MAXLENGTH]) rc = getul(gd,(UBYTE*)rdparam[ARG_MAXLENGTH], &psd->psd_MaxLength);
  471.                if (rc && rdparam[ARG_LOCYL]) rc = getul(gd,(UBYTE*)rdparam[ARG_LOCYL], &psd->psd_LoCyl);
  472.                if (rc && rdparam[ARG_HICYL]) rc = getul(gd,(UBYTE*)rdparam[ARG_HICYL], &psd->psd_HiCyl);
  473.  
  474.                d(("after ReadArgs(): doshandler %s maxlen %lu locyl %lu hicyl %lu\n",
  475.                   psd->psd_DOSName,psd->psd_MaxLength,psd->psd_LoCyl,psd->psd_HiCyl))
  476.  
  477.                FreeArgs(rda);
  478.             }
  479.             else
  480.             {
  481.                d(("ReadArgs() failed\n"))
  482.                *res = ERROR_BAD_STREAM_NAME;
  483.             }
  484.          }
  485.          else
  486.          {
  487.             d(("no proper name\n"))
  488.             *res = ERROR_BAD_STREAM_NAME;
  489.          }
  490.  
  491.          FreeDosObject(DOS_RDARGS, inrda);
  492.       }
  493.       else
  494.       {
  495.          d(("no RDArgs\n"))
  496.          *res = ERROR_NO_FREE_STORE;
  497.       }
  498.  
  499.       FreeVec(temp);
  500.    }
  501.    else
  502.    {
  503.       d(("no more memory\n"))
  504.       *res = ERROR_NO_FREE_STORE;
  505.    }
  506.  
  507.    return rc;
  508. }
  509. /*E*/
  510.  
  511. /*F*/ static BOOL FindDevice(GD gd, struct PrivateStreamData *psd)
  512. {
  513.    struct DosList *dol;
  514.    struct FileSysStartupMsg *fssm=NULL;
  515.    BOOL rc = FALSE;
  516.    UBYTE *name;
  517.    UBYTE n;
  518.    UBYTE pat[40];
  519.  
  520.    d(("entered: %s\n", psd->psd_DOSName))
  521.  
  522.    n = strlen(psd->psd_DOSName);
  523.  
  524.    if (dol = LockDosList(LDF_READ | LDF_DEVICES))
  525.    {
  526.       while(dol = NextDosEntry(dol, LDF_DEVICES))
  527.       {
  528.          name = (UBYTE*)BADDR(dol->dol_Name);
  529.  
  530.          memset(pat,0,40);
  531.          strncpy(pat,name+1,name[0]);
  532.          d(("%s\n",pat))
  533.  
  534.          if ((n == name[0]) && !Strnicmp((char*)(name+1), psd->psd_DOSName, n))
  535.          {
  536.             d(("found\n"))
  537.  
  538.             fssm = (struct FileSysStartupMsg*)BADDR(dol->dol_misc.dol_handler.dol_Startup);
  539.  
  540.             if (fssm)
  541.             {
  542.                struct DosEnvec *de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
  543.  
  544.                d(("found fssm\n"))
  545.                   /* note: fssm->fssm_Device is a NUL terminated BSTR!! :-) */
  546.                strcpy((char*)psd->psd_Device, (char*)BADDR(fssm->fssm_Device)+1);
  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.                psd->psd_HiCyl = MIN(psd->psd_HiCyl, de->de_HighCyl);
  552.                psd->psd_LoCyl = MIN(psd->psd_LoCyl, psd->psd_HiCyl);
  553.                d(("de->de_BlocksPerTrack %ld, psd->psd_LoCyl %ld, de->de_Surfaces %ld, psd->psd_SectorSize %ld\n",
  554.                   de->de_BlocksPerTrack,psd->psd_LoCyl,de->de_Surfaces,psd->psd_SectorSize))
  555.                psd->psd_Offset = de->de_BlocksPerTrack * psd->psd_LoCyl * de->de_Surfaces * psd->psd_SectorSize;
  556.  
  557.                psd->psd_Len = de->de_BlocksPerTrack * psd->psd_SectorSize * (psd->psd_HiCyl - psd->psd_LoCyl + 1) * de->de_Surfaces;
  558.                psd->psd_Len = MIN(psd->psd_MaxLength, psd->psd_Len);
  559.                d(("len %lu\n",psd->psd_Len))
  560.  
  561.                d(("device %s, unit %ld, flags %ld, secsiz %ld, off %ld\n",
  562.                   psd->psd_Device,psd->psd_Unit,psd->psd_Flags,psd->psd_SectorSize,psd->psd_Offset))
  563.  
  564.                rc = TRUE;
  565.             }
  566.             else
  567.                d(("no fssm\n"))
  568.  
  569.             break;
  570.          }
  571.       }
  572.  
  573.       UnLockDosList(LDF_READ | LDF_DEVICES);
  574.    }
  575.  
  576.    return(rc);
  577. }
  578. /*E*/
  579.  
  580. /*F*/ static void __regargs OpenDH(GD gd, struct DosPacket *Pkt,ULONG *OpenCnt)
  581. {
  582.    struct FileHandle *FH;
  583.    struct PrivateStreamData *psd;
  584.    struct MsgPort *IOPort;
  585.    BOOL ok = FALSE;
  586.  
  587.    Pkt->dp_Res1 = DOSFALSE;
  588.    FH = (struct FileHandle *)BADDR(Pkt->dp_Arg1);
  589.    FH->fh_Port = (struct MsgPort *)FALSE;
  590.    FH->fh_Arg1 = 0L;
  591.  
  592.    d(("allocing psd\n"))
  593.    if (psd = AllocVec(sizeof(*psd),MEMF_PUBLIC|MEMF_CLEAR))
  594.    {
  595.       if (streamspecs(gd, psd, (BPTR)Pkt->dp_Arg3, &Pkt->dp_Res2))
  596.       {
  597.          d(("creating msgport\n"))
  598.          if (IOPort=CreateMsgPort())
  599.          {
  600.             if (psd->psd_IO=CreateIORequest(IOPort, sizeof(struct IOStdReq)))
  601.             {
  602.                if (FindDevice(gd, psd))
  603.                {
  604.                   if (OpenDevice(psd->psd_Device, psd->psd_Unit, (struct IORequest *)psd->psd_IO, psd->psd_Flags)==0L)
  605.                   {
  606.                      if (psd->psd_Buffer = AllocVec(psd->psd_SectorSize, psd->psd_BufMemType))
  607.                      {
  608.                         if (Pkt->dp_Type == ACTION_FINDOUTPUT)
  609.                         {
  610.                            psd->psd_Write = TRUE;
  611.                            psd->psd_IO->io_Command = CMD_WRITE;
  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 __regargs 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',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.          DoIO((struct IORequest *)psd->psd_IO);
  691.       }
  692.       psd->psd_IO->io_Command=CMD_UPDATE;
  693.  
  694.       d(("DoIO(CMD_UPDATE)\n"))
  695.       DoIO((struct IORequest *)psd->psd_IO);
  696.    }
  697.  
  698.    d(("FreeVec() buffer\n"))
  699.  
  700.    FreeVec(psd->psd_Buffer);
  701.  
  702.    d(("stopping motor off\n"))
  703.    psd->psd_IO->io_Command = TD_MOTOR;
  704.    psd->psd_IO->io_Length = 0L;
  705.    DoIO((struct IORequest *)psd->psd_IO);
  706.    d(("closing device\n"))
  707.    CloseDevice ((struct IORequest *)psd->psd_IO);
  708.  
  709.    d(("deleting msg port\n"))
  710.    DeleteMsgPort (psd->psd_IO->io_Message.mn_ReplyPort);
  711.  
  712.    d(("deleting stdio\n"))
  713.    DeleteIORequest (psd->psd_IO);
  714.  
  715.    d(("FreeVec() rh\n"))
  716.    FreeVec (psd);
  717.  
  718.    (*OpenCnt)--;
  719.  
  720.    d(("leaving closedh()\n"))
  721.  
  722. }
  723. /*E*/
  724.  
  725. /*F*/ static LONG __regargs RawRead(GD gd, struct PrivateStreamData *psd, UBYTE *Buffer, LONG Bytes, LONG *res2)
  726. {
  727.    LONG LatchBytes, RDBytes;
  728.    BOOL error = FALSE;
  729.  
  730.       /* check bouunds */
  731.    if ((psd->psd_Pos + Bytes) > psd->psd_Len) Bytes = psd->psd_Len - psd->psd_Pos;
  732.  
  733.    LatchBytes = Bytes;
  734.  
  735.    d(("read %ld bytes\n",Bytes))
  736.  
  737.    /*
  738.    ** first, read what's left in buffer
  739.    */
  740.    if (psd->psd_Left)
  741.    {
  742.       RDBytes=MIN(psd->psd_Left, Bytes);
  743.       CopyMem(psd->psd_Ptr, Buffer, RDBytes);
  744.  
  745.       Buffer += RDBytes;
  746.       Bytes -= RDBytes;
  747.  
  748.       psd->psd_Pos += RDBytes;   /* incr. position in file */
  749.       psd->psd_Ptr += RDBytes;
  750.       psd->psd_Left -= RDBytes;
  751.    }
  752.  
  753.    /*
  754.    ** second, try to read as much blocks as possible directly to
  755.    ** user buffer, avoiding CopyMem()
  756.    */
  757.    if (!error && (Bytes > psd->psd_SectorSize))
  758.    {
  759.       RDBytes = (Bytes / psd->psd_SectorSize) * psd->psd_SectorSize;
  760.  
  761.       psd->psd_IO->io_Data = Buffer;
  762.       psd->psd_IO->io_Length = RDBytes;
  763.       psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  764.       if (DoIO((struct IORequest *)psd->psd_IO))
  765.       {
  766.          RDBytes = psd->psd_IO->io_Actual;
  767.          error = TRUE;
  768.          *res2 = psd->psd_IO->io_Error;
  769.       }
  770.       Buffer += RDBytes;
  771.       Bytes -= RDBytes;
  772.  
  773.       psd->psd_Pos += RDBytes;         /* incr. position in file */
  774.       psd->psd_Left = 0;               /* for safety, initialise buffer */
  775.       psd->psd_Ptr = psd->psd_Buffer;
  776.    }
  777.  
  778.    if (!error && Bytes)
  779.    {
  780.       /*
  781.       ** now there are only some bytes < SectorSize left, so they fit into one buffer
  782.       ** So, read a buffer and copy some bytes from it to user-buffer.
  783.       */
  784.       RDBytes = Bytes;
  785.       psd->psd_IO->io_Length = psd->psd_SectorSize;
  786.       psd->psd_IO->io_Data = psd->psd_Buffer;
  787.       psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  788.  
  789.       if (DoIO((struct IORequest *)psd->psd_IO))
  790.       {
  791.          *res2 = psd->psd_IO->io_Error;
  792.          RDBytes = psd->psd_IO->io_Actual;
  793.       }
  794.  
  795.       CopyMem(psd->psd_Buffer, Buffer, RDBytes);
  796.  
  797.       psd->psd_Pos += RDBytes;
  798.       psd->psd_Ptr = psd->psd_Buffer + RDBytes;
  799.       psd->psd_Left = psd->psd_SectorSize - RDBytes;
  800.  
  801.       Bytes -= RDBytes;
  802.    }
  803.  
  804.    return LatchBytes - Bytes;
  805. }
  806. /*E*/
  807. /*F*/ static LONG __regargs RawWrite(GD gd, struct PrivateStreamData *psd,UBYTE *Buffer,LONG Bytes, LONG *res2)
  808. {
  809.    LONG LatchBytes,WRBytes;
  810.    BOOL error = FALSE;
  811.  
  812.       /* check bounds */
  813.    if ((psd->psd_Pos + Bytes) > psd->psd_Len) Bytes = psd->psd_Len-psd->psd_Pos;
  814.  
  815.    LatchBytes = Bytes;
  816.  
  817.    d(("write %ld bytes\n",Bytes))
  818.  
  819.    /*
  820.    ** first, take care for outstanding data
  821.    */
  822.    if (Bytes && psd->psd_Left)
  823.    {
  824.       WRBytes = MIN(psd->psd_Left, Bytes);
  825.       CopyMem(Buffer, psd->psd_Ptr, WRBytes);
  826.  
  827.       psd->psd_Ptr += WRBytes;      /* incr. position in buffer */
  828.       psd->psd_Left -= WRBytes;     /* decr. number of unused bytes */
  829.  
  830.       if (psd->psd_Left == 0)       /* Buffer full ? */
  831.       {                             /* then write it out */
  832.          psd->psd_IO->io_Data = psd->psd_Buffer;
  833.          psd->psd_IO->io_Length = psd->psd_SectorSize;
  834.          psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  835.          psd->psd_IO->io_Command = CMD_WRITE;
  836.          if (DoIO((struct IORequest *)psd->psd_IO))
  837.          {
  838.             *res2 = psd->psd_IO->io_Error;
  839.             WRBytes = psd->psd_IO->io_Actual;
  840.             error = TRUE;
  841.          }
  842.  
  843.          psd->psd_Ptr = psd->psd_Buffer;  /* reset buffer pointers */
  844.          psd->psd_Left = 0;
  845.       }
  846.  
  847.       Buffer += WRBytes;
  848.       Bytes -= WRBytes;
  849.       psd->psd_Pos += WRBytes;      /* incr. position in file */
  850.    }
  851.  
  852.    if (!error && Bytes)
  853.    {
  854.       /*
  855.       ** second, try to write as much blocks as possible directly from
  856.       ** user buffer in one go, avoiding CopyMem() and multiple I/O-Requests
  857.       */
  858.       if (Bytes > psd->psd_SectorSize)
  859.       {
  860.             /* I don't like to use bit masking at this point */
  861.          WRBytes = (Bytes / psd->psd_SectorSize) * psd->psd_SectorSize;
  862.  
  863.          psd->psd_IO->io_Data = Buffer;
  864.          psd->psd_IO->io_Length = WRBytes;
  865.          psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  866.          psd->psd_IO->io_Command = CMD_WRITE;
  867.          if (DoIO((struct IORequest *)psd->psd_IO))
  868.          {
  869.             *res2 = psd->psd_IO->io_Error;
  870.             WRBytes = psd->psd_IO->io_Actual;
  871.             error = TRUE;
  872.          }
  873.  
  874.          Buffer += WRBytes;
  875.          Bytes -= WRBytes;
  876.          psd->psd_Pos += WRBytes;   /* incr. position in file */
  877.  
  878.          psd->psd_Ptr = psd->psd_Buffer;  /* for safety, reset buffer pointers */
  879.          psd->psd_Left = 0;
  880.       }
  881.    }
  882.  
  883.    if (!error && Bytes)
  884.    {
  885.       /*
  886.       ** now there are only some bytes < SectorSize left, and they fit into one
  887.       ** buffer.
  888.       ** NOTE: the actual writing is delayed to Close() or further Write()'s
  889.       */
  890.       WRBytes = Bytes;
  891.       CopyMem(Buffer, psd->psd_Buffer, WRBytes);
  892.  
  893.       psd->psd_Pos += WRBytes;     /* incr. position in file */
  894.       Bytes -= WRBytes;
  895.       Buffer += WRBytes;
  896.  
  897.       psd->psd_Ptr = psd->psd_Buffer + WRBytes;     /* set position in buffer */
  898.       psd->psd_Left = psd->psd_SectorSize - WRBytes; /* set number of unused bytes */
  899.    }
  900.  
  901.    return LatchBytes - Bytes;
  902. }
  903. /*E*/
  904.  
  905. /*F*/ static ULONG main(void)
  906. {
  907.    struct GlobalData GlobalData;
  908.    struct GlobalData *gd;
  909.  
  910.    struct DosPacket *Pkt;
  911.    BOOL Done;
  912.    ULONG OpenCnt;
  913.  
  914.    gd = &GlobalData;
  915.  
  916.    d(("Hello, this is the DEV-Handler\n"))
  917.  
  918.    SysBase = *(struct Library**)4L;
  919.  
  920.    if ((gd->gd_We = (struct Process *)FindTask(NULL))->pr_CLI) return RETURN_FAIL;
  921.  
  922.    d(("waiting for startup-packet...\n"))
  923.    Pkt = WaitDosPacket(gd, &gd->gd_We->pr_MsgPort);
  924.  
  925.    if (openres(gd))
  926.    {
  927.       gd->gd_DosList = (struct DosList *)BADDR(Pkt->dp_Arg3);
  928.       gd->gd_DosList->dol_Task = gd->gd_Port;
  929.  
  930.       d(("replying startup-packet...\n"))
  931.       ReplyDosPacket(gd, gd->gd_Port, Pkt, DOSTRUE, Pkt->dp_Res2);
  932.  
  933.       Done=FALSE;
  934.       OpenCnt=0L;
  935.  
  936.       d(("entering mainloop\n"))
  937.  
  938.       while (!Done)
  939.       {
  940.          Pkt=WaitDosPacket(gd, gd->gd_Port);
  941.  
  942.          d(("got packet %ld\n",Pkt->dp_Type))
  943.  
  944.          Pkt->dp_Res1 = DOSFALSE;
  945.          Pkt->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  946.  
  947.          switch (Pkt->dp_Type)
  948.          {
  949.             case ACTION_FINDINPUT:
  950.             case ACTION_FINDOUTPUT:
  951.                OpenDH (gd, Pkt, &OpenCnt);
  952.                ReplyDosPacket(gd, gd->gd_Port,Pkt, Pkt->dp_Res1, Pkt->dp_Res2);
  953.             break;
  954.  
  955.             case ACTION_END:
  956.                CloseDH (gd, (struct PrivateStreamData *)Pkt->dp_Arg1,&OpenCnt);
  957.                ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSTRUE, 0);
  958.             break;
  959.  
  960.             case ACTION_READ:
  961.             {
  962.                struct PrivateStreamData *psd = (struct PrivateStreamData *)Pkt->dp_Arg1;
  963.  
  964.                if (psd && !psd->psd_Write)
  965.                {
  966.                   LONG Bytes, error;
  967.  
  968.                   Bytes = RawRead(gd, (struct PrivateStreamData *)Pkt->dp_Arg1,
  969.                                       (UBYTE *)Pkt->dp_Arg2,Pkt->dp_Arg3, &error);
  970.  
  971.                   ReplyDosPacket(gd, gd->gd_Port,Pkt, Bytes, error);
  972.                }
  973.             }
  974.             break;
  975.  
  976.             case ACTION_WRITE:
  977.             {
  978.                struct PrivateStreamData *psd = (struct PrivateStreamData *)Pkt->dp_Arg1;
  979.  
  980.                if (psd && psd->psd_Write)
  981.                {
  982.                   LONG Bytes, error;
  983.  
  984.                   Bytes = RawWrite(gd, (struct PrivateStreamData *)Pkt->dp_Arg1,
  985.                                        (UBYTE *)Pkt->dp_Arg2, Pkt->dp_Arg3, &error);
  986.  
  987.                   ReplyDosPacket(gd, gd->gd_Port,Pkt, Bytes, error);
  988.                }
  989.             }
  990.             break;
  991.  
  992.             case ACTION_IS_FILESYSTEM:
  993.                ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE, 0);
  994.             break;
  995.  
  996.             case ACTION_SEEK:
  997.             case ACTION_SET_FILE_SIZE:
  998.                ReplyDosPacket(gd, gd->gd_Port,Pkt, -1,ERROR_ACTION_NOT_KNOWN);
  999.             break;
  1000.  
  1001.             case ACTION_DIE:
  1002.                if (OpenCnt==0L)
  1003.                {
  1004.                   d(("opencnt = 0\n"))
  1005.  
  1006.                   if (IsListEmpty(&gd->gd_Port->mp_MsgList))
  1007.                   {
  1008.                      gd->gd_DosList->dol_Task = NULL;
  1009.  
  1010.                      ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSTRUE, 0);
  1011.  
  1012.                      Done=TRUE;
  1013.                   }
  1014.                   else ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE,ERROR_OBJECT_IN_USE);
  1015.                }
  1016.                else ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE,ERROR_OBJECT_IN_USE);
  1017.             break;
  1018.  
  1019.             default:
  1020.                ReplyDosPacket(gd, gd->gd_Port, Pkt, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
  1021.             break;
  1022.          }
  1023.       }
  1024.    }
  1025.    else ReplyDosPacket(gd, &gd->gd_We->pr_MsgPort, Pkt, DOSFALSE, ERROR_NO_FREE_STORE);
  1026.  
  1027.    closeres(gd);
  1028.  
  1029.    d(("returning\n"))
  1030.  
  1031.    return RETURN_OK;
  1032. }
  1033. /*E*/
  1034.  
  1035.