home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 18 / amigaformatcd18.iso / -in_the_mag- / emulation / emus / handlers / amicdfilesystem / src / device.c < prev    next >
C/C++ Source or Header  |  1997-07-31  |  42KB  |  1,717 lines

  1. /* device.c:
  2.  *
  3.  * Handler for ISO-9660 (+ Rock Ridge) + HFS CDROM filing system.
  4.  * Originally based on DOSDEV V1.10 (2 Nov 87) by Matthew Dillon.
  5.  * Major changes made by Nicola Salmoria.
  6.  *
  7.  * ----------------------------------------------------------------------
  8.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  9.  * All rights reserved.
  10.  * This software may be freely distributed and redistributed for
  11.  * non-commercial purposes, provided this notice is included.
  12.  * ----------------------------------------------------------------------
  13.  * [History removed]
  14.  */
  15.  
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <exec/memory.h>
  19. #include <exec/execbase.h>
  20. #include <exec/resident.h>
  21. #include <dos/dosextens.h>
  22. #include <dos/dostags.h>
  23. #include <dos/filehandler.h>
  24. #include <devices/timer.h>
  25. #include <devices/input.h>
  26. #include <devices/inputevent.h>
  27. #include <devices/trackdisk.h>
  28. #include <utility/date.h>
  29. #include <intuition/intuitionbase.h>
  30. #include <workbench/workbench.h>
  31. #include <resources/filesysres.h>
  32. #include <clib/alib_protos.h>
  33. #include <proto/dos.h>
  34. #include <proto/exec.h>
  35. #include <proto/utility.h>
  36. #include <proto/intuition.h>
  37. #include <proto/icon.h>
  38. #include <proto/wb.h>
  39.  
  40. #include "cdrom.h"
  41. #include "generic.h"
  42. #include "rock.h"
  43.  
  44. #define VERSION 37
  45. #define REVISION 5
  46. static const UBYTE versionstring20[] = "\0$VER: amicdfilesystem 37.5 (2.10.94)";
  47.  
  48.  
  49. /*
  50.  * The only purpose of this Resident structure is to make
  51.  * Version CD0:
  52.  * return the version number of the filesystem.
  53.  */
  54. static const struct Resident versiontag =
  55. {
  56.     RTC_MATCHWORD,
  57.     &versiontag,
  58.     &versiontag + 1,
  59.     0,
  60.     VERSION,
  61.     0,
  62.     -81,
  63.     NULL,
  64.     &versionstring20[7],
  65.     NULL
  66. };
  67.  
  68.  
  69. /* the only global data used is library bases, therefore this code is */
  70. /* reentrant, and could be run several times. If we added the filesystem */
  71. /* to the filesystem resource, one instance would be used for multiple */
  72. /* devices. */
  73.  
  74. struct ExecBase *SysBase;
  75. struct DosLibrary *DOSBase;
  76. struct Library *UtilityBase;
  77. struct IntuitionBase *IntuitionBase;
  78. struct Library *InputBase;
  79. struct Library *IconBase;
  80. struct Library *WorkbenchBase;
  81.  
  82.  
  83.  
  84. /* global data is kept in the HData structure, instead, which is located */
  85. /* on the stack. */
  86.  
  87. struct HConfig
  88. {
  89.     BOOL UseTrackdisk;            /* Use trackdisk calls instead of SCSI-direct */
  90.  
  91.     BOOL Lowercase;                /* Map ISO names to lower case */
  92.  
  93.     ULONG ScanInterval;            /* Time between successive diskchange checks */
  94. };
  95.  
  96. struct HData
  97. {
  98.     struct MsgPort *MyPort;        /* our handler port */
  99.     struct DosList *MyDevNode;        /* our device node */
  100.     struct FileSysStartupMsg *fssm;
  101.     struct DosEnvec *envec;
  102.     struct DosList *CurrentVolume;     /* current volume, or NULL */
  103.     BPTR LockList;            /* list of open locks */
  104.     LONG DiskInserted;        /* see #defines below */
  105.     LONG Inhibited;            /* !0 if the volume is inhibited (nesting count) */
  106.  
  107.     CDROM *CD;
  108.     VOLUME *CDVolume;
  109.     CDROM_OBJ *TopLevelObj;
  110.  
  111.     UBYTE VolumeName[40];        /* When a dos disk is inserted, contains the */
  112.                                 /* volume name in BCPL form. */
  113.                                 /* When an audio disk is inserted, contains */
  114.                                 /* tha name which will be used for the AppIcon, */
  115.                                 /* for example CD0:CDDA */
  116.  
  117.     struct AppIcon *AppIcon;    /* CDDA AppIcon */
  118.     struct MsgPort *AppPort;    /* MsgPort used by the AppIcon */
  119.  
  120.     struct MsgPort *TimerPort;        /* timer.device I/O port */
  121.     struct timerequest *TimerIO;    /* timer.device I/O request */
  122.     struct IOStdReq *InputIO;        /* input.device I/O request */
  123.  
  124.     UBYTE PlayCDDA[128];            /* Command invoked if appicon is activated */
  125.                                     /* (initialized by Show_CDDA_Icon()) */
  126.     BOOL Playing;                /* TRUE if a CDDA disk is playing */
  127.     BOOL pad;
  128.  
  129.     struct HConfig HConfig;        /* configuration */
  130. };
  131.  
  132.  
  133. /* allowed values for the DiskInserted field */
  134.  
  135. #define DI_NO_DISK 0        /* no disk in the drive */
  136. #define DI_DISK_OK 1        /* disk in drive */
  137. #define DI_UNREADABLE_DISK 2    /* disk in drive, but couldn't be read for some reason */
  138. #define DI_CDDA_DISK 3        /* CDDA disk in drive */
  139.  
  140.  
  141.  
  142.  
  143. ULONG Centrypoint(VOID);
  144.  
  145. VOID ReturnPacket(struct DosPacket *packet,struct MsgPort *port,LONG res1,LONG res2);
  146. VOID AddToFSResource(ULONG dostype,BPTR seglist);
  147. void btos(LONG, char *);
  148. CDROM_OBJ *OpenObject(BPTR parentlock,BSTR name,struct HData *HData);
  149. BPTR cdlock(CDROM_OBJ *, int,struct HData *HData);
  150. void cdunlock(BPTR lock,struct HData *HData);
  151. LONG CheckLock(BPTR lock,struct HData *HData);
  152. CDROM_OBJ *getlockfile(BPTR lock,struct HData *HData);
  153. int Check_For_Volume_Name_Prefix (char *);
  154. VOID Fill_InfoData(struct InfoData *id,struct HData *HData);
  155. void Fill_FileInfoBlock (struct FileInfoBlock *, CDROM_INFO *, VOLUME *,struct HData *HData);
  156. void Mount(struct HData *HData);
  157. struct DosList *CreateVolumeNode(struct HData *HData);
  158. void RemoveVolumeNode (struct HData *HData);
  159. VOID RemoveDosList(struct DosList *vol);
  160. void Check_Disk (struct HData *HData);
  161. void Send_Timer_Request(struct HData *HData);
  162. int Open_Timer_Device(struct HData *HData);
  163. int Open_Input_Device(struct HData *HData);
  164. VOID CreateInputEvent(BOOL inserted,struct HData *HData);
  165. int Get_Startup (struct HData *HData);
  166.  
  167. VOID Display_Error(UBYTE *text,APTR par1, ...);
  168. VOID Show_CDDA_Icon(struct HData *HData);
  169. VOID Hide_CDDA_Icon (struct HData *HData);
  170.  
  171. ULONG _stackswap(ULONG function(),...);
  172.  
  173.  
  174.  
  175.  
  176. ULONG entrypoint(VOID)
  177. {
  178. /* we must always swap the stack because when mounted from RDB we will get */
  179. /* only 600 bytes of stack. */
  180. return(_stackswap(Centrypoint));
  181. }
  182.  
  183.  
  184.  
  185. ULONG __saveds Centrypoint(VOID)
  186. {
  187. struct DosPacket *packet;
  188. struct Process *process;
  189. struct HData HData;
  190. LONG timercount = 0;
  191.  
  192.  
  193. SysBase = *((struct ExecBase **)4);
  194.  
  195. process = (struct Process *)FindTask(NULL);
  196. /* if we were run from a shell, fail */
  197. if (process->pr_CLI) return(RETURN_FAIL);
  198.  
  199. WaitPort(&process->pr_MsgPort);        /* get startup packet */
  200. packet = (struct DosPacket *)GetMsg(&process->pr_MsgPort)->mn_Node.ln_Name;
  201.  
  202. memset(&HData,0,sizeof(struct HData));
  203.  
  204. if (!(HData.fssm = BADDR(packet->dp_Arg2)) ||
  205.         !(HData.envec = BADDR(HData.fssm->fssm_Environ)) ||
  206.     /* make sure that the mountlist has enough fields */
  207.         HData.envec->de_TableSize < DE_DOSTYPE)
  208. {
  209.     Forbid();
  210.     ReturnPacket(packet,&process->pr_MsgPort,DOSFALSE,0);
  211.     return(0);        /* exit */
  212. }
  213.  
  214. HData.MyDevNode = BADDR(packet->dp_Arg3);
  215.  
  216. /* add the seglist to the filesystem.resource so it will be reused by other */
  217. /* devices with the same DosType */
  218. AddToFSResource(HData.envec->de_DosType,HData.MyDevNode->dol_misc.dol_handler.dol_SegList);
  219.  
  220. if (SysBase->LibNode.lib_Version < 37 ||
  221.         !(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37)) ||
  222.         !(UtilityBase = OpenLibrary("utility.library",37)) ||
  223.         !(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)) ||
  224.         !(HData.MyPort = CreateMsgPort()) ||
  225.         !Open_Timer_Device(&HData) ||
  226.         !Open_Input_Device(&HData) ||
  227.         !Get_Startup(&HData))
  228. {
  229.     if (DOSBase)
  230.     {
  231.         DeleteMsgPort(HData.MyPort);
  232.         CloseLibrary(IntuitionBase);
  233.         CloseLibrary(UtilityBase);
  234.         CloseLibrary(DOSBase);
  235.     }
  236.     Forbid();
  237.     ReturnPacket(packet,&process->pr_MsgPort,DOSFALSE,0);
  238.     return(0);        /* exit */
  239. }
  240.  
  241. /* initialize dn_Task so that DOS won't start a new process for every access */
  242. HData.MyDevNode->dol_Task = HData.MyPort;
  243.  
  244. ReturnPacket(packet,HData.MyPort,DOSTRUE,0);
  245.  
  246. Send_Timer_Request(&HData);
  247.  
  248. Check_Disk(&HData);
  249.  
  250.  
  251. for (;;)
  252. {
  253.     ULONG dossignal,appsignal,timersignal,sigrec;
  254.  
  255.  
  256.     dossignal = 1L << HData.MyPort->mp_SigBit;
  257.     appsignal = HData.AppPort ? 1L << HData.AppPort->mp_SigBit : 0;
  258.     timersignal = 1L << HData.TimerPort->mp_SigBit;
  259.  
  260.     sigrec = Wait(dossignal | timersignal | appsignal | SIGBREAKF_CTRL_F);
  261.  
  262.     if (sigrec & SIGBREAKF_CTRL_F)
  263.     {
  264. D(kprintf("diskchange interrupt!\n"));
  265.         Check_Disk(&HData);
  266.     }
  267.  
  268.     if (sigrec & timersignal)
  269.     {
  270.         if (HData.HConfig.ScanInterval)
  271.         {
  272.             if (++timercount == HData.HConfig.ScanInterval)
  273.             {
  274.                 Check_Disk(&HData);
  275.  
  276.                 timercount = 0;
  277.             }
  278.         }
  279.  
  280. /* turn off the motor if it is on (Motor_Off() knows whether it's on) */
  281.         Motor_Off(HData.CD);
  282.  
  283. /* retry to display the AppIcon, in case something went wrong before */
  284.         if (HData.DiskInserted == DI_CDDA_DISK) Show_CDDA_Icon(&HData);
  285.  
  286.         GetMsg(HData.TimerPort);
  287.         Send_Timer_Request(&HData);
  288.     }
  289.  
  290.     if (sigrec & appsignal)
  291.     {
  292.         struct Message *msg;
  293.  
  294.  
  295.         while (msg = GetMsg(HData.AppPort))
  296.         {
  297.             ReplyMsg (msg);
  298.             if (HData.PlayCDDA[0])
  299.                 SystemTags(HData.PlayCDDA,
  300.                         SYS_Input,Open("NIL:",MODE_OLDFILE),
  301.                         SYS_Output,Open("NIL:",MODE_NEWFILE),
  302.                         SYS_Asynch,TRUE,
  303.                     TAG_END);
  304.             else
  305.             {
  306.                 int res;
  307.  
  308.  
  309.                 if (HData.Playing) res = Stop_Play_Audio(HData.CD);
  310.                 else res = Start_Play_Audio(HData.CD);
  311.  
  312.                 if (res) HData.Playing = !HData.Playing;
  313.             }
  314.         }
  315.     }
  316.  
  317.     if (sigrec & dossignal)
  318.     {
  319.         struct Message *msg;
  320.  
  321.  
  322.         while (msg = GetMsg(HData.MyPort))
  323.         {
  324.             LONG res1,res2;
  325.  
  326.  
  327.             packet = (struct DosPacket *)msg->mn_Node.ln_Name;
  328.  
  329.             switch (packet->dp_Type)
  330.             {
  331.             case ACTION_FINDINPUT:
  332.             case ACTION_FINDUPDATE:
  333.             case ACTION_FINDOUTPUT:
  334. D(switch (packet->dp_Type)
  335.     {
  336.     case ACTION_FINDUPDATE:
  337.         kprintf("ACTION_FINDUPDATE fh %lx lock %lx name \"%b\" ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3);
  338.         break;
  339.     case ACTION_FINDINPUT:
  340.         kprintf("ACTION_FINDINPUT fh %lx lock %lx name \"%b\" ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3);
  341.         break;
  342.     case ACTION_FINDOUTPUT:
  343.         kprintf("ACTION_FINDOUTPUT fh %lx lock %lx name \"%b\" ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3);
  344.         break;
  345.     }
  346. )
  347.                 res1 = DOSFALSE;
  348.                 if (!(res2 = CheckLock(packet->dp_Arg2,&HData)))
  349.                 {
  350.                     CDROM_OBJ *obj;
  351.  
  352.  
  353.                     if (!(obj = OpenObject(packet->dp_Arg2,packet->dp_Arg3,&HData)))
  354.                     {
  355.                         res2 = IoErr();
  356.                         if (res2 == ERROR_OBJECT_NOT_FOUND &&
  357.                                 packet->dp_Type == ACTION_FINDOUTPUT)
  358.                             res2 = ERROR_DISK_WRITE_PROTECTED;
  359.                         else if (res2 == TDERR_DiskChanged)
  360.                             res2 = packet->dp_Arg2 ? ERROR_DEVICE_NOT_MOUNTED : ERROR_NO_DISK;
  361.                     }
  362.                     else
  363.                     {
  364.                         if (packet->dp_Type == ACTION_FINDOUTPUT)
  365.                         {
  366.                             Close_Object(obj);
  367.                             res2 = ERROR_DISK_WRITE_PROTECTED;
  368.                         }
  369.                         else if (obj->directory_f)
  370.                         {
  371.                             Close_Object(obj);
  372.                             res2 = ERROR_OBJECT_WRONG_TYPE;
  373.                         }
  374.                         else
  375.                         {
  376.                 /* make a lock out of the object, this way the icon will not */
  377.                 /* disappear from the Workbench if there are files open */
  378.                             if (((struct FileHandle *)BADDR(packet->dp_Arg1))->fh_Args =
  379.                                     cdlock(obj,ACCESS_READ,&HData))
  380.                                 res1 = DOSTRUE;
  381.                             else res2 = ERROR_NO_FREE_STORE;
  382.                         }
  383.                     }
  384.                 }
  385.                 break;
  386.  
  387.             case ACTION_FH_FROM_LOCK:
  388. D(kprintf("ACTION_FH_FROM_LOCK fh %lx lock %lx ->\n",packet->dp_Arg1,packet->dp_Arg2));
  389.                 res1 = DOSFALSE;
  390.                 if (!(res2 = CheckLock(packet->dp_Arg2,&HData)))
  391.                 {
  392.                     CDROM_OBJ *obj = getlockfile(packet->dp_Arg2,&HData);
  393.  
  394.  
  395.                     if (obj->directory_f)
  396.                         res2 = ERROR_OBJECT_WRONG_TYPE;
  397.                     else
  398.                     {
  399.                         ((struct FileHandle *)BADDR(packet->dp_Arg1))->fh_Args = packet->dp_Arg2;
  400.                         res1 = DOSTRUE;
  401.                     }
  402.                 }
  403.                 break;
  404.  
  405.             case ACTION_END:
  406. D(kprintf("ACTION_END fh_Args %lx ->\n",packet->dp_Arg1));
  407.                 res1 = DOSFALSE;
  408.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  409.                 {
  410.                     cdunlock(packet->dp_Arg1,&HData);
  411.                     res1 = DOSTRUE;
  412.                 }
  413.                 break;
  414.  
  415.             case ACTION_READ:
  416. D(kprintf("ACTION_READ fh_Args %lx buffer %lx len %ld ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3));
  417.                 res1 = -1;
  418.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  419.                 {
  420.                     res1 = Read_From_File(HData.CDVolume,
  421.                             getlockfile(packet->dp_Arg1,&HData),
  422.                             (APTR)packet->dp_Arg2,packet->dp_Arg3);
  423.                     res2 = IoErr();
  424.                     if (res2 == TDERR_DiskChanged)
  425.                         res2 = ERROR_DEVICE_NOT_MOUNTED;
  426.  
  427. if (res1 > 0) res2 = 0;
  428.                 }
  429.                 break;
  430.  
  431.             case ACTION_SEEK:
  432. D(kprintf("ACTION_SEEK fh_Args %lx pos %ld offs %ld ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3));
  433.                 res1 = -1;
  434.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  435.                 {
  436.                     CDROM_OBJ *obj = getlockfile(packet->dp_Arg1,&HData);
  437.  
  438.  
  439.                     res1 = obj->pos;
  440.                     if (res2 = Seek_Position(obj,packet->dp_Arg2,packet->dp_Arg3))
  441.                         res1 = -1;
  442.                 }
  443.                 break;
  444.  
  445.             case ACTION_LOCATE_OBJECT:
  446. D(kprintf("ACTION_LOCATE_OBJECT lock %lx name \"%b\" mode %ld ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3));
  447.                 res1 = NULL;
  448.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  449.                 {
  450.                     CDROM_OBJ *obj;
  451.  
  452.  
  453.                     if (!(obj = OpenObject(packet->dp_Arg1,packet->dp_Arg2,&HData)))
  454.                     {
  455.                         res2 = IoErr();
  456.                         if (res2 == TDERR_DiskChanged)
  457.                             res2 = packet->dp_Arg1 ? ERROR_DEVICE_NOT_MOUNTED : ERROR_NO_DISK;
  458.                     }
  459.                     else
  460.                     {
  461.                         if (!(res1 = cdlock(obj,packet->dp_Arg3,&HData)))
  462.                             res2 = ERROR_NO_FREE_STORE;
  463.                     }
  464.                 }
  465.                 break;
  466.  
  467.             case ACTION_FREE_LOCK:
  468. D(kprintf("ACTION_FREE_LOCK lock %lx ->\n",packet->dp_Arg1));
  469.                 cdunlock(packet->dp_Arg1,&HData);
  470.                 res1 = DOSTRUE;
  471.                 break;
  472.  
  473.             case ACTION_COPY_DIR:
  474.             case ACTION_COPY_DIR_FH:
  475. D(switch (packet->dp_Type)
  476.     {
  477.     case ACTION_COPY_DIR:
  478.         kprintf("ACTION_COPY_DIR lock %lx ->\n",packet->dp_Arg1);
  479.         break;
  480.     case ACTION_COPY_DIR_FH:
  481.         kprintf("ACTION_COPY_DIR_FH fh_Args %lx ->\n",packet->dp_Arg1);
  482.         break;
  483.     }
  484. )
  485.                 res1 = NULL;
  486.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)) && packet->dp_Arg1)
  487.                 {
  488.                     CDROM_OBJ *new;
  489.  
  490.  
  491.                     if (!(new = Clone_Object(getlockfile(packet->dp_Arg1,&HData))))
  492.                         res2 = ERROR_NO_FREE_STORE;
  493.                     else
  494.                     {
  495.                         if (!(res1 = cdlock(new,ACCESS_READ,&HData)))
  496.                             res2 = ERROR_NO_FREE_STORE;
  497.                     }
  498.                 }
  499.                 break;
  500.  
  501.             case ACTION_PARENT:
  502.             case ACTION_PARENT_FH:
  503. D(switch (packet->dp_Type)
  504.     {
  505.     case ACTION_PARENT:
  506.         D(kprintf("ACTION_PARENT lock %lx ->\n",packet->dp_Arg1));
  507.         break;
  508.     case ACTION_PARENT_FH:
  509.         kprintf("ACTION_PARENT_FH fh_Args %lx ->\n",packet->dp_Arg1);
  510.         break;
  511.     }
  512. )
  513.                 res1 = NULL;
  514.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  515.                 {
  516.                     if (packet->dp_Arg1)
  517.                     {
  518.                         CDROM_OBJ *obj = getlockfile(packet->dp_Arg1,&HData);
  519.                         CDROM_OBJ *parent;
  520.  
  521.  
  522.                         if (Is_Top_Level_Object(HData.CDVolume,obj))
  523.                             res2 = 0;
  524.                         else
  525.                         {
  526.                             if (!(parent = Find_Parent(HData.CDVolume,obj)))
  527.                             {
  528.                                 res2 = IoErr();
  529.                                 if (res2 == TDERR_DiskChanged)
  530.                                     res2 = ERROR_DEVICE_NOT_MOUNTED;
  531.                             }
  532.                             else
  533.                             {
  534.                                 if (!(res1 = cdlock(parent,ACCESS_READ,&HData)))
  535.                                     res2 = ERROR_NO_FREE_STORE;
  536.                             }
  537.                         }
  538.                     }
  539.                     else
  540.                         res2 = ERROR_OBJECT_NOT_FOUND;
  541.                 }
  542.                 break;
  543.  
  544.             case ACTION_SAME_LOCK: /*    Lock  Lock                 Bool       */
  545.                 {
  546.                     CDROM_OBJ *obj1 = getlockfile(packet->dp_Arg1,&HData);
  547.                     CDROM_OBJ *obj2 = getlockfile(packet->dp_Arg2,&HData);
  548.                     struct FileLock *plock1,*plock2;
  549.  
  550. D(kprintf("ACTION_SAME_LOCK lock1 %lx lock2 %lx ->\n",packet->dp_Arg1,packet->dp_Arg2));
  551.  
  552.                     plock1 = BADDR(packet->dp_Arg1);
  553.                     plock2 = BADDR(packet->dp_Arg2);
  554.  
  555.                     if (plock1->fl_Volume != plock2->fl_Volume)
  556.                         res1 = DOSFALSE;
  557.                     else if (Same_Objects(obj1,obj2))
  558.                         res1 = DOSTRUE;
  559.                     else
  560.                         res1 = DOSFALSE;
  561.  
  562.                     res2 = 0;
  563.                 }
  564.                 break;
  565.  
  566.             case ACTION_EXAMINE_OBJECT:
  567.             case ACTION_EXAMINE_FH:
  568. D(switch (packet->dp_Type)
  569.     {
  570.     case ACTION_EXAMINE_OBJECT:
  571.         kprintf("ACTION_EXAMINE_OBJECT lock %lx fib %lx ->\n",packet->dp_Arg1,packet->dp_Arg2);
  572.         break;
  573.     case ACTION_EXAMINE_FH:
  574.         kprintf("ACTION_EXAMINE_FH fh_Args %lx fib %lx ->\n",packet->dp_Arg1,packet->dp_Arg2);
  575.         break;
  576.     }
  577. )
  578.                 res1 = DOSFALSE;
  579.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  580.                 {
  581.                     struct FileInfoBlock *fib;
  582.                     CDROM_INFO info;
  583.  
  584.  
  585.                     fib = BADDR(packet->dp_Arg2);
  586.                     memset(fib,0,sizeof(struct FileInfoBlock));
  587.                     if (!(res2 = CDROM_Info(HData.CDVolume,
  588.                             getlockfile(packet->dp_Arg1,&HData),&info)))
  589.                     {
  590.                         Fill_FileInfoBlock(fib,&info,HData.CDVolume,&HData);
  591.                         res1 = DOSTRUE;
  592.                     }
  593.                 }
  594.                 break;
  595.  
  596.             case ACTION_EXAMINE_NEXT:
  597. D(kprintf("ACTION_EXAMINE_NEXT lock %lx fib %lx (%s) ->\n",packet->dp_Arg1,packet->dp_Arg2,&((struct FileInfoBlock *)BADDR(packet->dp_Arg2))->fib_FileName[1]));
  598.  
  599.                 res1 = DOSFALSE;
  600.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  601.                 {
  602.                     struct FileInfoBlock *fib;
  603.                     CDROM_OBJ *dir = getlockfile(packet->dp_Arg1,&HData);
  604.                     CDROM_INFO info;
  605.  
  606.  
  607.                     fib = BADDR(packet->dp_Arg2);
  608.                     if (!dir->directory_f)
  609.                         res2 = ERROR_OBJECT_WRONG_TYPE;
  610.                     else if (res2 = Examine_Next(HData.CDVolume,dir, &info,(unsigned long *)&fib->fib_DiskKey))
  611.                     {
  612.                         if (res2 == TDERR_DiskChanged)
  613.                             res2 = ERROR_DEVICE_NOT_MOUNTED;
  614.                     }
  615.                     else
  616.                     {
  617.                         Fill_FileInfoBlock(fib,&info,HData.CDVolume,&HData);
  618.                         res1 = DOSTRUE;
  619.                     }
  620.                 }
  621.                 break;
  622.  
  623.             case ACTION_INFO:
  624. D(kprintf("ACTION_INFO lock %lx infodata %lx ->\n",packet->dp_Arg1,packet->dp_Arg2));
  625.                 res1 = DOSFALSE;
  626.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  627.                 {
  628.                     Fill_InfoData(BADDR(packet->dp_Arg2),&HData);
  629.                     res1 = DOSTRUE;
  630.                 }
  631.                 break;
  632.  
  633.             case ACTION_DISK_INFO:
  634. D(kprintf("ACTION_DISK_INFO infodata %lx ->\n",packet->dp_Arg1));
  635.                 Fill_InfoData(BADDR(packet->dp_Arg1),&HData);
  636.                 res1 = DOSTRUE;
  637.                 break;
  638.  
  639.             case ACTION_CURRENT_VOLUME:
  640. D(kprintf("ACTION_CURRENT_VOLUME fh_Args %lx ->\n",packet->dp_Arg1));
  641.                 if (packet->dp_Arg1)
  642.                     res1 = ((struct FileLock *)BADDR(packet->dp_Arg1))->fl_Volume;
  643.                 else res1 = MKBADDR(HData.CurrentVolume);
  644.                 res2 = HData.fssm->fssm_Unit;
  645.                 break;
  646.  
  647.             case ACTION_INHIBIT:
  648. D(kprintf("ACTION_INHIBIT bool %ld ->\n",packet->dp_Arg1));
  649.                 if (packet->dp_Arg1 != DOSFALSE)
  650.                 {
  651.                     RemoveVolumeNode(&HData);
  652.                     HData.Inhibited++;
  653.                     HData.DiskInserted = DI_DISK_OK;    /* this way any operation */
  654.                                     /* will fail with error "not a dos disk" */
  655.                 }
  656.                 else
  657.                 {
  658.                     if (HData.Inhibited)
  659.                     {
  660.                         HData.Inhibited--;
  661.                         HData.CD->t_changeint2 = (unsigned long)-2;
  662.                         HData.DiskInserted = DI_NO_DISK;    /* force a disk check */
  663.                         Check_Disk(&HData);
  664.                     }
  665.                 }
  666.                 break;
  667.  
  668.             case ACTION_READ_LINK:
  669.                 {
  670.                     CDROM_OBJ *obj;
  671.                     CDROM_OBJ *parentdir = getlockfile (packet->dp_Arg1,&HData);
  672.                     char *outbuf = (char *) packet->dp_Arg3;
  673.                     t_ulong maxlength = packet->dp_Arg4;
  674.                     int offs;
  675.                     char buf[256];
  676.                     int res;
  677.  
  678. D(kprintf("ACTION_READ_LINK lock %lx path %s buffer %lx bufsiz %ld ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3,packet->dp_Arg4));
  679.  
  680.                     res1 = 0;
  681.                     if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  682.                     {
  683.                         offs = Check_For_Volume_Name_Prefix ((char *) packet->dp_Arg2);
  684.                         obj = Open_Object(HData.CDVolume,parentdir, (char *) packet->dp_Arg2 + offs);
  685.                         if (obj)
  686.                         {
  687.                             res = Get_Link_Name (HData.CDVolume,obj, buf, sizeof (buf));
  688.                             if (res == 0 || strlen (buf) + HData.VolumeName[0] + 1 >= maxlength)
  689.                                 strncpy (outbuf, "illegal_link", maxlength - 1);
  690.                             else
  691.                             {
  692.                                 if (buf[0] == ':')
  693.                                     strcpy (outbuf,&HData.VolumeName[0]);
  694.                                 else
  695.                                     outbuf[0] = 0;
  696.  
  697.                                 strcat (outbuf, buf);
  698.                             }
  699.  
  700.                             outbuf[maxlength - 1] = 0;
  701.                             Close_Object(obj);
  702.                             res1 = strlen (outbuf);
  703.                         }
  704.                         else
  705.                         {
  706.                             res2 = IoErr();
  707.                             if (res2 == TDERR_DiskChanged)
  708.                                 res2 = packet->dp_Arg1 ? ERROR_DEVICE_NOT_MOUNTED : ERROR_NO_DISK;
  709.                         }
  710.                     }
  711.                 }
  712.                 break;
  713.  
  714.             case ACTION_RENAME_DISK:
  715.             case ACTION_SERIALIZE_DISK:
  716. D(switch (packet->dp_Type)
  717.     {
  718.     case ACTION_RENAME_DISK:
  719.         kprintf("ACTION_RENAME_DISK name \"%b\" ->\n",packet->dp_Arg1);
  720.         break;
  721.     case ACTION_SERIALIZE_DISK:
  722.         kprintf("ACTION_SERIALIZE_DISK ->\n");
  723.         break;
  724.     }
  725. )
  726.                 res1 = DOSFALSE;
  727.                 if (!HData.CurrentVolume)
  728.                     res2 = HData.DiskInserted == DI_NO_DISK ? ERROR_NO_DISK : ERROR_NOT_A_DOS_DISK;
  729.                 else res2 = ERROR_DISK_WRITE_PROTECTED;
  730.                 break;
  731.  
  732.             case ACTION_FORMAT:
  733. D(kprintf("ACTION_FORMAT name \"%b\" dostype %lx ->\n",packet->dp_Arg1,packet->dp_Arg2));
  734.                 res1 = DOSFALSE;
  735.                 if (HData.DiskInserted == DI_NO_DISK) res2 = ERROR_NO_DISK;
  736.                 else res2 = ERROR_DISK_WRITE_PROTECTED;
  737.                 break;
  738.  
  739.             case ACTION_WRITE:
  740.             case ACTION_SET_FILE_SIZE:
  741. D(switch (packet->dp_Type)
  742.     {
  743.     case ACTION_WRITE:
  744.         kprintf("ACTION_WRITE fh_Args %lx buffer %lx len %ld ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3);
  745.         break;
  746.     case ACTION_SET_FILE_SIZE:
  747.         kprintf("ACTION_SET_FILE_SIZE fh_Args %lx pos %ld mode %ld ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3);
  748.         break;
  749.     }
  750. )
  751.                 res1 = -1;
  752.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  753.                     res2 = ERROR_DISK_WRITE_PROTECTED;
  754.                 break;
  755.  
  756.             case ACTION_DELETE_OBJECT:
  757.             case ACTION_RENAME_OBJECT:
  758.             case ACTION_CREATE_DIR:
  759.             case ACTION_MAKE_LINK:
  760. D(switch (packet->dp_Type)
  761.     {
  762.     case ACTION_DELETE_OBJECT:
  763.         kprintf("ACTION_DELETE_OBJECT lock %lx name \"%b\" ->\n",packet->dp_Arg1,packet->dp_Arg2);
  764.         break;
  765.     case ACTION_RENAME_OBJECT:
  766.         kprintf("ACTION_RENAME_OBJECT lock %lx name \"%b\" newlock %lx newname \"%b\" ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3,packet->dp_Arg4);
  767.         break;
  768.     case ACTION_CREATE_DIR:
  769.         kprintf("ACTION_CREATE_DIR lock %lx name \"%b\" ->\n",packet->dp_Arg1,packet->dp_Arg2);
  770.         break;
  771.     case ACTION_MAKE_LINK:
  772.         kprintf("ACTION_MAKE_LINK lock %lx name \"%b\" dest %lx soft %ld ->\n",packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3,packet->dp_Arg4);
  773.         break;
  774.     }
  775. )
  776.                 res1 = DOSFALSE;
  777.                 if (!(res2 = CheckLock(packet->dp_Arg1,&HData)))
  778.                     res2 = ERROR_DISK_WRITE_PROTECTED;
  779.                 break;
  780.  
  781.             case ACTION_SET_PROTECT:
  782.             case ACTION_SET_COMMENT:
  783.             case ACTION_SET_DATE:
  784.             case ACTION_SET_OWNER:
  785. D(switch (packet->dp_Type)
  786.     {
  787.     case ACTION_SET_PROTECT:
  788.         kprintf("ACTION_SET_PROTECT (arg1 unused) lock %lx name \"%b\" bits %lx ->\n",packet->dp_Arg2,packet->dp_Arg3,packet->dp_Arg4);
  789.         break;
  790.     case ACTION_SET_COMMENT:
  791.         kprintf("ACTION_SET_COMMENT (arg1 unused) lock %lx name \"%b\" comment \"%b\" ->\n",packet->dp_Arg2,packet->dp_Arg3,packet->dp_Arg4);
  792.         break;
  793.     case ACTION_SET_DATE:
  794.         kprintf("ACTION_SET_DATE (arg1 unused) lock %lx name \"%b\" date %lx ->\n",packet->dp_Arg2,packet->dp_Arg3,packet->dp_Arg4);
  795.         break;
  796.     case ACTION_SET_OWNER:
  797.         kprintf("ACTION_SET_OWNER (arg1 unused) lock %lx name \"%b\" owner %lx ->\n",packet->dp_Arg2,packet->dp_Arg3,packet->dp_Arg4);
  798.         break;
  799.     }
  800. )
  801.                 res1 = DOSFALSE;
  802.                 if (!(res2 = CheckLock(packet->dp_Arg2,&HData)))
  803.                     res2 = ERROR_DISK_WRITE_PROTECTED;
  804.                 break;
  805.  
  806.             case ACTION_IS_FILESYSTEM:
  807. D(kprintf("ACTION_IS_FILESYSTEM ->\n"));
  808.                 res1 = DOSTRUE;
  809.                 break;
  810.  
  811.             case ACTION_FLUSH:
  812. D(kprintf("ACTION_FLUSH ->\n"));
  813.                 res1 = DOSTRUE;
  814.                 break;
  815.  
  816.             default:
  817. D(kprintf("Unknown pkt #%ld  %lx %lx %lx %lx %lx ->\n",(LONG)packet->dp_Type,
  818.         packet->dp_Arg1,packet->dp_Arg2,packet->dp_Arg3,packet->dp_Arg4,packet->dp_Arg5));
  819.                 res1 = DOSFALSE;
  820.                 res2 = ERROR_ACTION_NOT_KNOWN;
  821.                 break;
  822.             }
  823.  
  824.             ReturnPacket(packet,HData.MyPort,res1,res2);
  825.         }
  826.     }
  827. }
  828. }
  829.  
  830.  
  831.  
  832. VOID AddToFSResource(ULONG dostype,BPTR seglist)
  833. {
  834. struct FileSysResource *FileSysResBase;
  835.  
  836.  
  837. if (FileSysResBase = (struct FileSysResource *)OpenResource(FSRNAME))
  838. {
  839.     struct FileSysEntry *fse,*nfse;
  840.  
  841.  
  842.     Forbid();
  843.  
  844.     fse = (struct FileSysEntry *)FileSysResBase->fsr_FileSysEntries.lh_Head;
  845.     while (nfse = (struct FileSysEntry *)fse->fse_Node.ln_Succ)
  846.     {
  847.     /* if filesystem already in resource, return */
  848.         if (fse->fse_DosType == dostype) break;
  849.  
  850.         fse = nfse;
  851.     }
  852.  
  853.     Permit();
  854.  
  855.     if (!nfse && (fse = AllocMem(sizeof(struct FileSysEntry),MEMF_PUBLIC | MEMF_CLEAR)))
  856.     {
  857.         fse->fse_Node.ln_Name = (UBYTE *)&versionstring20[7];
  858.         fse->fse_DosType = dostype;
  859.         fse->fse_Version = ((LONG)VERSION) << 16 | REVISION;
  860.         fse->fse_PatchFlags = 0x180;
  861.         fse->fse_SegList = seglist;
  862.         fse->fse_GlobalVec = -1;
  863.  
  864.         Forbid();
  865.         AddHead(&FileSysResBase->fsr_FileSysEntries,fse);
  866.         Permit();
  867.     }
  868. }
  869. }
  870.  
  871.  
  872.  
  873. /*
  874.  * Return a packet back to DOS.
  875.  */
  876. VOID ReturnPacket(struct DosPacket *packet,struct MsgPort *port,LONG res1,LONG res2)
  877. {
  878. struct Message *mess;
  879. struct MsgPort *replyport;
  880.  
  881.  
  882. D(kprintf("%lx %ld\n",res1,res2));
  883.  
  884. packet->dp_Res1 = res1;
  885. packet->dp_Res2 = res2;
  886. replyport = packet->dp_Port;
  887. mess = packet->dp_Link;
  888. packet->dp_Port = port;
  889. mess->mn_Node.ln_Name = (UBYTE *)packet;
  890. PutMsg(replyport,mess);
  891. }
  892.  
  893.  
  894.  
  895. /*
  896.  *  Convert a BSTR into a normal string.. copying the string into buf.
  897.  *  I use normal strings for internal storage, and convert back and forth
  898.  *  when required.
  899.  */
  900.  
  901. void btos(LONG bstr, char *buf)
  902. {
  903.     unsigned char *str = BADDR(bstr);
  904.     memcpy(buf,&str[1],str[0]);
  905.     buf[str[0]] = 0;
  906. }
  907.  
  908.  
  909.  
  910. /*
  911.  * Locate and open an object on the CD-ROM. Returns a CDROM_OBJ pointer,
  912.  * or NULL if an error occurred. If an error occurred, IoErr() contains
  913.  * the error code.
  914.  */
  915. CDROM_OBJ *OpenObject(BPTR parentlock,BSTR name,struct HData *HData)
  916. {
  917. CDROM_OBJ *parentdir;
  918. CDROM_OBJ *obj;
  919. int offs;
  920. char    buf[256];
  921.  
  922.  
  923. parentdir = getlockfile(parentlock,HData);
  924. btos(name,buf);
  925.  
  926. offs = Check_For_Volume_Name_Prefix(buf);
  927. if (!buf[offs])
  928. {
  929.     if (parentdir)
  930.         obj = Clone_Object(parentdir);
  931.     else
  932.         obj = Open_Top_Level_Directory(HData->CDVolume);
  933. }
  934. else
  935.     obj = Open_Object(HData->CDVolume,parentdir,buf + offs);
  936.  
  937. if (obj)
  938. {
  939.     if (obj->symlink_f)
  940.     {
  941.         Close_Object(obj);
  942.         obj = NULL;
  943.         SetIoErr(ERROR_IS_SOFT_LINK);
  944.     }
  945. }
  946. /* else IoErr() already contains the error code set by Open_Object() */
  947.  
  948. return(obj);
  949. }
  950.  
  951.  
  952.  
  953. /*
  954.  *  The lock function.    The file has already been checked to see if it
  955.  *  is lockable given the mode.
  956.  * Returns NULL if out of memory.
  957.  */
  958.  
  959. BPTR cdlock(CDROM_OBJ *cdfile, int mode,struct HData *HData)
  960. {
  961. struct FileLock *lock;
  962.  
  963.  
  964. if (lock = AllocVec(sizeof(struct FileLock),MEMF_PUBLIC | MEMF_CLEAR))
  965. {
  966.     lock->fl_Key = (long) cdfile;
  967.     lock->fl_Access = ACCESS_READ;
  968.     lock->fl_Task = HData->MyPort;
  969.     lock->fl_Volume = MKBADDR(HData->CurrentVolume);
  970.  
  971.     lock->fl_Link = HData->LockList;
  972.     HData->LockList = MKBADDR(lock);
  973. }
  974.  
  975. return(MKBADDR(lock));
  976. }
  977.  
  978.  
  979.  
  980. void cdunlock (BPTR lock,struct HData *HData)
  981.  
  982. {
  983. struct FileLock *flock,*cl,*ncl;
  984. struct DosList *vol;
  985.  
  986.  
  987. if (!lock) return;
  988.  
  989. flock = BADDR(lock);
  990. vol = BADDR(flock->fl_Volume);
  991. if (vol == HData->CurrentVolume)
  992.     cl = (struct FileLock *)&HData->LockList;
  993. else
  994.     cl = (struct FileLock *)&vol->dol_misc.dol_volume.dol_LockList;
  995.  
  996. while (cl && (ncl = BADDR(cl->fl_Link)) != flock) cl = ncl;
  997.  
  998. if (cl) cl->fl_Link = ncl->fl_Link;
  999.  
  1000. if (vol != HData->CurrentVolume && !vol->dol_misc.dol_volume.dol_LockList)
  1001. {
  1002.     RemoveDosList(vol);
  1003.     CreateInputEvent(FALSE,HData);
  1004. }
  1005.  
  1006. Close_Object(getlockfile(lock,HData));
  1007. FreeVec(flock);                /* free lock        */
  1008. }
  1009.  
  1010.  
  1011.  
  1012. /*
  1013.  * Check if the volume associated to the given lock is present in the drive.
  1014.  * Return 0 if everything OK, or an error code (to be assigned to res2) if
  1015.  * an error occurred.
  1016.  */
  1017. LONG CheckLock(BPTR lock,struct HData *HData)
  1018. {
  1019. if (lock && BADDR(((struct FileLock *)BADDR(lock))->fl_Volume) != HData->CurrentVolume)
  1020.     return(ERROR_DEVICE_NOT_MOUNTED);
  1021. else if (!HData->CurrentVolume)
  1022.     return(HData->DiskInserted == DI_NO_DISK ? ERROR_NO_DISK : ERROR_NOT_A_DOS_DISK);
  1023. else return(0);
  1024. }
  1025.  
  1026.  
  1027.  
  1028. /*
  1029.  *  GETLOCKFILE(bptrlock)
  1030.  *
  1031.  *  Return the CDROM_OBJ (file or directory) associated with the
  1032.  *  given lock, which is passed as a BPTR.
  1033.  *
  1034.  *  According to the DOS spec, the only way a NULL lock will ever be
  1035.  *  passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
  1036.  *  In anycase, If a NULL lock is passed to me I simply assume it means
  1037.  *  the root directory of the CDROM.
  1038.  */
  1039.  
  1040. CDROM_OBJ *getlockfile(BPTR lock,struct HData *HData)
  1041. {
  1042.   struct FileLock *rl = BADDR(lock);
  1043.  
  1044.   if (rl)
  1045.     return (CDROM_OBJ *) rl->fl_Key;
  1046.   return HData->TopLevelObj;
  1047. }
  1048.  
  1049. /*
  1050.  * If p_pathname contains a ':' character, return the position of the first
  1051.  * character after ':'
  1052.  * Otherwise, return 0.
  1053.  */
  1054.  
  1055. int Check_For_Volume_Name_Prefix (char *p_pathname)
  1056. {
  1057.   char *pos = strchr (p_pathname, ':');
  1058.  
  1059.   return pos ? (pos - p_pathname) + 1 : 0;
  1060. }
  1061.  
  1062.  
  1063.  
  1064. /*
  1065.  * Fill an InfoData structure with info on the current volume.
  1066.  */
  1067. VOID Fill_InfoData(struct InfoData *id,struct HData *HData)
  1068. {
  1069. memset(id,0,sizeof(struct InfoData));
  1070. id->id_UnitNumber = HData->fssm->fssm_Unit;
  1071. id->id_DiskState = ID_WRITE_PROTECTED;
  1072. if (HData->CurrentVolume)
  1073. {
  1074.     id->id_NumBlocks     = Volume_Size(HData->CDVolume);
  1075.     id->id_NumBlocksUsed = id->id_NumBlocks - Volume_Free(HData->CDVolume);
  1076. D(kprintf("total %ld used %ld\n",id->id_NumBlocks,id->id_NumBlocksUsed));
  1077.  
  1078.     id->id_DiskType = ID_DOS_DISK;
  1079.     id->id_VolumeNode = MKBADDR(HData->CurrentVolume);
  1080.     id->id_BytesPerBlock = Block_Size(HData->CDVolume);
  1081.     id->id_InUse = HData->LockList;
  1082. }
  1083. else
  1084. {
  1085.     if (HData->Inhibited) id->id_DiskType = 0x42555359;        /* BUSY */
  1086.     else switch (HData->DiskInserted)
  1087.     {
  1088.     case DI_NO_DISK:
  1089.     case DI_CDDA_DISK:
  1090.         id->id_DiskType = ID_NO_DISK_PRESENT;
  1091.         break;
  1092.  
  1093.     case DI_UNREADABLE_DISK:
  1094.         id->id_DiskType = ID_UNREADABLE_DISK;
  1095.         break;
  1096.  
  1097.     case DI_DISK_OK:
  1098.     default:
  1099.         id->id_DiskType = ID_NOT_REALLY_DOS;
  1100.         break;
  1101.     }
  1102. }
  1103. }
  1104.  
  1105.  
  1106.  
  1107. /*
  1108.  * Fills a FileInfoBlock with the information contained in the
  1109.  * directory record of a CD-ROM directory or file.
  1110.  */
  1111.  
  1112. void Fill_FileInfoBlock (struct FileInfoBlock *p_fib, CDROM_INFO *p_info, VOLUME *p_volume,struct HData *HData)
  1113. {
  1114. char *src = p_info->name;
  1115. char *dest = p_fib->fib_FileName+1;
  1116. int len = p_info->name_length;
  1117.  
  1118.  
  1119. if (p_info->symlink_f)
  1120.     p_fib->fib_DirEntryType = ST_SOFTLINK;
  1121. else
  1122.     p_fib->fib_DirEntryType = p_info->directory_f ? ST_USERDIR : ST_FILE;
  1123.  
  1124. p_fib->fib_EntryType = p_fib->fib_DirEntryType;
  1125.  
  1126. if (len == 1 && *src == ':')
  1127. {
  1128.     /* root of file system: */
  1129.     p_fib->fib_DirEntryType = ST_USERDIR;
  1130.     /* file name == volume name: */
  1131.     /* VolumeName is a BCPL string, but it's NULL-terminated. */
  1132.     strcpy(p_fib->fib_FileName,HData->VolumeName);
  1133. }
  1134. else
  1135. {
  1136.     short real_len;
  1137.  
  1138.  
  1139.     /* copy file name: */
  1140.     memcpy(dest,src,len);
  1141.  
  1142.     real_len = len;
  1143.  
  1144.     /* remove version number */
  1145.     {
  1146.         WORD i;
  1147.  
  1148.  
  1149.         i = len;
  1150.         while (i)
  1151.         {
  1152.             if (src[--i] == ';')
  1153.             {
  1154.                 real_len = i;
  1155.                 break;
  1156.             }
  1157.         }
  1158.     }
  1159.  
  1160.     p_fib->fib_FileName[0] = real_len;
  1161.     /* NULL terminate the string */
  1162.     p_fib->fib_FileName[real_len + 1] = 0;
  1163. }
  1164.  
  1165. p_fib->fib_Protection = 0;
  1166. p_fib->fib_Size = p_info->file_length;
  1167. p_fib->fib_NumBlocks = p_info->file_length >> 11;
  1168. if (p_info->symlink_f)
  1169.     strcpy (p_fib->fib_Comment, "\x0DSymbolic link");
  1170. else
  1171.     p_fib->fib_Comment[0] = 0;
  1172.  
  1173. p_fib->fib_Date.ds_Days   = p_info->date / (24 * 60 * 60);
  1174. p_fib->fib_Date.ds_Minute = (p_info->date % (24 * 60 * 60)) / 60;
  1175. p_fib->fib_Date.ds_Tick   = (p_info->date % 60) * TICKS_PER_SECOND;
  1176. }
  1177.  
  1178.  
  1179. /*
  1180.  * Mount a volume.
  1181.  */
  1182.  
  1183. void Mount(struct HData *HData)
  1184. {
  1185. Clear_Sector_Buffers(HData->CD);    /* make sure the buffers are empty */
  1186.  
  1187. HData->CD->t_changeint2 = HData->CD->t_changeint;
  1188. HData->DiskInserted = DI_DISK_OK;
  1189.  
  1190. if (!(HData->CDVolume = Open_Volume(HData->CD,
  1191.         HData->HConfig.Lowercase)))
  1192. {
  1193. D(kprintf ("!!! cannot open VOLUME !!!\n"));
  1194.  
  1195. /* A secondary error less than ERROR_NO_FREE_STORE is supposed to be a device */
  1196. /* error. */
  1197.     if (IoErr() < ERROR_NO_FREE_STORE)
  1198.         HData->DiskInserted = DI_UNREADABLE_DISK;
  1199.  
  1200.     if (Has_Audio_Tracks(HData->CD))
  1201.     {
  1202.         HData->DiskInserted = DI_CDDA_DISK;
  1203.         Show_CDDA_Icon(HData);
  1204.     }
  1205.     CreateInputEvent(TRUE,HData);
  1206.     return;
  1207. }
  1208.  
  1209. if (!(HData->TopLevelObj = Open_Top_Level_Directory(HData->CDVolume)))
  1210. {
  1211. D(kprintf ("!!! cannot open top level directory !!!\n"));
  1212.     Close_Volume(HData->CDVolume);
  1213.     HData->CDVolume = NULL;
  1214.  
  1215.     CreateInputEvent(TRUE,HData);
  1216.     return;
  1217. }
  1218.  
  1219. D(kprintf ("***mounting***\n"));
  1220.  
  1221. Volume_ID(HData->CDVolume,&HData->VolumeName[1],sizeof(HData->VolumeName)-2);
  1222. if (!(HData->VolumeName[0] = strlen(&HData->VolumeName[1])))
  1223.     strcpy(HData->VolumeName,"\7Unnamed");
  1224.  
  1225. /* if we are (probably) dealing with a floppy, read geometry */
  1226. if (HData->CD->use_trackdisk && !HData->envec->de_LowCyl &&
  1227.         Volume_Size(HData->CDVolume) < 10000)
  1228. {
  1229.     struct DriveGeometry dg;
  1230.  
  1231.  
  1232.     HData->CD->scsireq->io_Command = TD_GETGEOMETRY;
  1233.     HData->CD->scsireq->io_Data = &dg;
  1234.     HData->CD->scsireq->io_Length = sizeof(struct DriveGeometry);
  1235.     if (!DoIO((struct IORequest *)HData->CD->scsireq))
  1236.     {
  1237.         HData->envec->de_SizeBlock = dg.dg_SectorSize / 4;
  1238.         HData->envec->de_HighCyl = dg.dg_Cylinders - 1;
  1239.         HData->envec->de_Surfaces = dg.dg_Heads;
  1240.         HData->envec->de_BlocksPerTrack = dg.dg_TrackSectors;
  1241.     }
  1242. }
  1243.  
  1244. if (!CreateVolumeNode(HData))
  1245. {
  1246.     Close_Object(HData->TopLevelObj);
  1247.     Close_Volume(HData->CDVolume);
  1248.     HData->CDVolume = NULL;
  1249. }
  1250.  
  1251. CreateInputEvent(TRUE,HData);
  1252. }
  1253.  
  1254.  
  1255. /*
  1256.  * Create Volume node and add to the device list. This will
  1257.  * cause the WORKBENCH to recognize us as a disk. If we don't
  1258.  * create a Volume node, Wb will not recognize us.
  1259.  */
  1260.  
  1261. struct DosList *CreateVolumeNode(struct HData *HData)
  1262. {
  1263. struct DosInfo *di = BADDR(((struct RootNode *)DOSBase->dl_Root)->rn_Info);
  1264. struct DosList *dl;
  1265. ULONG p_volume_date = Volume_Creation_Date(HData->CDVolume);
  1266.  
  1267.  
  1268. Forbid();
  1269.  
  1270. for (dl = BADDR(di->di_DevInfo);dl;dl = BADDR(dl->dol_Next))
  1271. {
  1272.     if (dl->dol_Type == DLT_VOLUME &&
  1273.             !Stricmp(BADDR(dl->dol_Name),HData->VolumeName) &&
  1274.             dl->dol_misc.dol_volume.dol_DiskType == HData->envec->de_DosType &&
  1275.             dl->dol_misc.dol_volume.dol_VolumeDate.ds_Days == p_volume_date / (24 * 60 * 60) &&
  1276.             dl->dol_misc.dol_volume.dol_VolumeDate.ds_Minute == (p_volume_date % (24 * 60 * 60)) / 60 &&
  1277.             dl->dol_misc.dol_volume.dol_VolumeDate.ds_Tick == (p_volume_date % 60) * TICKS_PER_SECOND)
  1278.         break;
  1279. }
  1280.  
  1281. if (!dl)
  1282. {
  1283.     if (dl = MakeDosEntry(&HData->VolumeName[1],DLT_VOLUME))
  1284.     {
  1285.         dl->dol_misc.dol_volume.dol_DiskType = HData->envec->de_DosType;
  1286.         dl->dol_misc.dol_volume.dol_VolumeDate.ds_Days = p_volume_date / (24 * 60 * 60);
  1287.         dl->dol_misc.dol_volume.dol_VolumeDate.ds_Minute = (p_volume_date % (24 * 60 * 60)) / 60;
  1288.         dl->dol_misc.dol_volume.dol_VolumeDate.ds_Tick = (p_volume_date % 60) * TICKS_PER_SECOND;
  1289.         dl->dol_Next = di->di_DevInfo;
  1290.         di->di_DevInfo = MKBADDR(dl);
  1291.     }
  1292. }
  1293.  
  1294. /* make sure that dl_Task is NULL, otherwise it means that another handler */
  1295. /* is using the same disk - we can't create our volume */
  1296. if (dl && !dl->dol_Task)
  1297. {
  1298.     struct FileLock *lock;
  1299.  
  1300.  
  1301.     dl->dol_Task = HData->MyPort;
  1302.     HData->CurrentVolume = dl;
  1303.     HData->LockList = dl->dol_misc.dol_volume.dol_LockList;
  1304.     dl->dol_misc.dol_volume.dol_LockList = NULL;
  1305.  
  1306.     lock = BADDR(HData->LockList);
  1307.     while (lock)
  1308.     {
  1309.         lock->fl_Task = HData->MyPort;
  1310.         lock = BADDR(lock->fl_Link);
  1311.     }
  1312. }
  1313. else dl = NULL;
  1314.  
  1315. Permit();
  1316.  
  1317. return(dl);
  1318. }
  1319.  
  1320.  
  1321.  
  1322. /*
  1323.  *    Remove Volume entry.
  1324.  */
  1325.  
  1326. void RemoveVolumeNode(struct HData *HData)
  1327. {
  1328. if (HData->DiskInserted != DI_NO_DISK)
  1329. {
  1330.     Hide_CDDA_Icon(HData);
  1331.     HData->CD->t_changeint2 = HData->CD->t_changeint;
  1332.     HData->DiskInserted = DI_NO_DISK;
  1333.     HData->Playing = FALSE;
  1334.  
  1335.     if (HData->CurrentVolume)
  1336.     {
  1337.         D(kprintf("***unmounting***\n"));
  1338.  
  1339.     /* remove the volume node only if there are no outstanding locks */
  1340.         if (!HData->LockList)
  1341.             RemoveDosList(HData->CurrentVolume);
  1342.         else
  1343.         {
  1344.             HData->CurrentVolume->dol_Task = NULL;
  1345.             HData->CurrentVolume->dol_misc.dol_volume.dol_LockList = HData->LockList;
  1346.         }
  1347.  
  1348.         Close_Object(HData->TopLevelObj);
  1349.         Close_Volume(HData->CDVolume);
  1350.  
  1351.         HData->CurrentVolume = NULL;
  1352.         HData->LockList = NULL;
  1353.         HData->CDVolume = NULL;
  1354.     }
  1355.  
  1356.     CreateInputEvent(FALSE,HData);
  1357. }
  1358. }
  1359.  
  1360.  
  1361.  
  1362. VOID RemoveDosList(struct DosList *vol)
  1363. {
  1364. struct DosInfo *di;
  1365. struct DosList *dl;
  1366. void *dlp;
  1367.  
  1368.  
  1369. D(kprintf("Removing Volume node\n"));
  1370. Forbid ();
  1371.  
  1372. di = BADDR(((struct RootNode *)DOSBase->dl_Root)->rn_Info);
  1373.  
  1374. dlp = &di->di_DevInfo;
  1375. for (dl = BADDR(di->di_DevInfo);dl && dl != vol;dl = BADDR(dl->dol_Next))
  1376.     dlp = &dl->dol_Next;
  1377. if (dl == vol)
  1378. {
  1379.     *(BPTR *)dlp = dl->dol_Next;
  1380.     FreeDosEntry(dl);
  1381. }
  1382.  
  1383. Permit();
  1384. }
  1385.  
  1386.  
  1387.  
  1388. /*
  1389.  *  Open timer device structures:
  1390.  */
  1391.  
  1392. int Open_Timer_Device(struct HData *HData)
  1393. {
  1394. if (HData->TimerPort = CreateMsgPort())
  1395. {
  1396.     if (HData->TimerIO = (struct timerequest *)
  1397.             CreateIORequest(HData->TimerPort,sizeof(struct timerequest)))
  1398.     {
  1399.         if (!OpenDevice(TIMERNAME,UNIT_VBLANK,HData->TimerIO,0))
  1400.             return(1);
  1401.  
  1402.         DeleteIORequest(HData->TimerIO);
  1403.     }
  1404.  
  1405.     DeleteMsgPort(HData->TimerPort);
  1406.     HData->TimerPort = NULL;
  1407. }
  1408.  
  1409. return(0);
  1410. }
  1411.  
  1412.  
  1413.  
  1414. /*
  1415.  *  Open input device structures:
  1416.  */
  1417.  
  1418. int Open_Input_Device(struct HData *HData)
  1419. {
  1420. struct MsgPort *port;
  1421.  
  1422.  
  1423. if (port = CreateMsgPort())
  1424. {
  1425.     if (HData->InputIO = CreateIORequest(port,sizeof(struct IOStdReq)))
  1426.     {
  1427.         if (!OpenDevice("input.device",0,HData->InputIO,0))
  1428.         {
  1429.             InputBase = (struct Library *)HData->InputIO->io_Device;
  1430.             return(1);
  1431.         }
  1432.  
  1433.         DeleteIORequest(HData->InputIO);
  1434.     }
  1435.  
  1436.     DeleteMsgPort(port);
  1437. }
  1438.  
  1439. return(0);
  1440. }
  1441.  
  1442.  
  1443.  
  1444. /*
  1445.  *  Send timer request
  1446.  */
  1447.  
  1448. void Send_Timer_Request(struct HData *HData)
  1449. {
  1450. HData->TimerIO->tr_node.io_Command = TR_ADDREQUEST;
  1451. HData->TimerIO->tr_time.tv_secs = 1;
  1452. HData->TimerIO->tr_time.tv_micro = 0;
  1453. SendIO(HData->TimerIO);
  1454. }
  1455.  
  1456.  
  1457.  
  1458. /*
  1459.  *  Check whether the disk has been removed or inserted.
  1460.  */
  1461.  
  1462. void Check_Disk (struct HData *HData)
  1463. {
  1464.   int i;
  1465.   unsigned long l1, l2;
  1466.  
  1467.  
  1468. /* don't check for disk if we are inhibited */
  1469. if (HData->Inhibited) return;
  1470.  
  1471. D(kprintf ("Checking Disk...\n"));
  1472.  
  1473. if (HData->CD->use_trackdisk)
  1474. {
  1475.     i = (Test_Unit_Ready(HData->CD));
  1476.     l1 = HData->CD->t_changeint;
  1477.     l2 = HData->CD->t_changeint2;
  1478.     if (l1 != l2)
  1479.     {
  1480.         if (i)
  1481.         {
  1482. D(kprintf ("disk has been inserted (T %ld)\n", l1));
  1483.             RemoveVolumeNode(HData);
  1484.             Mount(HData);
  1485.         }
  1486.         else
  1487.         {
  1488.             if (HData->DiskInserted != DI_NO_DISK)
  1489.             {
  1490. D(kprintf ("disk has been removed (T %ld)\n", l1));
  1491.                 RemoveVolumeNode(HData);
  1492.             }
  1493.         }
  1494.     }
  1495. }
  1496. else
  1497. {
  1498.     if (HData->DiskInserted != DI_NO_DISK)
  1499.     {
  1500.         if (!Test_Unit_Ready(HData->CD))
  1501.         {
  1502. D(kprintf ("disk has been removed\n"));
  1503.             RemoveVolumeNode(HData);
  1504.         }
  1505.     }
  1506.     else
  1507.     {
  1508. /* have to call Test_Unit_Ready() twice because the first SCSI command */
  1509. /* after a disk insertion is always rejected. */
  1510.         if (Test_Unit_Ready (HData->CD) || Test_Unit_Ready (HData->CD))
  1511.         {
  1512. D(kprintf ("disk has been inserted\n"));
  1513.             Mount(HData);
  1514.         }
  1515.     }
  1516. }
  1517. }
  1518.  
  1519.  
  1520.  
  1521. /*
  1522.  * generate a `disk inserted/removed' event, in order to get Workbench to
  1523.  * rescan the DosList and update the list of volume icons.
  1524.  */
  1525.  
  1526. VOID CreateInputEvent(BOOL inserted,struct HData *HData)
  1527. {
  1528. struct InputEvent ie;
  1529.  
  1530.  
  1531. memset(&ie,0,sizeof(struct InputEvent));
  1532. ie.ie_Class = inserted ? IECLASS_DISKINSERTED : IECLASS_DISKREMOVED;
  1533. HData->InputIO->io_Command = IND_WRITEEVENT;
  1534. HData->InputIO->io_Data = &ie;
  1535. HData->InputIO->io_Length = sizeof(struct InputEvent);
  1536. DoIO(HData->InputIO);
  1537. }
  1538.  
  1539.  
  1540.  
  1541. int
  1542. Get_Startup (struct HData *HData)
  1543. {
  1544.   enum {
  1545.     ARG_LOWERCASE,
  1546.     ARG_TRACKDISK,
  1547.     ARG_POLL,
  1548.     ARGCOUNT
  1549.   };
  1550.  
  1551. LONG Args[ARGCOUNT];
  1552. UBYTE *LocalBuffer;
  1553.   struct RDArgs *ArgsPtr;
  1554.   int result = FALSE,len,i;
  1555. UBYTE *p_startup;
  1556.  
  1557.  
  1558.   /* Clear the argument vector. */
  1559.   memset (Args, 0, sizeof(Args));
  1560.  
  1561.   /* valid startup entry? */
  1562. if (HData->envec->de_TableSize >= DE_CONTROL)
  1563.     p_startup = BADDR(HData->envec->de_Control);
  1564. else p_startup = NULL;
  1565.  
  1566. if (!p_startup) p_startup = "";
  1567.  
  1568.   /* Get the contents of the startup field. */
  1569.   len = p_startup[0];
  1570.   if (!(LocalBuffer = AllocVec(len + 2,MEMF_ANY)))
  1571.     return(FALSE);
  1572.  
  1573.   memcpy (LocalBuffer, p_startup + 1, len);
  1574.   /* terminate string with LF (fix ReadArgs() bug) */
  1575.   LocalBuffer[len] = '\n';
  1576.   /* Provide null-termination. */
  1577.   /* Provide null-termination. */
  1578.   LocalBuffer[len+1] = 0;
  1579.  
  1580.   /* Remove leading quotes. */
  1581.   for (i = 0 ; i < len ; i++) {
  1582.     if (LocalBuffer[i] != ' ') {
  1583.       if (LocalBuffer[i] == '\"')
  1584.     LocalBuffer[i] = ' ';
  1585.       break;
  1586.     }
  1587.   }
  1588.  
  1589.   /* Remove trailing quotes. */
  1590.   for (i = len - 1 ; i >= 0 ; i--) {
  1591.     if (LocalBuffer[i] != ' '){
  1592.       if (LocalBuffer[i] == '\"')
  1593.     LocalBuffer[i] = ' ';
  1594.       break;
  1595.     }
  1596.   }
  1597.  
  1598. if (ArgsPtr = (struct RDArgs *) AllocDosObjectTags (DOS_RDARGS,TAG_DONE))
  1599. {
  1600.     /* Don't prompt for input! */
  1601.     ArgsPtr->RDA_Flags |= RDAF_NOPROMPT;
  1602.  
  1603.     /* Set up for local parsing. */
  1604.     ArgsPtr->RDA_Source.CS_Buffer = LocalBuffer;
  1605.     ArgsPtr->RDA_Source.CS_Length = strlen ((char *) LocalBuffer);
  1606.     ArgsPtr->RDA_Source.CS_CurChr = 0;
  1607.  
  1608.     /* Read the arguments. */
  1609.     if (ReadArgs(
  1610.             "L=LOWERCASE/S,"
  1611.             "T=TRACKDISK/S,"
  1612.             "P=POLL/S",
  1613.             Args,ArgsPtr))
  1614.     {
  1615.         result = TRUE;
  1616.  
  1617.  
  1618.         HData->HConfig.Lowercase = Args[ARG_LOWERCASE];
  1619. D(kprintf("lowercase = %ld\n",HData->HConfig.Lowercase));
  1620.         HData->HConfig.UseTrackdisk = Args[ARG_TRACKDISK];
  1621. D(kprintf("trackdisk = %ld\n",HData->HConfig.UseTrackdisk));
  1622.  
  1623.         if (Args[ARG_POLL])
  1624.             HData->HConfig.ScanInterval = 3;
  1625. D(kprintf("scaninterval = %ld\n",HData->HConfig.ScanInterval));
  1626.  
  1627.         FreeArgs(ArgsPtr);
  1628.     }
  1629.  
  1630.     FreeDosObject (DOS_RDARGS, ArgsPtr);
  1631. }
  1632.  
  1633.   if (result) {
  1634.     if (!(HData->CD = Open_CDROM (&((UBYTE *)BADDR(HData->fssm->fssm_Device))[1],
  1635.             HData->fssm->fssm_Unit,HData->fssm->fssm_Flags,
  1636.             HData->envec->de_LowCyl * HData->envec->de_Surfaces *
  1637.                 HData->envec->de_BlocksPerTrack * 4 * HData->envec->de_SizeBlock,
  1638.             HData->HConfig.UseTrackdisk,
  1639.     /* if the Mask is in 24-bit range, use 24BITDMA memory */
  1640.             (HData->envec->de_Mask & 0xff000000) ?
  1641.                 HData->envec->de_BufMemType : HData->envec->de_BufMemType | MEMF_24BITDMA,
  1642.             HData->envec->de_NumBuffers,5, /* file buffers */
  1643.             !HData->HConfig.ScanInterval))) {
  1644.       result = FALSE;
  1645.     }
  1646.   }
  1647.  
  1648. FreeVec(LocalBuffer);
  1649.  
  1650.   return result;
  1651. }
  1652.  
  1653.  
  1654.  
  1655.  
  1656.  
  1657.  
  1658. VOID Show_CDDA_Icon(struct HData *HData)
  1659. {
  1660. struct DiskObject *appicon;
  1661.  
  1662.  
  1663. if (!IconBase) IconBase = OpenLibrary("icon.library",37);
  1664. if (!WorkbenchBase) WorkbenchBase = OpenLibrary("workbench.library",37);
  1665.  
  1666. if (!IconBase || !WorkbenchBase || HData->AppIcon) return;
  1667.  
  1668. if (!(appicon = GetDiskObject("ENV:sys/def_CDDAdisk")) &&
  1669.         !(appicon = GetDefDiskObject(WBKICK)))
  1670.     return;
  1671.  
  1672. strncpy(HData->VolumeName,&((UBYTE *)BADDR(HData->MyDevNode->dol_Name))[1],sizeof(HData->VolumeName)-1);
  1673. if (strlen(HData->VolumeName) < sizeof(HData->VolumeName)-5)
  1674.     strcat(HData->VolumeName,":CDDA");
  1675.  
  1676. if (HData->AppPort = CreateMsgPort())
  1677.     HData->AppIcon = AddAppIconA(0,0,HData->VolumeName,HData->AppPort,NULL,appicon,NULL);
  1678.  
  1679. /* copy the default tool name */
  1680. if (appicon->do_DefaultTool)
  1681.     strcpy(HData->PlayCDDA,appicon->do_DefaultTool);
  1682. else HData->PlayCDDA[0] = 0;
  1683.  
  1684. /* the icon may be freed immediately, the Workbench copies it internally */
  1685. FreeDiskObject(appicon);
  1686.  
  1687. /* AddAppIconA may fail if the Workbench has not yet been loaded. */
  1688. if (!HData->AppIcon)
  1689. {
  1690.     DeleteMsgPort(HData->AppPort);
  1691.     HData->AppPort = NULL;
  1692. }
  1693. }
  1694.  
  1695.  
  1696.  
  1697. void Hide_CDDA_Icon(struct HData *HData)
  1698. {
  1699. struct Message *msg;
  1700.  
  1701.  
  1702. if (HData->AppIcon)
  1703. {
  1704.     RemoveAppIcon(HData->AppIcon);
  1705.     HData->AppIcon = NULL;
  1706.  
  1707.     if (HData->AppPort)
  1708.     {
  1709.         while (msg = GetMsg(HData->AppPort))
  1710.             ReplyMsg(msg);
  1711.         DeleteMsgPort(HData->AppPort);
  1712.  
  1713.         HData->AppPort = NULL;
  1714.     }
  1715. }
  1716. }
  1717.