home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga Shareware Floppies / ma28.dms / ma28.adf / AmiCDROM / source / Csourcefiles.lha / device.c < prev    next >
C/C++ Source or Header  |  1994-09-19  |  44KB  |  1,541 lines

  1. /* device.c:
  2.  *
  3.  * Handler for ISO-9660 (+ Rock Ridge) + HFS CDROM filing system.
  4.  * Based on DOSDEV V1.10 (2 Nov 87) by Matthew Dillon.
  5.  *
  6.  * ----------------------------------------------------------------------
  7.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  8.  * All rights reserved.
  9.  * This software may be freely distributed and redistributed for
  10.  * non-commercial purposes, provided this notice is included.
  11.  * ----------------------------------------------------------------------
  12.  * History:
  13.  *
  14.  * 01-Sep-94   fmu   - Added ACTION_EXAMINE_FH.
  15.  *             - Added ACTION_PARENT_FH.
  16.  *             - Added ACTION_MAKE_LINK (-> error message).
  17.  *             - Automatically remove volume if all locks on the
  18.  *               the volume have been freed.
  19.  * 17-May-94   fmu   New option MAYBELOWERCASE (=ML).
  20.  * 20-Apr-94   fmu   Improved implementation of ACTION_INHIBIT.
  21.  * 17-Apr-94   fmu   Fixed bug concerning TRACKDISK disk change recognition.
  22.  * 12-Apr-94   fmu   Adapted ACTION_CURRENT_VOLUME to new filehandle
  23.  *             management.
  24.  * 09-Apr-94   fmu   Volume management: locks and filehandles will not
  25.  *                   be forgotten if a CDROM is removed from the drive.
  26.  * 06-Feb-94   dmb   - Full support for ACTION_INHIBIT
  27.  *                   - Change Check_Disk() for trackdisk support
  28.  * 05-Jan-93   fmu   - Retry displaying CD-DA icon if WB is not open.
  29.  *                   - id_UnitNumber of InfoData set to SCSI unit number.
  30.  *                   - Added Make_FSSM().
  31.  * 01-Jan-93   fmu   Support for symbolic links on RockRidge disks.
  32.  * 11-Dec-93   fmu   - ACTION_FLUSH always returns DOSTRUE.
  33.  *                   - ISO volume names are mapped to lowercase if
  34.  *                     the option LOWERCASE has been selected.
  35.  * 26-Nov-93   fmu   Some packets are now handled even if no disk
  36.  *                   is inserted.
  37.  * 21-Nov-93   fmu   - User programmable diskchange check interval.
  38.  *                   - Better support for ACTION_INHIBIT.
  39.  *                   - Handles filenames with ';'.
  40.  * 15-Nov-93   fmu   Missing return value for 'handler' inserted.
  41.  * 14-Nov-93   fmu   Added ACTION_USER packet for 'cdcontrol' program.
  42.  * 15-Oct-93   fmu   Adapted to new VOLUME structure.
  43.  * 10-Oct-93   fmu   - Creates volume node for 'no DOS' disks.
  44.  *             - Volume node now contains the correct volume
  45.  *               creation date.
  46.  * 09-Oct-93   fmu   - New format for mountlist startup field.
  47.  *             - SAS/C support.
  48.  *             - Debug process assembly tag adapted to small
  49.  *               memory model.
  50.  *             - Get_Startup moved to file devsupp.c.
  51.  * 03-Oct-93   fmu   - New buffering options 'S' and 'C'.
  52.  *                   - Fixed bug in cdlock.
  53.  *             - Fixed bug in ACTION_CURRENT_VOLUME.
  54.  * 27-Sep-93   fmu   Added ACTION_SAME_LOCK
  55.  * 25-Sep-93   fmu   - Send 'disk inserted' / 'disk removed' event via
  56.  *                     input.device if disk has been changed.
  57.  *                   - Corrected bug in ACTION_DISK_INFO.
  58.  * 24-Sep-93   fmu   - Added fast memory option 'F'.
  59.  *                   - Added ACTION_IS_FILESYSTEM.
  60.  *                   - Added 'write protected' error for write actions.
  61.  *                   - Added ACTION_CURRENT_VOLUME.
  62.  *                   - Unload handler code after ACTION_DIE.
  63.  *                   - Immediately terminate program if called from CLI.
  64.  *                   - Added library version number.
  65.  *                   - Set volume label to "Unnamed" for disks without name.
  66.  * 16-Sep-93   fmu   Added code to detect whether a lock stems from the
  67.  *                   current volume or from another volume which has
  68.  *                   been removed from the drive.
  69.  */
  70.  
  71. /*
  72.  *  Debugging routines are disabled by simply attempting to open the
  73.  *  file "debugoff", turned on again with "debugon".  No prefix may be
  74.  *  attached to these names (you must be CD'd to TEST:).
  75.  *
  76.  *  See Documentation for a detailed discussion.
  77.  */
  78.  
  79. #include <stdlib.h>
  80. #include <string.h>
  81.  
  82. #include "device.h"
  83. #include "intui.h"
  84. #include "devsupp.h"
  85. #include "cdcontrol.h"
  86. #include "params.h"
  87. #include "rock.h"
  88.  
  89. #ifdef __GNUC__
  90. struct Library *ixemulbase;
  91. #endif
  92.  
  93. /*
  94.  *  Since this code might be called several times in a row without being
  95.  *  unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
  96.  *  for any global/static assignments that might be changed by running the
  97.  *  code.
  98.  */
  99.  
  100. PROC    *DosProc;     /* Our Process                        */
  101. DEVNODE *DosNode;     /* Our DOS node.. created by DOS for us            */
  102. DEVLIST *DevList;     /* Device List structure for our volume node       */
  103.  
  104. EXECLIB *SysBase;     /* EXEC library base                */
  105. DOSLIB    *DOSBase;     /* DOS library base for debug process        */
  106. LIB    *UtilityBase; /* Utility library for miscellaneous tasks     */
  107.  
  108. CDROM   *g_cd;
  109. VOLUME  *g_volume;
  110. CDROM_OBJ *g_top_level_obj;
  111. char    *g_vol_name;
  112.  
  113. PORT *g_timer_mp;           /*  timer message port        */
  114. struct timerequest *g_timer_io; /*  timer i/o request        */
  115. ULONG g_timer_sigbit;
  116. ULONG g_dos_sigbit;
  117.  
  118. char    g_device[80];        /* SCSI device name */
  119. short    g_unit;            /* SCSI unit */
  120. short    g_use_rock_ridge;    /* Use Rock Ridge flag 'R' */
  121. short    g_maybe_map_to_lowercase;/* Conditional map to lower case flag 'ML' */
  122. short    g_map_to_lowercase;    /* Map to lower case flag 'L' */
  123. int     g_trackdisk;        /* Use trackdisk calls instead of SCSI-direct */
  124.  
  125. int    g_std_buffers;        /* Number of buffers for standard SCSI access */
  126. int    g_file_buffers;        /* Number of buffers for contiguous reads */
  127.  
  128. t_bool    g_show_version_numbers; /* Show version numbers */
  129.  
  130. int    g_scan_interval;    /* Time between successive diskchange checks */
  131.  
  132. t_bool    g_disk_inserted;    /* Is a disk inserted? */
  133.  
  134. char    g_play_cdda_command[80];/* Command invoked if appicon is activated */
  135.  
  136. int    g_inhibited;        /* Number of active INHIBIT(TRUE) packets */
  137.  
  138. struct MsgPort *DosTask;
  139.  
  140. #if !defined(NDEBUG) || defined(DEBUG_SECTORS)
  141.             /*    DEBUGGING            */
  142. PORT *Dbport;        /*    owned by the debug process    */
  143. PORT *Dback;        /*    owned by the DOS device driver    */
  144. short DBDisable;
  145. MSG DummyMsg;        /*    Dummy message that debug proc can use    */
  146. #endif
  147.  
  148. void *dosalloc(ulong);
  149. void dosfree (ulong *);
  150. void btos(LONG, char *);
  151. void *NextNode (NODE *);
  152. void *GetHead (LIST *);
  153. LOCK *cdlock(CDROM_OBJ *, int);
  154. void cdunlock (LOCK *);
  155. CDROM_OBJ *getlockfile (LONG);
  156. char *typetostr (int);
  157. void returnpacket(struct DosPacket *);
  158. int packetsqueued (void);
  159. int Check_For_Volume_Name_Prefix (char *);
  160. void Fill_FileInfoBlock (FIB *, CDROM_INFO *, VOLUME *);
  161. void Mount (void);
  162. void Unmount (int);
  163. int Mount_Check (void);
  164. void Check_Disk (void);
  165. void Send_Timer_Request (void);
  166. void Cleanup_Timer_Device (void);
  167. int Open_Timer_Device (void);
  168. void Send_Event (int);
  169. void Remove_Seglist (void);
  170. BPTR Make_FSSM (void);
  171. void Install_TD_Interrupt (void);
  172. void Uninstall_TD_Interrupt (void);
  173. void Remove_Volume_Node (DEVLIST*);
  174.  
  175. /*
  176.  *  Don't call the entry point main().  This way, if you make a mistake
  177.  *  with the compile options you'll get a link error.
  178.  */
  179.  
  180. #ifdef __GNUC__
  181. asm(".text; jmp pc@(_handler-.+2)");
  182. #endif
  183.  
  184. #if defined(LATTICE)
  185. int __saveds handler (void)
  186. #else
  187. int handler (void)
  188. #endif
  189. {
  190.     register PACKET *packet;
  191.     register short   error;
  192.     MSG     *msg;
  193.     ubyte   notdone = 1;
  194.     char    buf[256];
  195.     void    *tmp;
  196.     ULONG   signals;
  197.     ubyte   playing = FALSE;
  198.  
  199.     /*
  200.      *    Initialize all global variables. SysBase MUST be initialized before
  201.      *  we can make Exec calls. The DOS library is opened for the debug
  202.      *  process only.
  203.      */
  204.  
  205.     SysBase = *(EXECLIB **) 4L;
  206.     DosProc = (PROC *) FindTask(NULL);
  207.     if (DosProc->pr_CLI)
  208.       return RETURN_FAIL;
  209.     DOSBase = (DOSLIB *) OpenLibrary ((UBYTE *) "dos.library",37);
  210. #ifdef __GNUC__
  211.     ixemulbase = OpenLibrary ("ixemul.library", 0);
  212. #endif
  213.     UtilityBase = (LIB *) OpenLibrary ((UBYTE *) "utility.library",37);
  214.  
  215.     BUG2(DBDisable = 0;)                /*  Init. globals    */
  216.     BUG2(Dbport = Dback = NULL;)
  217.     DevList = NULL;
  218.     {
  219.     WaitPort(&DosProc->pr_MsgPort);     /*  Get Startup Packet    */
  220.     msg = GetMsg(&DosProc->pr_MsgPort);
  221.     packet = (PACKET *)msg->mn_Node.ln_Name;
  222.  
  223.     /*
  224.      *  Loading DosNode->dn_Task causes DOS *NOT* to startup a new
  225.      *  instance of the device driver for every reference.    E.G. if
  226.      *  you were writing a CON device you would want this field to
  227.      *  be NULL.
  228.      */
  229.  
  230.         DosNode = BTOC(packet->dp_Arg3);
  231.  
  232.     /*
  233.      *  Set dn_Task field which tells DOS not to startup a new
  234.      *  process on every reference.
  235.      */
  236.  
  237.         DosNode->dn_Task = &DosProc->pr_MsgPort;
  238.     DosTask = DosNode->dn_Task;
  239.  
  240.     Init_Intui ();
  241.  
  242. #ifdef __GNUC__
  243.     if (!ixemulbase)
  244.       Display_Error ("Cannot open ixemul.library");
  245. #endif
  246.  
  247.     if (UtilityBase && DOSBase &&
  248. #ifdef __GNUC__
  249.         ixemulbase &&
  250. #endif
  251.         Get_Startup (packet->dp_Arg2)) {
  252.         packet->dp_Res1 = DOS_TRUE;
  253.          packet->dp_Res2 = 0;
  254.  
  255.       /*
  256.        *  Load dn_Startup field with a BPTR to a FileSysStartupMsg.
  257.        *  (According to the official documentation, this is not
  258.        *  required. Some debugging tools, however, depend on it.)
  259.        */
  260.         
  261.         DosNode->dn_Startup = Make_FSSM ();
  262.  
  263.     } else {                /*    couldn't open dos.library   */
  264.         packet->dp_Res1 = DOS_FALSE;
  265.         packet->dp_Res2 = 333; /* any error code */
  266.         returnpacket(packet);
  267.         Forbid ();
  268.         Remove_Seglist ();
  269.         if (DOSBase) {
  270.           Close_Intui ();
  271.               if (UtilityBase)
  272.                 CloseLibrary (UtilityBase);
  273.           CloseLibrary ((struct Library *) DOSBase);
  274.         }
  275.         return 0;                /*    exit process            */
  276.     }
  277.     returnpacket(packet);
  278.     }
  279.  
  280.     g_inhibited = 0;
  281.  
  282.     g_disk_inserted = (Test_Unit_Ready (g_cd) ||
  283.                    Test_Unit_Ready (g_cd));
  284.  
  285.     /*
  286.      *    Initialize debugging code
  287.      */
  288.  
  289.     BUG2(dbinit();)
  290.  
  291.     BUG(dbprintf("%d std buffers, %d file buffers\n",
  292.              g_std_buffers, g_file_buffers);)
  293.  
  294.     g_timer_sigbit = 0;
  295.     if (g_scan_interval > 0) {
  296.       /* Initialize timer: */
  297.       if (Open_Timer_Device ())
  298.         Send_Timer_Request ();
  299.     }
  300.  
  301.     g_vol_name = dosalloc (128);
  302.  
  303.     /* Mount volume (if any disk is inserted): */
  304.     Mount ();
  305.  
  306.     g_dos_sigbit = 1L << DosProc->pr_MsgPort.mp_SigBit;
  307.  
  308.     /*
  309.      *    Here begins the endless loop, waiting for requests over our
  310.      *    message port and executing them.  Since requests are sent over
  311.      *    our message port, this precludes being able to call DOS functions
  312.      *    ourselves (that is why the debugging routines are a separate process)
  313.      */
  314.  
  315. top:
  316.     for (; notdone;) {
  317.     signals = Wait(g_dos_sigbit | g_timer_sigbit | g_app_sigbit);
  318.     if (signals & g_timer_sigbit) {
  319.       GetMsg (g_timer_mp);
  320.       if (!g_inhibited)
  321.         Check_Disk ();
  322.       Send_Timer_Request ();
  323.           if (g_retry_show_cdda_icon)
  324.         Show_CDDA_Icon ();
  325.     }
  326.     if (signals & g_app_sigbit) {
  327.       struct Message *msg;
  328.       while (msg = GetMsg (g_app_port)) {
  329.         ReplyMsg (msg);
  330.         if (g_play_cdda_command[0])
  331.           SystemTags ((UBYTE *) g_play_cdda_command,
  332.                   SYS_Input, Open ((UBYTE *) "NIL:", MODE_OLDFILE),
  333.                   SYS_Output, Open ((UBYTE *) "NIL:", MODE_NEWFILE),
  334.                   SYS_Asynch, TRUE,
  335.               TAG_END);
  336.         else {
  337.           int res;
  338.           if (playing)
  339.             res = Stop_Play_Audio (g_cd);
  340.           else
  341.             res = Start_Play_Audio (g_cd);
  342.               if (!res)
  343.             Display_Error ("Cannot perform play audio command!");
  344.           else
  345.             playing = !playing;
  346.         }
  347.       }
  348.     }
  349.     if (!(signals & g_dos_sigbit))
  350.       continue;
  351.     while (msg = GetMsg(&DosProc->pr_MsgPort)) {
  352.         packet = (PACKET *)msg->mn_Node.ln_Name;
  353.         packet->dp_Res1 = DOS_TRUE;
  354.         packet->dp_Res2 = 0;
  355.         error = 0;
  356. #ifndef NDEBUG
  357.         dbprintf("Packet: %3ld %08lx %08lx %08lx %10s ",
  358.         packet->dp_Type,
  359.         packet->dp_Arg1, packet->dp_Arg2,
  360.         packet->dp_Arg3,
  361.         typetostr(packet->dp_Type)
  362.         );
  363. #endif
  364.  
  365.             if (g_inhibited) {
  366.           switch (packet->dp_Type) {
  367.           /* packets we will handle even if the handler is inhibited: */
  368.           case ACTION_DIE:
  369.           case ACTION_INHIBIT:
  370.           case ACTION_MORE_CACHE:
  371.           case ACTION_DISK_INFO:
  372.             break;
  373.           /* packets we cannot handle because the handler is inhibited: */
  374.           default:
  375.             packet->dp_Res1 = DOS_FALSE;
  376.         packet->dp_Res2 = ERROR_NOT_A_DOS_DISK;
  377.             BUG(dbprintf("ERR=%ld\n", (long) packet->dp_Res2);)
  378.             returnpacket(packet);
  379.                 continue;            
  380.           }
  381.         } else if (DevList == NULL) {
  382.           switch (packet->dp_Type) {
  383.           /* packets we will handle even if no disk is inserted: */
  384.           case ACTION_DIE:
  385.           case ACTION_USER:
  386.           case ACTION_IS_FILESYSTEM:
  387.           case ACTION_INHIBIT:
  388.           case ACTION_MORE_CACHE:
  389.           case ACTION_FLUSH:
  390.           case ACTION_FREE_LOCK:
  391.         break;
  392.           /* packets we cannot handle because no disk is inserted: */
  393.           default:
  394.             packet->dp_Res1 = DOS_FALSE;
  395.             packet->dp_Res2 = (g_disk_inserted ? ERROR_NOT_A_DOS_DISK :
  396.                    ERROR_NO_DISK);
  397.             BUG(dbprintf("ERR=%ld\n", (long) packet->dp_Res2);)
  398.             returnpacket(packet);
  399.                 continue;            
  400.           }
  401.         }
  402.  
  403.         switch(packet->dp_Type) {
  404.         case ACTION_DIE:        /*    attempt to die?             */
  405.         notdone = 0;        /*    try to die                */
  406.         break;
  407.         case ACTION_USER:        /*  Mode,Par1,Par2            Bool    */
  408.             error = Handle_Control_Packet (packet->dp_Arg1,
  409.                            packet->dp_Arg2,
  410.                            packet->dp_Arg3);
  411.             break;
  412.         case ACTION_FINDINPUT:  /*  FileHandle,Lock,Name        Bool    */
  413.         {
  414.             if (Mount_Check ()) {
  415.               CDROM_OBJ *obj;
  416.               CDROM_OBJ *parentdir = getlockfile(packet->dp_Arg2);
  417.               int       offs;
  418.  
  419.               if (parentdir->volume != g_volume) {
  420.                   /* old lock from another disk: */
  421.             error = ERROR_DEVICE_NOT_MOUNTED;
  422.             goto openbreak;
  423.               }
  424.               
  425.               btos(packet->dp_Arg3,buf);
  426.               BUG(dbprintf("'%s' ", buf);)
  427.               offs = Check_For_Volume_Name_Prefix (buf);
  428.               if (obj = Open_Object (parentdir, buf + offs)) {
  429.                 if (obj->symlink_f) {
  430.                 error = ERROR_IS_SOFT_LINK;
  431.                 goto openbreak;
  432.             }
  433.             if (obj->directory_f) {
  434.                 error = ERROR_OBJECT_WRONG_TYPE;
  435.                 goto openbreak;
  436.             }
  437.               } else {
  438.             if (iso_errno == ISOERR_ILLEGAL_NAME) {
  439.                 error = ERROR_INVALID_COMPONENT_NAME;
  440.                 goto openbreak;
  441.             } else if (iso_errno == ISOERR_NOT_FOUND)
  442.                   error = ERROR_OBJECT_NOT_FOUND;
  443.             else if (iso_errno == ISOERR_NO_MEMORY) {
  444.               error = ERROR_NO_FREE_STORE;
  445.               goto openbreak;
  446.             } else if (iso_errno == ISOERR_IS_SYMLINK) {
  447.               error = ERROR_IS_SOFT_LINK;
  448.               goto openbreak;
  449.             } else {
  450.               error = 333;
  451.               goto openbreak;
  452.             }
  453.               }
  454.               if (!error) {
  455.                 g_volume->file_handles++;
  456.               ((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long) obj;
  457.             Register_File_Handle (obj);
  458.               }
  459.             } else
  460.               error = ERROR_NO_DISK;
  461.         }
  462.           openbreak:
  463.         break;
  464.         case ACTION_READ:        /*     FHArg1,CPTRBuffer,Length   ActLength  */
  465.         {
  466.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  467.             char      *ptr = (char *) packet->dp_Arg2;
  468.             long    length = packet->dp_Arg3;
  469.             int     actual;
  470.  
  471.             if (obj->volume != g_volume) {
  472.               /* old lock from another disk: */
  473.               error = ERROR_DEVICE_NOT_MOUNTED;
  474.               break;
  475.             }
  476.             actual = Read_From_File (obj, ptr, length);
  477.             packet->dp_Res1 = actual;
  478.         }
  479.         break;
  480.         case ACTION_END:        /*     FHArg1             Bool:TRUE  */
  481.         {
  482.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  483.  
  484.             if (obj->volume != g_volume) {
  485.               /* old lock from another disk: */
  486.               error = ERROR_DEVICE_NOT_MOUNTED;
  487.               break;
  488.             }
  489.             Unregister_File_Handle (obj);
  490.             Close_Object (obj);
  491.             g_volume->file_handles--;
  492.         }
  493.         break;
  494.         case ACTION_SEEK:        /*     FHArg1,Position,Mode        OldPosition*/
  495.             {
  496.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  497.             long offset = packet->dp_Arg2;
  498.             int mode = packet->dp_Arg3;
  499.             
  500.             if (obj->volume != g_volume) {
  501.               /* old lock from another disk: */
  502.               error = ERROR_DEVICE_NOT_MOUNTED;
  503.               break;
  504.             }
  505.             packet->dp_Res1 = obj->pos;
  506.             if (!Seek_Position (obj, offset, mode)) {
  507.               error = ERROR_SEEK_ERROR;
  508.               packet->dp_Res1 = -1;
  509.             }
  510.         }
  511.         break;
  512.         case ACTION_EXAMINE_NEXT: /*   Lock,Fib              Bool */
  513.         {
  514.             FIB       *fib = BTOC (packet->dp_Arg2);
  515.             CDROM_OBJ *dir = getlockfile (packet->dp_Arg1);
  516.             CDROM_INFO info;
  517.  
  518.             if (dir->volume != g_volume) {
  519.               /* old lock from another disk: */
  520.               error = ERROR_DEVICE_NOT_MOUNTED;
  521.               break;
  522.             }
  523.             if (!dir->directory_f) {
  524.             error = ERROR_OBJECT_WRONG_TYPE;
  525.             break;
  526.             }
  527.             if (Examine_Next (dir, &info,
  528.                           (unsigned long *) &fib->fib_DiskKey)) {
  529.               error = 0;
  530.               Fill_FileInfoBlock (fib, &info, dir->volume);
  531.             } else {
  532.               error = ERROR_NO_MORE_ENTRIES;
  533.             }
  534.             break;
  535.         }
  536.         case ACTION_EXAMINE_FH:     /*   FHArg1,Fib              Bool */
  537.         case ACTION_EXAMINE_OBJECT: /*   Lock,Fib              Bool */
  538.         {
  539.             FIB *fib = BTOC (packet->dp_Arg2);
  540.             CDROM_INFO info;
  541.             CDROM_OBJ *obj;
  542.  
  543.              if (packet->dp_Type == ACTION_EXAMINE_FH)
  544.                    obj = (CDROM_OBJ*) packet->dp_Arg1;
  545.             else
  546.                        obj = getlockfile (packet->dp_Arg1);
  547.             if (obj->volume != g_volume) {
  548.               /* old lock from another disk: */
  549.               error = ERROR_DEVICE_NOT_MOUNTED;
  550.               break;
  551.             }
  552.             fib->fib_DiskKey = 0;
  553.             error = 0;
  554.             if (!CDROM_Info (obj, &info))
  555.               error = -1;
  556.             else
  557.               Fill_FileInfoBlock (fib, &info, obj->volume);
  558.         }
  559.         break;
  560.         case ACTION_INFO:        /*    Lock, InfoData      Bool:TRUE    */
  561.         tmp = BTOC(packet->dp_Arg2);
  562.         error = -1;
  563.         /*  fall through    */
  564.         case ACTION_DISK_INFO:  /*    InfoData      Bool:TRUE    */
  565.         {
  566.           if (Mount_Check ()) {
  567.             register INFODATA *id;
  568.  
  569.             (error) ? (id = tmp) : (id = BTOC (packet->dp_Arg1));
  570.             error = 0;
  571.             memset (id, 0, sizeof(*id));
  572.             id->id_UnitNumber = g_unit;
  573.             id->id_VolumeNode = (long) CTOB (DevList);
  574.             id->id_InUse = 0;
  575.                 id->id_DiskState = ID_WRITE_PROTECTED;
  576.             if (g_inhibited) {
  577.               id->id_DiskType = 0x42555359 /* "BUSY" */;
  578.               id->id_NumBlocks     = 0;
  579.               id->id_BytesPerBlock = 0;
  580.             } else {
  581.               id->id_DiskType = ID_DOS_DISK;
  582.               id->id_NumBlocks     = Volume_Size (g_volume);
  583.               id->id_BytesPerBlock = Block_Size (g_volume);
  584.             }
  585.             id->id_NumBlocksUsed = id->id_NumBlocks;
  586.           }
  587.         }
  588.         break;
  589.         case ACTION_IS_FILESYSTEM:   /*  -                      Bool */
  590.           packet->dp_Res1 = DOSTRUE;
  591.           break;
  592.         case ACTION_PARENT_FH:  /*   FHArg1                     ParentLock */
  593.         case ACTION_PARENT:     /*     Lock                ParentLock */
  594.             {
  595.           if (Mount_Check ()) {
  596.             if (packet->dp_Arg1) {
  597.               CDROM_OBJ *obj;
  598.               CDROM_OBJ *parent;
  599.           
  600.               if (packet->dp_Type == ACTION_PARENT_FH)
  601.                 obj = (CDROM_OBJ*) packet->dp_Arg1;
  602.               else
  603.                 obj = getlockfile (packet->dp_Arg1);
  604.               if (obj->volume != g_volume) {
  605.                 /* old lock from another disk: */
  606.                 error = ERROR_DEVICE_NOT_MOUNTED;
  607.                 break;
  608.               }
  609.               if (Is_Top_Level_Object (obj)) {
  610.                 packet->dp_Res1 = packet->dp_Res2 = 0;
  611.               } else {
  612.                 parent = Find_Parent (obj);
  613.                 if (!parent) {
  614.                   if (iso_errno == ISOERR_NO_MEMORY)
  615.                     error = ERROR_NO_FREE_STORE;
  616.                   else
  617.                     error = ERROR_OBJECT_NOT_FOUND;
  618.                 } else {
  619.                   packet->dp_Res1 = (long)
  620.                 CTOB (cdlock (parent, ACCESS_READ));
  621.                 }
  622.               }
  623.             } else
  624.               error = ERROR_OBJECT_NOT_FOUND;
  625.           } else
  626.             error = ERROR_NO_DISK;
  627.         }
  628.         break;
  629.         case ACTION_LOCATE_OBJECT:    /*   Lock,Name,Mode        Lock       */
  630.         {
  631.           if (Mount_Check ()) {
  632.             CDROM_OBJ *parentdir = getlockfile (packet->dp_Arg1);
  633.                     CDROM_OBJ *obj;
  634.             int offs;
  635.  
  636.             if (parentdir->volume != g_volume) {
  637.               /* old lock from another disk: */
  638.               error = ERROR_DEVICE_NOT_MOUNTED;
  639.               break;
  640.             }
  641.             btos (packet->dp_Arg2, buf);
  642. #ifndef NDEBUG
  643.             dbprintf ("'%s' %ld ", buf, packet->dp_Arg3);
  644.             if (strcmp(buf,"debugoff") == 0)
  645.             DBDisable = 1;
  646.             if (strcmp(buf,"debugon") == 0)
  647.             DBDisable = 0;
  648. #endif
  649.  
  650.             offs = Check_For_Volume_Name_Prefix (buf);
  651.             if (buf[offs]==0) {
  652.               if (parentdir)
  653.                 obj = Clone_Object (parentdir);
  654.               else
  655.                 obj = Open_Top_Level_Directory (g_volume);
  656.             } else
  657.               obj = Open_Object (parentdir, buf + offs);
  658.             
  659.             if (obj) {
  660.               if (obj->symlink_f)
  661.                 error = ERROR_IS_SOFT_LINK;
  662.               else
  663.                 packet->dp_Res1 = (long) CTOB (cdlock (obj, packet->dp_Arg3));
  664.             } else {
  665.               if (iso_errno == ISOERR_SCSI_ERROR) {
  666.                 error = ERROR_OBJECT_NOT_FOUND;
  667.             Unmount (FALSE);
  668.               } else if (iso_errno == ISOERR_ILLEGAL_NAME)
  669.             error = ERROR_INVALID_COMPONENT_NAME;
  670.               else if (iso_errno == ISOERR_NOT_FOUND)
  671.             error = ERROR_OBJECT_NOT_FOUND;
  672.               else if (iso_errno == ISOERR_NO_MEMORY)
  673.                 error = ERROR_NO_FREE_STORE;
  674.               else if (iso_errno == ISOERR_IS_SYMLINK)
  675.                 error = ERROR_IS_SOFT_LINK;
  676.               else
  677.                 error = 333;
  678.             }
  679.           } else
  680.             error = ERROR_NO_DISK;
  681.         }
  682.         break;
  683.         case ACTION_COPY_DIR:   /*     Lock,                Lock       */
  684.             {
  685.           if (packet->dp_Arg1) {
  686.             CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  687.             CDROM_OBJ *new;
  688.             
  689.             if (obj->volume != g_volume) {
  690.               /* old lock from another disk: */
  691.               error = ERROR_DEVICE_NOT_MOUNTED;
  692.               break;
  693.             }
  694.             new = Clone_Object (obj);
  695.             if (!new)
  696.               error = ERROR_NO_FREE_STORE;
  697.             else
  698.               packet->dp_Res1 = (long) CTOB (cdlock (new, ACCESS_READ));
  699.           } else
  700.             packet->dp_Res1 = 0;
  701.         }
  702.         break;
  703.         case ACTION_FREE_LOCK:  /*     Lock,                Bool       */
  704.         if (packet->dp_Arg1);
  705.             cdunlock (BTOC(packet->dp_Arg1));
  706.         break;
  707.         case ACTION_CURRENT_VOLUME: /* FHArg1                   DevList    */
  708.             {
  709.           CDROM_OBJ *obj = (CDROM_OBJ*) packet->dp_Arg1;
  710.               if (obj)
  711.             packet->dp_Res1 = (long) CTOB (Find_Dev_List (obj));
  712.           else
  713.                 packet->dp_Res1 = (long) CTOB (DevList);
  714.               break;
  715.         }
  716.         case ACTION_INHIBIT:    /*     Bool                Bool       */
  717.                 if (packet->dp_Arg1 != DOS_FALSE) {
  718.                   /* true meens forbid access */
  719.           g_inhibited++;
  720.                   if (DevList)
  721.                     Unmount(FALSE);
  722.                   Hide_CDDA_Icon ();
  723.                   g_cd->t_changeint2 = -2;
  724.                 } else {
  725.                   /* false meens access allowed */
  726.           if (g_inhibited)
  727.             g_inhibited--;
  728.           if (g_inhibited == 0) {
  729.             g_disk_inserted = FALSE;
  730.                     Check_Disk();
  731.           }
  732.                 }
  733.         break;
  734.         /*
  735.          *  FINDINPUT and FINDOUTPUT normally should return the
  736.          *  'write protected' error. If the field 'Name', however,
  737.          *  designates the root (e.g. CD0:), then the 'wrong type'
  738.          *  error should be returned. Otherwise, AmigaDOS would do
  739.          *  some funny things (such as saying 'Volume CD0: is write-
  740.          *  protected') if you try to mount the handler with the
  741.          *  field 'Mount' set to 1.
  742.          */
  743.         case ACTION_FINDOUTPUT: /*   Handle  Lock  Name         Bool       */
  744.         case ACTION_FINDUPDATE: /*   Handle  Lock  Name         Bool       */
  745.         {
  746.           int pos;
  747.           
  748.           btos(packet->dp_Arg3,buf);
  749.           BUG(dbprintf("'%s' ", buf);)
  750.           if ((pos = Check_For_Volume_Name_Prefix (buf)) &&
  751.               buf[pos] == 0)
  752.         error = ERROR_OBJECT_WRONG_TYPE;
  753.           else
  754.         error = ERROR_DISK_WRITE_PROTECTED;
  755.           break;
  756.         }
  757.         case ACTION_SAME_LOCK: /*    Lock  Lock                 Bool       */
  758.         {
  759.           CDROM_OBJ *obj1 = getlockfile(packet->dp_Arg1),
  760.                     *obj2 = getlockfile(packet->dp_Arg2);
  761.  
  762.               if (Same_Objects (obj1, obj2))
  763.                 packet->dp_Res1 = DOSTRUE;
  764.           else
  765.                 packet->dp_Res1 = DOSFALSE;
  766.  
  767.           break;
  768.         }
  769.         case ACTION_READ_LINK: /*  Lock Name Buf Length         NumChar    */
  770.         {
  771.           CDROM_OBJ *obj;
  772.           CDROM_OBJ *parentdir = getlockfile (packet->dp_Arg1);
  773.           char *outbuf = (char *) packet->dp_Arg3;
  774.           t_ulong maxlength = packet->dp_Arg4;
  775.           int offs;
  776.           char buf[256];
  777.           int res;
  778.  
  779.           if (parentdir->volume != g_volume) {
  780.             /* old lock from another disk: */
  781.             error = ERROR_DEVICE_NOT_MOUNTED;
  782.             break;
  783.           }
  784.               BUG(dbprintf ("'%s' len=%lu ", packet->dp_Arg2, maxlength);)
  785.           offs = Check_For_Volume_Name_Prefix ((char *) packet->dp_Arg2);
  786.           obj = Open_Object (parentdir, (char *) packet->dp_Arg2 + offs);
  787.           if (obj) {
  788.             res = Get_Link_Name (obj, buf, sizeof (buf));
  789.         if (res == 0 ||
  790.             strlen (buf) + strlen (g_vol_name+1) + 1 >= maxlength)
  791.           strncpy (outbuf, "illegal_link", maxlength - 1);
  792.         else {
  793.           if (buf[0] == ':')
  794.             strcpy (outbuf, g_vol_name+1);
  795.           else
  796.             outbuf[0] = 0;
  797.           strcat (outbuf, buf);
  798.         }
  799.         outbuf[maxlength - 1] = 0;
  800.         Close_Object (obj);
  801.         packet->dp_Res1 = strlen (outbuf);
  802.           } else {
  803.         if (iso_errno == ISOERR_ILLEGAL_NAME)
  804.           error = ERROR_INVALID_COMPONENT_NAME;
  805.         else if (iso_errno == ISOERR_NOT_FOUND)
  806.           error = ERROR_OBJECT_NOT_FOUND;
  807.         else if (iso_errno == ISOERR_NO_MEMORY)
  808.           error = ERROR_NO_FREE_STORE;
  809.         else if (iso_errno == ISOERR_IS_SYMLINK)
  810.           error = ERROR_IS_SOFT_LINK;
  811.         else
  812.           error = 333;
  813.           }
  814.           break;
  815.         }
  816.         case ACTION_MAKE_LINK:
  817.         case ACTION_RENAME_DISK:
  818.         case ACTION_WRITE:
  819.         case ACTION_SET_PROTECT:
  820.         case ACTION_DELETE_OBJECT:
  821.         case ACTION_RENAME_OBJECT:
  822.         case ACTION_CREATE_DIR:
  823.         case ACTION_SET_COMMENT:
  824.         case ACTION_SET_DATE:
  825.         case ACTION_SET_FILE_SIZE:
  826.               error = ERROR_DISK_WRITE_PROTECTED;
  827.               break;
  828.         case ACTION_FLUSH:        /*     writeout bufs, disk motor off           */
  829.           break;
  830.         /*
  831.          *    A few other packet types which we do not support
  832.          */
  833.         case ACTION_MORE_CACHE: /*     #BufsToAdd            Bool       */
  834.         case ACTION_WAIT_CHAR:  /*     Timeout, ticks         Bool       */
  835.         case ACTION_SCREEN_MODE:/*     Bool(-1:RAW 0:CON)        OldState   */
  836.         default:
  837.         error = ERROR_ACTION_NOT_KNOWN;
  838.         break;
  839.         }
  840.         if (packet) {
  841.         if (error) {
  842.             BUG(dbprintf("ERR=%ld\n", error);)
  843.             packet->dp_Res1 = DOS_FALSE;
  844.             packet->dp_Res2 = error;
  845.         } else {
  846.             BUG(dbprintf("RES=%06lx\n", packet->dp_Res1));
  847.         }
  848.         returnpacket(packet);
  849.         }
  850.     }
  851.     }
  852.     BUG(dbprintf("Can we remove ourselves? ");)
  853.     Delay(100);        /*    I wanna even see the debug message! */
  854.     Forbid();
  855.     if (packetsqueued() ||
  856.         (g_volume && (g_volume->locks || g_volume->file_handles))) {
  857.     Permit();
  858.     BUG(dbprintf(" ..  not yet!\n");)
  859.     notdone = 1;
  860.     goto top;        /*  sorry... can't exit     */
  861.     } else
  862.     BUG(dbprintf(" ..  yes!\n");)
  863.  
  864.     /* remove timer device and any pending timer requests: */
  865.     if (g_timer_sigbit)
  866.       Cleanup_Timer_Device ();
  867.  
  868.     /* this is getting dangerous. We will unload our very own
  869.      * code via UnLoadSeg() and need to keep the system in
  870.      * Forbid() state in order to avoid getting the free memory
  871.      * reclaimed by other tasks. This means: *NO* Wait() after
  872.      * Unmount(TRUE) ist called!
  873.      */
  874.  
  875.     Unmount (TRUE);
  876.     
  877.     dosfree ((ulong *) g_vol_name);
  878.  
  879.     Cleanup_CDROM (g_cd);
  880.  
  881.     Close_Intui ();
  882.  
  883.     /*
  884.      *    Remove debug process, closedown, fall of the end of the world
  885.      *    (which is how you kill yourself if a PROCESS.  A TASK would have
  886.      *    had to RemTask(NULL) itself).
  887.      */
  888.  
  889.     BUG2(Delay (50);)
  890.     BUG2(dbuninit();)
  891.     if (UtilityBase)
  892.       CloseLibrary (UtilityBase);
  893.     if (DOSBase)
  894.       CloseLibrary ((struct Library *) DOSBase);
  895.     
  896.     return 0;
  897. }
  898.  
  899.  
  900. /*
  901.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  902.  *  can see by this and how the PACKET structure is extracted in the
  903.  *  GetMsg() of the main routine.
  904.  */
  905.  
  906. void returnpacket(struct DosPacket *packet)
  907. {
  908.     register struct Message *mess;
  909.     register struct MsgPort *replyport;
  910.  
  911.     replyport             = packet->dp_Port;
  912.     mess             = packet->dp_Link;
  913.     packet->dp_Port         = &DosProc->pr_MsgPort;
  914.     mess->mn_Node.ln_Name    = (char *)packet;
  915.     mess->mn_Node.ln_Succ    = NULL;
  916.     mess->mn_Node.ln_Pred    = NULL;
  917.     PutMsg(replyport, mess);
  918. }
  919.  
  920. /*
  921.  *  Are there any packets queued to our device?
  922.  */
  923.  
  924. int packetsqueued (void)
  925. {
  926.     return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
  927.         (void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
  928. }
  929.  
  930. /*
  931.  *  DOS MEMORY ROUTINES
  932.  *
  933.  *  DOS makes certain assumptions about LOCKS.    A lock must minimally be
  934.  *  a FileLock structure, with additional private information after the
  935.  *  FileLock structure.  The longword before the beginning of the structure
  936.  *  must contain the length of structure + 4.
  937.  *
  938.  *  NOTE!!!!! The workbench does not follow the rules and assumes it can
  939.  *  copy lock structures.  This means that if you want to be workbench
  940.  *  compatible, your lock structures must be EXACTLY sizeof(struct FileLock).
  941.  */
  942.  
  943. void *dosalloc(ulong bytes)
  944. {
  945.     register ulong *ptr;
  946.  
  947.     bytes += 4;
  948.     ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
  949.     *ptr = bytes;
  950.     return(ptr+1);
  951. }
  952.  
  953. void dosfree (ulong *ptr)
  954. {
  955.     --ptr;
  956.     FreeMem(ptr, *ptr);
  957. }
  958.  
  959. /*
  960.  *  Convert a BSTR into a normal string.. copying the string into buf.
  961.  *  I use normal strings for internal storage, and convert back and forth
  962.  *  when required.
  963.  */
  964.  
  965. void btos(LONG bstr, char *buf)
  966. {
  967.     unsigned char *str = BTOC(bstr);
  968.     bmov((char *) str+1, buf, *str);
  969.     buf[*str] = 0;
  970. }
  971.  
  972. /*
  973.  *  Some EXEC list handling routines not found in the EXEC library.
  974.  */
  975.  
  976. void *NextNode (NODE *node)
  977. {
  978.     node = node->mln_Succ;
  979.     if (node->mln_Succ == NULL)
  980.     return(NULL);
  981.     return(node);
  982. }
  983.  
  984. void *GetHead (LIST *list)
  985. {
  986.     if ((void *)list->mlh_Head != (void *)&list->mlh_Tail)
  987.     return(list->mlh_Head);
  988.     return(NULL);
  989. }
  990.  
  991. /*
  992.  *  The lock function.    The file has already been checked to see if it
  993.  *  is lockable given the mode.
  994.  */
  995.  
  996. LOCK *cdlock(CDROM_OBJ *cdfile, int mode)
  997. {
  998.   LOCK *lock = dosalloc (sizeof(LOCK));
  999.  
  1000.   cdfile->volume->locks++;
  1001.   lock->fl_Key = (LONG) Location (cdfile);
  1002.   lock->fl_Link = (long) cdfile;
  1003.   lock->fl_Access = ACCESS_READ;
  1004.   lock->fl_Task = &DosProc->pr_MsgPort;
  1005.   lock->fl_Volume = (BPTR) CTOB (DevList);
  1006.   Register_Lock (lock);
  1007.   return(lock);
  1008. }
  1009.  
  1010. void cdunlock (LOCK *lock)
  1011. {
  1012.   CDROM_OBJ *obj = (CDROM_OBJ *) lock->fl_Link;
  1013.  
  1014.   Unregister_Lock (lock);
  1015.   --obj->volume->locks;
  1016.   
  1017.   /* if all locks and filehandles have been removed, and if the volume
  1018.    * is not the current volume, then the volume node may be removed:
  1019.    */
  1020.   if (obj->volume != g_volume &&
  1021.       obj->volume->locks == 0 && obj->volume->file_handles == 0) {     
  1022.     VOLUME *vol = obj->volume;
  1023.     
  1024.     Forbid ();
  1025.       Remove_Volume_Node (vol->devlist);
  1026.     Permit ();
  1027.     Close_Object (obj);
  1028.     Close_Volume (vol);
  1029.     Send_Event (FALSE);
  1030.   } else
  1031.     Close_Object (obj);
  1032.  
  1033.   dosfree ((ulong *) lock);                /* free lock        */
  1034. }
  1035.  
  1036. /*
  1037.  *  GETLOCKFILE(bptrlock)
  1038.  *
  1039.  *  Return the CDROM_OBJ (file or directory) associated with the
  1040.  *  given lock, which is passed as a BPTR.
  1041.  *
  1042.  *  According to the DOS spec, the only way a NULL lock will ever be
  1043.  *  passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
  1044.  *  In anycase, If a NULL lock is passed to me I simply assume it means
  1045.  *  the root directory of the CDROM.
  1046.  */
  1047.  
  1048. CDROM_OBJ *getlockfile (LONG lock)
  1049. {
  1050.   LOCK *rl = BTOC (lock);
  1051.  
  1052.   if (rl)
  1053.     return (CDROM_OBJ *) rl->fl_Link;
  1054.   return g_top_level_obj;
  1055. }
  1056.  
  1057. /*
  1058.  * If p_pathname contains a ':' character, return the position of the first
  1059.  * character after ':'
  1060.  * Otherwise, return 0.
  1061.  */
  1062.  
  1063. int Check_For_Volume_Name_Prefix (char *p_pathname)
  1064. {
  1065.   char *pos = strchr (p_pathname, ':');
  1066.   
  1067.   return pos ? (pos - p_pathname) + 1 : 0;
  1068. }
  1069.  
  1070. /*
  1071.  * Fills a FileInfoBlock with the information contained in the
  1072.  * directory record of a CD-ROM directory or file.
  1073.  */
  1074.  
  1075. void Fill_FileInfoBlock (FIB *p_fib, CDROM_INFO *p_info, VOLUME *p_volume)
  1076. {
  1077.   char *src = p_info->name;
  1078.   char *dest = p_fib->fib_FileName+1;
  1079.   int len = p_info->name_length;
  1080.  
  1081.   if (p_info->symlink_f)
  1082.     p_fib->fib_DirEntryType = ST_SOFTLINK;
  1083.   else
  1084.     p_fib->fib_DirEntryType = p_info->directory_f ? ST_USERDIR : ST_FILE;
  1085.   
  1086.   /* I don't know exactly why I have to set fib_EntryType, but other
  1087.    * handlers (e.g. DiskHandler by J Toebes et.al.) also do this.
  1088.    */
  1089.    
  1090.   p_fib->fib_EntryType = p_fib->fib_DirEntryType;
  1091.   
  1092.   if (len == 1 && *src == ':') {
  1093.     /* root of file system: */
  1094.     p_fib->fib_DirEntryType = ST_USERDIR;
  1095.     /* file name == volume name: */
  1096.     memcpy (p_fib->fib_FileName, g_vol_name, (int)(g_vol_name[0])+1);
  1097.   } else {
  1098.     /* copy file name: */
  1099.     if (g_show_version_numbers) {
  1100.       p_fib->fib_FileName[0] = len;
  1101.       for (; len; len--)
  1102.         *dest++ = *src++;
  1103.     } else {
  1104.       short i, real_len=len;
  1105.       for (i=0; i<len; i++) {
  1106.         if (*src == ';')
  1107.       real_len = i;
  1108.         *dest++ = *src++;
  1109.       }
  1110.       p_fib->fib_FileName[0] = real_len;
  1111.     }
  1112.  
  1113.     if ((g_map_to_lowercase && p_volume->protocol == PRO_ISO) ||
  1114.         (g_maybe_map_to_lowercase && !p_volume->mixed_char_filenames)) {
  1115.       /* convert ISO filename to lowercase: */
  1116.       int i, len = p_fib->fib_FileName[0];
  1117.       char *cp = p_fib->fib_FileName + 1;
  1118.     
  1119.       for (i=0; i<len; i++, cp++)
  1120.         *cp = ToLower (*cp);
  1121.     }
  1122.   }
  1123.   p_fib->fib_Protection = 0;
  1124.   p_fib->fib_Size = p_info->file_length;
  1125.   p_fib->fib_NumBlocks = p_info->file_length >> 11;
  1126.   if (p_info->symlink_f)
  1127.     strcpy (p_fib->fib_Comment, "\x0DSymbolic link");
  1128.   else
  1129.     p_fib->fib_Comment[0] = 0;
  1130.  
  1131.   p_fib->fib_Date.ds_Days   = p_info->date / (24 * 60 * 60);
  1132.   p_fib->fib_Date.ds_Minute = (p_info->date % (24 * 60 * 60)) / 60;
  1133.   p_fib->fib_Date.ds_Tick   = (p_info->date % 60) * TICKS_PER_SECOND;
  1134. }
  1135.  
  1136. /*
  1137.  * Create Volume node and add to the device list. This will
  1138.  * cause the WORKBENCH to recognize us as a disk. If we don't
  1139.  * create a Volume node, Wb will not recognize us.
  1140.  */
  1141.  
  1142. void Create_Volume_Node (LONG p_disk_type, ULONG p_volume_date)
  1143. {
  1144.   DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  1145.   DEVLIST *dl;
  1146.   char *name;
  1147.  
  1148.   if (dl = Find_Volume_Node (g_vol_name + 1)) {
  1149.     BUG(dbprintf("[Reusing old volume node]");)
  1150.     Forbid ();
  1151.     DevList = dl;
  1152.     dl->dl_Task = &DosProc->pr_MsgPort;
  1153.     Permit ();
  1154.   } else {
  1155.     Forbid ();
  1156.     DevList = dl = dosalloc(sizeof(DEVLIST));
  1157.     dl->dl_Type = DLT_VOLUME;
  1158.     dl->dl_Task = &DosProc->pr_MsgPort;
  1159.     dl->dl_DiskType = p_disk_type;
  1160.     name = dosalloc (g_vol_name[0]+2);
  1161.     if (name) {
  1162.       dl->dl_Name = (BSTR) CTOB (name);
  1163.       memcpy (name, g_vol_name, g_vol_name[0]+2);
  1164.     }
  1165.     dl->dl_VolumeDate.ds_Days = p_volume_date / (24 * 60 * 60);
  1166.     dl->dl_VolumeDate.ds_Minute = (p_volume_date % (24 * 60 * 60)) / 60;
  1167.     dl->dl_VolumeDate.ds_Tick = (p_volume_date % 60) * TICKS_PER_SECOND;
  1168.     dl->dl_Next = di->di_DevInfo;
  1169.     di->di_DevInfo = (long)CTOB(dl);
  1170.     Permit ();
  1171.     Register_Volume_Node (dl);
  1172.   }
  1173. }
  1174.  
  1175. /*
  1176.  * Mount a volume.
  1177.  */
  1178.  
  1179. void Mount (void)
  1180. {
  1181.   char buf[33];
  1182.  
  1183.   if (Has_Audio_Tracks (g_cd))
  1184.     Show_CDDA_Icon ();
  1185.  
  1186.   g_volume = Open_Volume (g_cd, g_use_rock_ridge);
  1187.   if (!g_volume) {
  1188.     BUG(dbprintf ("!!! cannot open VOLUME (iso_errno=%d) !!!\n", iso_errno);)
  1189.     return;
  1190.   } else {
  1191.     g_disk_inserted = TRUE;
  1192.     g_cd->t_changeint2 = g_cd->t_changeint;
  1193.     g_top_level_obj = Open_Top_Level_Directory (g_volume);
  1194.     if (!g_top_level_obj) {
  1195.       BUG(dbprintf ("!!! cannot open top level directory !!!\n");)
  1196.       return;
  1197.     }
  1198.   }
  1199.   
  1200.   BUG(dbprintf ("***mounting*** ");)
  1201.  
  1202.   Volume_ID (g_volume, buf, sizeof (buf)-1);  
  1203.   g_vol_name[0] = strlen (buf);
  1204.   memcpy (g_vol_name+1, buf, strlen (buf));
  1205.  
  1206.   if (!(g_vol_name[0]))
  1207.     memcpy (g_vol_name, "\7Unnamed", 8);
  1208.  
  1209.   /* AmigaDOS expects the BCPL string g_vol_name to be null-terminated: */
  1210.   g_vol_name[(int)(g_vol_name[0])+1] = 0;
  1211.  
  1212.   /* convert ISO volume name to lowercase: */
  1213.   if ((g_map_to_lowercase && g_volume->protocol == PRO_ISO) ||
  1214.       (g_maybe_map_to_lowercase && !g_volume->mixed_char_filenames)) {
  1215.     int i;
  1216.     for (i=0; i<g_vol_name[0]; i++)
  1217.       g_vol_name[i+1] = ToLower (g_vol_name[i+1]);
  1218.   }
  1219.  
  1220.   g_volume->locks = Reinstall_Locks ();
  1221.   g_volume->file_handles = Reinstall_File_Handles ();
  1222.  
  1223.   Create_Volume_Node (ID_DOS_DISK, Volume_Creation_Date (g_volume));
  1224.   g_volume->devlist = DevList;
  1225.   g_cd->t_changeint2 = g_cd->t_changeint;
  1226.   Send_Event (TRUE);
  1227. }
  1228.  
  1229. void Remove_Seglist (void)
  1230. {
  1231.   DOSINFO *di;
  1232.   void *dlp;
  1233.   DEVNODE *dn;
  1234.  
  1235.   di = BTOC (((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  1236.   dlp = &di->di_DevInfo;
  1237.   dn = BTOC (di->di_DevInfo);
  1238.  
  1239.   while (dn) {
  1240.     if (dn->dn_Task == DosTask) {
  1241.       BUG(dbprintf("got it!\n");)
  1242.       if (TypeOfMem (BADDR (dn->dn_SegList))) {
  1243.     UnLoadSeg (dn->dn_SegList);
  1244.     dn->dn_SegList = 0;
  1245.       } else
  1246.     BUG(dbprintf("not a valid seglist\n");)
  1247.  
  1248.       dn->dn_Task = NULL;
  1249.  
  1250.       *(BPTR *) dlp = dn->dn_Next;
  1251.       dosfree ((ulong *) dn);
  1252.  
  1253.       break;
  1254.     } else {
  1255.       dlp = &dn->dn_Next;
  1256.       dn = BTOC (dn->dn_Next);
  1257.     }
  1258.   }
  1259. }
  1260.  
  1261. /*  Remove a volume node from the DOS list.
  1262.  *  (Must be nested between Forbid() and Permit()!)
  1263.  *  Since DOS uses singly linked lists, we must (ugg) search it manually to find
  1264.  *  the link before our Volume entry.
  1265.  */
  1266.  
  1267. void Remove_Volume_Node (DEVLIST* p_volume)
  1268. {
  1269.   DOSINFO *di;
  1270.   DEVLIST *dl;
  1271.   void *dlp;
  1272.  
  1273.   Unregister_Volume_Node (p_volume);
  1274.  
  1275.   di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  1276.  
  1277.   dlp = &di->di_DevInfo;
  1278.   for (dl = BTOC(di->di_DevInfo); dl && dl != p_volume; dl = BTOC(dl->dl_Next))
  1279.     dlp = &dl->dl_Next;
  1280.   if (dl == p_volume) {
  1281.     *(BPTR *)dlp = dl->dl_Next;
  1282.     dosfree((ulong *) BTOC (dl->dl_Name));
  1283.     dosfree((ulong *) dl);
  1284.   } else {
  1285.     BUG(dbprintf("****PANIC: Unable to find volume node\n");)
  1286.   }
  1287. }
  1288.  
  1289. /*  Unmount a volume, and optionally unload the handler code.
  1290.  */
  1291.  
  1292. void Unmount (int p_remove_seglist)
  1293. {
  1294.   g_cd->t_changeint2 = g_cd->t_changeint;
  1295.   Hide_CDDA_Icon ();
  1296.  
  1297.   Forbid ();
  1298.  
  1299.   if (DevList) {
  1300.  
  1301.     BUG(dbprintf("***unmounting***");)
  1302.     
  1303.     Close_Object (g_top_level_obj);
  1304.     
  1305.     if (g_volume->locks == 0 && g_volume->file_handles == 0) {
  1306.       Remove_Volume_Node (DevList);
  1307.       Close_Volume (g_volume);
  1308.     } else {
  1309.       BUG(dbprintf("[there are still %d locks on this volume]",
  1310.                  g_volume->locks);)
  1311.       BUG(dbprintf("[there are still %d file handles on this volume]",
  1312.                  g_volume->file_handles);)
  1313.       DevList->dl_Task = NULL;
  1314.     }
  1315.  
  1316.     DevList = NULL;
  1317.   }
  1318.  
  1319.   Send_Event (FALSE);
  1320.  
  1321.   g_volume = 0;
  1322.  
  1323.   /* when the handler code exits the corresponding device
  1324.    * node (e.g. "CD0") will be modified. The handler code
  1325.    * will be unloaded and the task entry will be set to
  1326.    * zero, so the next device access will reload and
  1327.    * restart the handler code.
  1328.    */
  1329.  
  1330.   if (p_remove_seglist) {
  1331.     Remove_Seglist ();
  1332.   } else
  1333.     Permit ();
  1334. }
  1335.  
  1336. /*
  1337.  * Mount_Check returns 1 if a valid disk is inserted in the drive. A check is
  1338.  * only performed if previously the drive was empty.
  1339.  */
  1340.  
  1341. int Mount_Check (void)
  1342. {
  1343.   if (!g_disk_inserted) {
  1344.    /*
  1345.     * No disk was inserted up to now: we will check whether
  1346.     * a disk has been inserted by sending the test unit ready
  1347.     * command. We have to send the command twice because
  1348.     * the first SCSI command after inserting a new disk is
  1349.     * always rejected.
  1350.     */
  1351.     if (Test_Unit_Ready (g_cd) ||
  1352.         Test_Unit_Ready (g_cd)) {
  1353.       g_disk_inserted = TRUE;
  1354.       Mount ();
  1355.     } else {
  1356.       return 0;
  1357.     }
  1358.     if (DevList)
  1359.       return 1;
  1360.     else {
  1361.       /* Mount() did not succeed: */
  1362.       return 0;
  1363.     }
  1364.   }
  1365.   return 1;
  1366. }
  1367.  
  1368. /*
  1369.  *  Open timer device structures:
  1370.  */
  1371.  
  1372. int Open_Timer_Device (void)
  1373. {
  1374.   if (!(g_timer_mp = CreateMsgPort ())) {
  1375.     BUG(dbprintf ("cannot create timer message port!\n");)
  1376.     return 0;
  1377.   }
  1378.   if (!(g_timer_io = (struct timerequest *)
  1379.        CreateIORequest (g_timer_mp, sizeof (struct timerequest)))) {
  1380.     BUG(dbprintf ("cannot create timer i/o structure!\n");)
  1381.     DeleteMsgPort (g_timer_mp);
  1382.     return 0;
  1383.   }
  1384.   if (OpenDevice ((UBYTE *) TIMERNAME, UNIT_VBLANK,
  1385.             (struct IORequest *) g_timer_io, 0)) {
  1386.     BUG(dbprintf ("cannot open timer device!\n");)
  1387.     DeleteIORequest ((struct IORequest *) g_timer_io);
  1388.     DeleteMsgPort (g_timer_mp);
  1389.     return 0;
  1390.   }
  1391.   g_timer_sigbit = 1L << g_timer_mp->mp_SigBit;
  1392.   return 1;
  1393. }
  1394.  
  1395. /*
  1396.  *  Remove timer device structures:
  1397.  */
  1398.  
  1399. void Cleanup_Timer_Device (void)
  1400. {
  1401.   /* remove any pending requests: */
  1402.   if (!CheckIO ((struct IORequest *) g_timer_io))
  1403.     AbortIO ((struct IORequest *) g_timer_io);
  1404.   WaitIO ((struct IORequest *) g_timer_io);
  1405.   
  1406.   CloseDevice ((struct IORequest *) g_timer_io);
  1407.   DeleteIORequest ((struct IORequest *) g_timer_io);
  1408.   DeleteMsgPort (g_timer_mp);
  1409. }
  1410.  
  1411. /*
  1412.  *  Send timer request
  1413.  */
  1414.  
  1415. void Send_Timer_Request (void)
  1416. {
  1417.   g_timer_io->tr_node.io_Command = TR_ADDREQUEST;
  1418.   g_timer_io->tr_time.tv_secs = g_scan_interval;
  1419.   g_timer_io->tr_time.tv_micro = 0;
  1420.   SendIO ((struct IORequest *) g_timer_io);
  1421. }
  1422.  
  1423. /*
  1424.  *  Check whether the disk has been removed or inserted.
  1425.  */
  1426.  
  1427. void Check_Disk (void)
  1428. {
  1429.   int i;
  1430.   unsigned long l1, l2;
  1431.  
  1432.   BUG(dbprintf ("Checking Disk... ");)
  1433.   if (g_cd->use_trackdisk) {
  1434.     i = (Test_Unit_Ready (g_cd) ||
  1435.          Test_Unit_Ready (g_cd));
  1436.     l1 = g_cd->t_changeint;
  1437.     l2 = g_cd->t_changeint2;
  1438.     BUG(if (l1==l2 && i) dbprintf ("no disk change (T %ld)", l1);)
  1439.     if (l1!=l2 && i) {
  1440.       g_disk_inserted = TRUE;
  1441.       BUG(dbprintf ("disk has been inserted (T %ld)", l1);)
  1442.       if (DevList)
  1443.         Unmount (FALSE);
  1444.       Delay (50);
  1445.       Clear_Sector_Buffers (g_cd);
  1446.       Mount ();
  1447.     }
  1448.     BUG(if (l1==l2 && !i) dbprintf ("no disk in drive (T %ld)", l1);)
  1449.     if (l1!=l2 && !i) {
  1450.       g_disk_inserted = FALSE;
  1451.       BUG(dbprintf ("disk has been removed (T %ld)", l1);)
  1452.       if (DevList)
  1453.         Unmount (FALSE);
  1454.       g_cd->t_changeint2 = g_cd->t_changeint;
  1455.     }
  1456.   } else {
  1457.     if (g_disk_inserted) {
  1458.       if (Test_Unit_Ready (g_cd)) {
  1459.         BUG(dbprintf ("no disk change"));
  1460.       } else {
  1461.         g_disk_inserted = FALSE;
  1462.         BUG(dbprintf ("disk has been removed");)
  1463.         if (DevList)
  1464.           Unmount (FALSE);
  1465.         Hide_CDDA_Icon ();
  1466.       }
  1467.     }
  1468.     if (!g_disk_inserted) {
  1469.       if (Test_Unit_Ready (g_cd) ||
  1470.           Test_Unit_Ready (g_cd)) {
  1471.         g_disk_inserted = TRUE;
  1472.         BUG(dbprintf ("disk has been inserted");)
  1473.         Clear_Sector_Buffers (g_cd);
  1474.         Mount ();
  1475.       }
  1476.     }
  1477.   }
  1478.   BUG(dbprintf ("\n");)
  1479. }
  1480.  
  1481. /* The following lines will generate a `disk inserted/removed' event, in order
  1482.  * to get Workbench to rescan the DosList and update the list of
  1483.  * volume icons.
  1484.  */
  1485.  
  1486. void Send_Event (int p_inserted)
  1487. {
  1488.   struct IOStdReq *InputRequest;
  1489.   struct MsgPort *InputPort;
  1490.  
  1491.   if (InputPort = (struct MsgPort *) CreateMsgPort ()) {
  1492.     if (InputRequest = (struct IOStdReq *)
  1493.         CreateIORequest (InputPort, sizeof (struct IOStdReq))) {
  1494.       if (!OpenDevice ((UBYTE *) "input.device", 0,
  1495.                      (struct IORequest *) InputRequest, 0)) {
  1496.     static struct InputEvent InputEvent;
  1497.  
  1498.     memset (&InputEvent, 0, sizeof (struct InputEvent));
  1499.  
  1500.     InputEvent.ie_Class = p_inserted ? IECLASS_DISKINSERTED :
  1501.                        IECLASS_DISKREMOVED;
  1502.  
  1503.     InputRequest->io_Command = IND_WRITEEVENT;
  1504.     InputRequest->io_Data = &InputEvent;
  1505.     InputRequest->io_Length = sizeof (struct InputEvent);
  1506.  
  1507.     DoIO ((struct IORequest *) InputRequest);
  1508.  
  1509.     CloseDevice ((struct IORequest *) InputRequest);
  1510.       }
  1511.       DeleteIORequest (InputRequest);
  1512.     }
  1513.     DeleteMsgPort (InputPort);
  1514.   }
  1515. }
  1516.  
  1517. BPTR Make_FSSM (void)
  1518. {
  1519.   struct FileSysStartupMsg* fssm;
  1520.   struct DosEnvec *env;
  1521.   char *dev;
  1522.   
  1523.   fssm = dosalloc (sizeof (*fssm));
  1524.   fssm->fssm_Unit = g_unit;
  1525.   dev = dosalloc (strlen (g_device) + 2);
  1526.   strcpy (dev+1, g_device);
  1527.   dev[0] = strlen (g_device);
  1528.   fssm->fssm_Device = (BPTR) CTOB (dev);
  1529.   env = dosalloc (sizeof (struct DosEnvec));
  1530.   env->de_TableSize = 19;
  1531.   env->de_SizeBlock = 2048;
  1532.   env->de_Surfaces = 1;
  1533.   env->de_SectorPerBlock = 1;
  1534.   env->de_BlocksPerTrack = 1;
  1535.   env->de_DosType = 0x4E444F53; /* NDOS */
  1536.   fssm->fssm_Environ = (BPTR) CTOB (env);
  1537.   fssm->fssm_Flags = 0;
  1538.  
  1539.   return (BPTR) CTOB (fssm);
  1540. }
  1541.