home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 396.lha / MSH_v1.30s / src / pack.c < prev    next >
C/C++ Source or Header  |  1990-07-10  |  26KB  |  1,055 lines

  1. /*-
  2.  * $Id: pack.c,v 1.30 90/06/04 23:15:58 Rhialto Rel $
  3.  * $Log:    pack.c,v $
  4.  * Revision 1.30  90/06/04  23:15:58  Rhialto
  5.  * Release 1 Patch 3
  6.  * 
  7.  *  Originally:
  8.  *
  9.  *    DOSDEVICE.C        V1.10   2 November 1987
  10.  *
  11.  *    EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C    PUBLIC DOMAIN.
  12.  *
  13.  *    By Matthew Dillon.
  14.  *
  15.  *  This has been stripped and refilled with messydos code
  16.  *  by Olaf Seibert.
  17.  *
  18.  *  This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  19.  *  not be used or copied without a licence.
  20.  *
  21.  *  Please note that we are NOT pure, so if you wish to mount
  22.  *  multiple MSDOS units, you must use different copies of this driver.
  23.  *
  24.  *  This file forms the interface between the actual handler code and all
  25.  *  AmigaDOS requirements. It shields it from ugly stuff like BPTRs, BSTRs,
  26.  *  FileLocks, FileHandles and VolumeNodes (in the form of DeviceLists).
  27.  *  Also, most protection against non-inserted disks is done here.
  28. -*/
  29.  
  30. #include "dos.h"
  31. #include "han.h"
  32.  
  33. #ifdef HDEBUG
  34. #   define    debug(x)  dbprintf x
  35. #else
  36. #   define    debug(x)
  37. #endif
  38.  
  39. /*
  40.  * Since this code might be called several times in a row without being
  41.  * unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
  42.  * for any global/static assignments that might be changed by running the
  43.  * code.
  44.  */
  45.  
  46. PORT           *DosPort;    /* Our DOS port... */
  47. DEVNODE        *DevNode;    /* Our DOS node.. created by DOS for us */
  48. DEVLIST        *VolNode;    /* Device List structure for our volume
  49.                  * node */
  50.  
  51. void           *SysBase;    /* EXEC library base */
  52. DOSLIB           *DOSBase;    /* DOS library base for debug process */
  53. long        PortMask;    /* The signal mask for our DosPort */
  54. long        WaitMask;    /* The signal mask to wait for */
  55. short        DiskChanged;    /* Set by disk change interrupt */
  56. short        Inhibited;    /* Are we inhibited (ACTION_INHIBIT)? */
  57. long        UnitNr;     /* From */
  58. char           *DevName;    /*   the */
  59. ulong        DevFlags;    /*     mountlist */
  60. long        DosType;
  61. PACKET           *DosPacket;    /* For the SystemRequest pr_WindowPtr */
  62.  
  63. void ChangeIntHand(), DiskChange();
  64. void NewVolNodeName(), NewVolNodeDate();
  65.  
  66. struct Interrupt ChangeInt = {
  67.     { 0 },            /* is_Node */
  68.     0,                /* is_Data */
  69.     ChangeIntHand,        /* is_Code */
  70. };
  71.  
  72. /*
  73.  * Don't call the entry point main().  This way, if you make a mistake
  74.  * with the compile options you'll get a link error.
  75.  */
  76.  
  77. void
  78. messydoshandler()
  79. {
  80.     register PACKET *packet;
  81.     MSG        *msg;
  82.     byte        notdone;
  83.     long        OpenCount;        /* How many open files/locks there are */
  84.  
  85.     /*
  86.      * Initialize all global variables.  SysBase MUST be initialized
  87.      * before we can make Exec calls.  AbsExecBase is a library symbol
  88.      * referencing absolute memory location 4.
  89.      */
  90.  
  91.     SysBase = AbsExecBase;
  92.     DOSBase = OpenLibrary("dos.library", 0L);
  93.  
  94. #ifdef HDEBUG
  95.     /*
  96.      * Initialize debugging code as soon as possible. Only SysBase and
  97.      * DOSBase are required.
  98.      */
  99.  
  100.     dbinit();
  101. #endif                /* HDEBUG */
  102.  
  103.     DosPort = &((struct Process *)FindTask(NULL))->pr_MsgPort;
  104.  
  105.     WaitPort(DosPort);      /* Get Startup Packet  */
  106.     msg = GetMsg(DosPort);
  107.     packet = (PACKET *) msg->mn_Node.ln_Name;
  108.  
  109.  
  110.     DevNode = BTOC(PArg3);
  111.     {
  112.     struct FileSysStartupMsg *fssm;
  113.     ulong *environ;
  114.     ulong Reserved;
  115.  
  116.     DevName = "messydisk.device";
  117.     UnitNr = 0;
  118.     DevFlags = 0;
  119.  
  120.     MaxCache = 5;
  121.     BufMemType = MEMF_PUBLIC;
  122.     Disk.nsides = MS_NSIDES;
  123.     Disk.spt = MS_SPT;
  124.     Disk.bps = MS_BPS;
  125.     Disk.lowcyl = 0;
  126.     Reserved = 0;
  127.  
  128.     if (fssm = (struct FileSysStartupMsg *)BTOC(DevNode->dn_Startup)) {
  129.                     /* Same as BTOC(packet->dp_Arg2) */
  130.         UnitNr = fssm->fssm_Unit;
  131.         if (fssm->fssm_Device)
  132.         DevName = (char *)BTOC(fssm->fssm_Device)+1;
  133.         DevFlags = fssm->fssm_Flags;
  134.  
  135.         if (environ = BTOC(fssm->fssm_Environ)) {
  136.         debug(("environ size %ld\n", environ[0]));
  137. #define get(xx,yy)  if (environ[DE_TABLESIZE] >= yy) xx = environ[yy];
  138.  
  139.         get(MaxCache, DE_NUMBUFFERS);
  140.         get(BufMemType, DE_MEMBUFTYPE);
  141.         get(Disk.nsides, DE_NUMHEADS);
  142.         get(Disk.spt, DE_BLKSPERTRACK);
  143.         get(Disk.bps, DE_SIZEBLOCK);
  144.         Disk.bps *= 4;
  145.         debug(("Disk.bps %d\n", Disk.bps));
  146.         get(Disk.lowcyl, DE_LOWCYL);
  147.         get(Reserved, DE_RESERVEDBLKS);
  148.         get(DosType, DE_DOSTYPE);
  149. #undef get
  150.         }
  151.     }
  152.     Disk.lowcyl *= (long)MS_BPS * Disk.spt * Disk.nsides;
  153.     Disk.lowcyl += (long)MS_BPS * Reserved;
  154.     }
  155.  
  156.     if (DOSBase && HanOpenUp()) {
  157.     /*
  158.      * Loading DevNode->dn_Task causes DOS *NOT* to startup a new
  159.      * instance of the device driver for every reference.    E.G. if
  160.      * you were writing a CON: device you would want this field to be
  161.      * NULL.
  162.      */
  163.  
  164.     DevNode->dn_Task = DosPort;
  165.  
  166.     PRes1 = DOSTRUE;
  167.     PRes2 = 0;
  168.     } else {            /* couldn't open dos.library  */
  169.     PRes1 = DOSFALSE;
  170.     PRes2 = ERROR_DEVICE_NOT_MOUNTED;   /* no better message available */
  171.     returnpacket(packet);
  172.     goto exit;        /* exit process    */
  173.     }
  174.     returnpacket(packet);
  175.  
  176.     /* Initialize some more global variables    */
  177.  
  178.     PortMask = 1L << DosPort->mp_SigBit;
  179.     VolNode = NULL;
  180.     OpenCount = 0;
  181.     Inhibited = 0;
  182.  
  183.     /* Get the first real packet       */
  184.     WaitPort(DosPort);
  185.     msg = GetMsg(DosPort);
  186.     notdone = 1;
  187.     WaitMask = PortMask | (1L << DiskReplyPort->mp_SigBit);
  188.     TDAddChangeInt(&ChangeInt);
  189.     DiskInserted(WhichDiskInserted());
  190.  
  191.     goto entry;
  192.  
  193.     /*
  194.      * Here begins the endless loop, waiting for requests over our message
  195.      * port and executing them.  Since requests are sent over the message
  196.      * port in our device and volume nodes, we must not use our Process
  197.      * message port for this: this precludes being able to call DOS
  198.      * functions ourselves.
  199.      */
  200.  
  201. top:
  202.     for (notdone = 1; notdone;) {
  203.     Wait(WaitMask);
  204.     if (DiskChanged)
  205.         DiskChange();
  206.     while (msg = GetMsg(DosPort)) {
  207.         byte        buf[256];    /* Max length of BCPL strings is
  208.                      * 255 + 1 for \0. */
  209.  
  210.     entry:
  211.         if (DiskChanged)
  212.         DiskChange();
  213.         packet = (PACKET *) msg->mn_Node.ln_Name;
  214.         PRes1 = DOSFALSE;
  215.         PRes2 = 0;
  216.         error = 0;
  217.         debug(("Packet: %3ld %08lx %08lx %08lx %10s\n",
  218.              PType, PArg1, PArg2, PArg3, typetostr(PType)));
  219.  
  220.         DosPacket = packet;     /* For the System Requesters */
  221.         switch (PType) {
  222.         case ACTION_DIE:        /* attempt to die?  */
  223.         notdone = 0;        /* try to die     */
  224.         break;
  225.         case ACTION_CURRENT_VOLUME: /* -              VolNode,UnitNr */
  226.         PRes1 = (long) CTOB(VolNode);
  227.         PRes2 = UnitNr;
  228.         break;
  229.         case ACTION_LOCATE_OBJECT:    /* Lock,Name,Mode    Lock         */
  230.         {
  231.             register struct FileLock *newlock;
  232.             struct FileLock *lock;
  233.             struct MSFileLock *msfl;
  234.             long        lockmode;
  235.  
  236.             lock = BTOC(PArg1);
  237.             if (CheckRead(lock))
  238.             break;
  239.             btos(PArg2, buf);
  240.             if ((lockmode = PArg3) != EXCLUSIVE_LOCK)
  241.             lockmode = SHARED_LOCK;
  242.             msfl = MSLock(lock ? lock->fl_Key : NULL,
  243.                   buf,
  244.                   lockmode);
  245.             if (msfl) {
  246.             if (newlock = NewFileLock(msfl, lock)) {
  247.                 newlock->fl_Access = lockmode;
  248.                 PRes1 = (long) CTOB(newlock);
  249.                 OpenCount++;
  250.             } else
  251.                 MSUnLock(msfl);
  252.             }
  253.         }
  254.         break;
  255.         case ACTION_RENAME_DISK:    /* BSTR:NewName        Bool      */
  256.         if (CheckWrite(NULL))
  257.             break;
  258.         btos(PArg1, buf);
  259.         buf[31] = '\0';
  260.         if (PRes1 = MSRelabel(buf))
  261.             NewVolNodeName();
  262.         break;
  263.         case ACTION_FREE_LOCK:    /* Lock            Bool      */
  264.         {
  265.             struct FileLock *lock;
  266.             struct MSFileLock *msfl;
  267.  
  268.             PRes1 = DOSTRUE;
  269.             lock = BTOC(PArg1);
  270.             if (lock == NULL)
  271.             break;
  272.  
  273.             msfl = (struct MSFileLock *)lock->fl_Key;
  274.             FreeFileLock(lock); /* may remove last lock on volume */
  275.             MSUnLock(msfl);     /* may call MayFreeVolNode */
  276.             OpenCount--;
  277.         }
  278.         break;
  279.         case ACTION_DELETE_OBJECT:    /* Lock,Name        Bool         */
  280.         {
  281.             struct FileLock *lock;
  282.  
  283.             lock = BTOC(PArg1);
  284.             if (CheckWrite(lock))
  285.             break;
  286.             btos(PArg2, buf);
  287.             PRes1 = MSDeleteFile(lock ? lock->fl_Key : NULL,
  288.                      buf);
  289.         }
  290.         break;
  291.         case ACTION_RENAME_OBJECT:    /* SLock,SName,DLock,DName   Bool    */
  292.         {
  293.             struct FileLock *slock, *dlock;
  294.             char         buf2[256];
  295.  
  296.             slock = BTOC(PArg1);
  297.             dlock = BTOC(PArg3);
  298.             if (CheckWrite(slock) || CheckWrite(dlock))
  299.             break;
  300.             btos(PArg2, buf);
  301.             btos(PArg4, buf2);
  302.             PRes1 = MSRename(slock ? slock->fl_Key : NULL,
  303.                      buf,
  304.                      dlock ? dlock->fl_Key : NULL,
  305.                      buf2);
  306.         }
  307.         break;
  308.         case ACTION_MORECACHE:    /* #BufsToAdd           Bool      */
  309.         if ((MaxCache += (short) PArg1) <= 0) {
  310.             MaxCache = 1;
  311.         } else
  312.             PRes1 = DOSTRUE;
  313.         debug(("Now %d cache sectors\n", MaxCache));
  314.         break;
  315.         case ACTION_COPY_DIR:    /* Lock            Lock      */
  316.         {
  317.             register struct FileLock *newlock;
  318.             struct FileLock *lock;
  319.             struct MSFileLock *msfl;
  320.  
  321.             lock = BTOC(PArg1);
  322.  
  323.             msfl = MSDupLock(lock ? lock->fl_Key : NULL);
  324.  
  325.             if (msfl) {
  326.             if (newlock = NewFileLock(msfl, lock)) {
  327.                 newlock->fl_Access =
  328.                 lock ? lock->fl_Access : SHARED_LOCK;
  329.                 PRes1 = (long) CTOB(newlock);
  330.                 OpenCount++;
  331.             } else
  332.                 MSUnLock(msfl);
  333.             }
  334.         }
  335.         break;
  336.         case ACTION_SET_PROTECT:    /* -,Lock,Name,Mask       Bool      */
  337.         {
  338.             struct FileLock *lock;
  339.  
  340.             lock = BTOC(PArg2);
  341.             if (CheckWrite(lock))
  342.             break;
  343.             btos(PArg3, buf);
  344.             PRes1 = MSSetProtect(lock ? lock->fl_Key : NULL, buf, PArg4);
  345.         }
  346.         break;
  347.         case ACTION_CREATE_DIR:    /* Lock,Name        Lock         */
  348.         {
  349.             register struct FileLock *newlock;
  350.             struct FileLock *lock;
  351.             struct MSFileLock *msfl;
  352.  
  353.             lock = BTOC(PArg1);
  354.             if (CheckWrite(lock))
  355.             break;
  356.             btos(PArg2, buf);
  357.  
  358.             msfl = MSCreateDir(lock ? lock->fl_Key : NULL, buf);
  359.  
  360.             if (msfl) {
  361.             if (newlock = NewFileLock(msfl, lock)) {
  362.                 newlock->fl_Access = SHARED_LOCK;
  363.                 PRes1 = (long) CTOB(newlock);
  364.                 OpenCount++;
  365.             } else
  366.                 MSUnLock(msfl);
  367.             }
  368.         }
  369.         break;
  370.         case ACTION_EXAMINE_OBJECT: /* Lock,Fib           Bool         */
  371.         {
  372.             struct FileLock *lock;
  373.  
  374.             lock = BTOC(PArg1);
  375.             if (CheckRead(lock))
  376.             break;
  377.             PRes1 = MSExamine(lock ? lock->fl_Key : NULL, BTOC(PArg2));
  378.         }
  379.         break;
  380.         case ACTION_EXAMINE_NEXT:    /* Lock,Fib           Bool         */
  381.         {
  382.             struct FileLock *lock;
  383.  
  384.             lock = BTOC(PArg1);
  385.             if (CheckRead(lock))
  386.             break;
  387.             PRes1 = MSExNext(lock ? lock->fl_Key : NULL, BTOC(PArg2));
  388.         }
  389.         break;
  390.         case ACTION_DISK_INFO:    /* InfoData           Bool:TRUE     */
  391.         PRes1 = MSDiskInfo(BTOC(PArg1));
  392.         break;
  393.         case ACTION_INFO:    /* Lock,InfoData           Bool:TRUE     */
  394.         if (CheckRead(BTOC(PArg1)))
  395.             break;
  396.         PRes1 = MSDiskInfo(BTOC(PArg2));
  397.         break;
  398.         case ACTION_FLUSH:        /* writeout bufs, disk motor off     */
  399.         MSUpdate(1);
  400.         break;
  401. /*        case ACTION_SET_COMMENT:    /* -,Lock,Name,Comment       Bool      */
  402.         case ACTION_PARENT: /* Lock                ParentLock    */
  403.         {
  404.             register struct FileLock *newlock;
  405.             struct FileLock *lock;
  406.             struct MSFileLock *msfl;
  407.             long mode;
  408.  
  409.             lock = BTOC(PArg1);
  410.  
  411.             msfl = MSParentDir(lock ? lock->fl_Key : NULL);
  412.  
  413.             if (msfl) {
  414.             if (newlock = NewFileLock(msfl, lock)) {
  415.                 newlock->fl_Access = SHARED_LOCK;
  416.                 PRes1 = (long) CTOB(newlock);
  417.                 OpenCount++;
  418.             } else
  419.                 MSUnLock(msfl);
  420.             }
  421.         }
  422.         break;
  423.         case ACTION_INHIBIT:    /* Bool            Bool      */
  424.         if (Inhibited = PArg1) {
  425.             DiskRemoved();
  426.         } else { /* Fall through to ACTION_DISK_CHANGE: */
  427.         case ACTION_DISK_CHANGE:    /* ?               ?         */
  428.             DiskChange();
  429.         }
  430.         PRes1 = DOSTRUE;
  431.         break;
  432.         case ACTION_SET_DATE: /* -,Lock,Name,CPTRDateStamp       Bool      */
  433.         {
  434.             struct FileLock *lock;
  435.  
  436.             lock = BTOC(PArg2);
  437.             if (CheckWrite(lock))
  438.             break;
  439.             btos(PArg3, buf);
  440.             PRes1 = MSSetDate(lock ? lock->fl_Key : NULL,
  441.                       buf,
  442.                       PArg4);
  443.         }
  444.         break;
  445.         case ACTION_READ:    /* FHArg1,CPTRBuffer,Length      ActLength  */
  446.         if (CheckRead(NULL)) {
  447.             PRes1 = -1;
  448.         } else
  449.             PRes1 = MSRead(PArg1, PArg2, PArg3);
  450.         break;
  451.         case ACTION_WRITE:    /* FHArg1,CPTRBuffer,Length      ActLength  */
  452.         if (CheckWrite(NULL)) {
  453.             PRes1 = -1;
  454.         } else
  455.             PRes1 = MSWrite(PArg1, PArg2, PArg3);
  456.         break;
  457.         case ACTION_OPENNEW:    /* FileHandle,Lock,Name    Bool      */
  458.         {
  459.             struct MSFileHandle *msfh;
  460.             struct FileHandle *fh;
  461.             struct FileLock *lock;
  462.  
  463.             if (CheckWrite(BTOC(PArg2)))
  464.             break;
  465.         case ACTION_OPENRW:     /* FileHandle,Lock,Name    Bool      */
  466.         case ACTION_OPENOLD:    /* FileHandle,Lock,Name    Bool      */
  467.  
  468.             fh = BTOC(PArg1);
  469.             lock = BTOC(PArg2);
  470.             if (CheckRead(lock))
  471.             break;
  472.             btos(PArg3, buf);
  473.             debug(("'%s' ", buf));
  474.             msfh = MSOpen(lock ? lock->fl_Key : NULL,
  475.                   buf,
  476.                   PType);
  477.             if (msfh) {
  478.             fh->fh_Arg1 = (long) msfh;
  479.             PRes1 = DOSTRUE;
  480.             OpenCount++;
  481.             }
  482.         }
  483.         break;
  484.         case ACTION_CLOSE:    /* FHArg1              Bool:TRUE  */
  485.         MSClose(PArg1);
  486.         PRes1 = DOSTRUE;
  487.         OpenCount--;
  488.         break;
  489.         case ACTION_SEEK:    /* FHArg1,Position,Mode      OldPosition */
  490.         if (CheckRead(NULL)) {
  491.             PRes1 = -1;
  492.         } else
  493.             PRes1 = MSSeek(PArg1, PArg2, PArg3);
  494.         break;
  495.         /*
  496.          * A few other packet types which we do not support
  497.          */
  498. /*        case ACTION_WAIT_CHAR:    /* Timeout, ticks       Bool      */
  499. /*        case ACTION_RAWMODE:    /* Bool(-1:RAW 0:CON)      OldState  */
  500.         default:
  501.         error = ERROR_ACTION_NOT_KNOWN;
  502.         break;
  503.         } /* end switch */
  504.         if (packet) {
  505.         if (error) {
  506.             debug(("ERR=%d\n", error));
  507.             PRes2 = error;
  508.         }
  509. #ifdef HDEBUG
  510.         else {
  511.             debug(("RES=%06lx\n", PRes1));
  512.         }
  513. #endif
  514.         returnpacket(packet);
  515.         DosPacket = NULL;
  516.         }
  517. #ifdef HDEBUG
  518.         else {
  519.         debug(("NOREP\n"));
  520.         }
  521. #endif
  522.     } /* end while (GetMsg()) */
  523.  
  524.     /*
  525.      *  Now check for an other cause of events: timer IO.
  526.      *  Unfortunately we cannot be sure that we always get a signal
  527.      *  when the timeout has elapsed, since the same message port is
  528.      *  used for other IO.
  529.      */
  530.     if (CheckIO(TimeIOReq)) {   /* Timer finished? */
  531.         debug(("TimeIOReq is finished\n"));
  532.         if (DelayState != DELAY_OFF) {
  533.         MSUpdate(0);    /* Also may switch off motor */
  534.         }
  535.     }
  536.     } /* end for (;notdone) */
  537.  
  538. #ifdef HDEBUG
  539.     debug(("Can we remove ourselves? "));
  540.     Delay(50L);                 /* I wanna even see the debug message! */
  541. #endif                /* HDEBUG */
  542.     Forbid();
  543.     if (OpenCount || packetsqueued()) {
  544.     Permit();
  545.     debug((" ..  not yet!\n"));
  546.     goto top;        /* sorry... can't exit     */
  547.     }
  548.     debug((" .. yes!\n"));
  549.  
  550.     /*
  551.      * Causes a new process to be created on next reference.
  552.      */
  553.  
  554.     DevNode->dn_Task = NULL;
  555.     TDRemChangeInt();
  556.     DiskRemoved();
  557.     HanCloseDown();
  558.     debug(("HanCloseDown returned. dbuninit in 2 seconds:\n"));
  559.  
  560.     /*
  561.      * Remove debug window, closedown, fall of the end of the world.
  562.      */
  563. exit:
  564. #ifdef HDEBUG
  565.     Delay(100L);                /* This is dangerous! */
  566.     dbuninit();
  567. #endif                /* HDEBUG */
  568.  
  569. #if 1
  570.     UnLoadSeg(DevNode->dn_SegList);     /* This is real fun. We are still */
  571.     DevNode->dn_SegList = NULL;     /* Forbid()den, fortunately */
  572. #endif
  573.  
  574.     CloseLibrary(DOSBase);
  575.  
  576.     /* Fall off the end of the world. Implicit Permit(). */
  577. }
  578.  
  579. void
  580. ChangeIntHand()
  581. {
  582. /* INDENT OFF */
  583. #asm
  584.     move.l  a6,-(sp)
  585. #endasm
  586.     DiskChanged = 1;
  587.     Signal(DosPort->mp_SigTask, PortMask);
  588. #asm
  589.     move.l  (sp)+,a6
  590. #endasm
  591. /* INDENT ON */
  592. }
  593.  
  594. /*
  595.  *  Make a new struct FileLock, for DOS use. It is put on a singly linked
  596.  *  list, which is attached to the same VolumeNode the old lock was on.
  597.  *
  598.  *  Also note that we must ALWAYS be prepared to UnLock() or DupLock()
  599.  *  any FileLocks we ever made, even if the volume in question has been
  600.  *  removed and/or inserted into another drive with another FileSystem
  601.  *  handler!
  602.  *
  603.  * DOS makes certain assumptions about LOCKS.    A lock must minimally be a
  604.  * FileLock structure, with additional private information after the
  605.  * FileLock structure.    The longword before the beginning of the structure
  606.  * must contain the length of structure + 4.
  607.  *
  608.  * NOTE!!!!! The workbench does not follow the rules and assumes it can copy
  609.  * lock structures.  This means that if you want to be workbench
  610.  * compatible, your lock structures must be EXACTLY sizeof(struct
  611.  * FileLock). Also, it sometimes uses uninitialized values for the lock mode...
  612.  */
  613.  
  614. struct FileLock *
  615. NewFileLock(msfl, fl)
  616. struct MSFileLock *msfl;
  617. struct FileLock *fl;
  618. {
  619.     struct FileLock *newlock;
  620.     DEVLIST *volnode;
  621.  
  622.     if (fl) {
  623.     volnode = BTOC(fl->fl_Volume);
  624.     } else {
  625.     volnode = VolNode;
  626.     }
  627.  
  628.     if (newlock = dosalloc((ulong)sizeof (*newlock))) {
  629.     newlock->fl_Key = (ulong) msfl;
  630.     newlock->fl_Task = DosPort;
  631.     newlock->fl_Volume = (BPTR) CTOB(volnode);
  632.     Forbid();
  633.     newlock->fl_Link = volnode->dl_LockList;
  634.     volnode->dl_LockList = (BPTR) CTOB(newlock);
  635.     Permit();
  636.     } else
  637.     error = ERROR_NO_FREE_STORE;
  638.  
  639.     return newlock;
  640. }
  641.  
  642. /*
  643.  *  This should be called before MSUnLock(), so that it may call
  644.  *  MayFreeVolNode() which then calls FreeVolNode(). A bit tricky,
  645.  *  I'm sorry for that.
  646.  */
  647.  
  648. long
  649. FreeFileLock(lock)
  650. struct FileLock *lock;
  651. {
  652.     register struct FileLock *fl;
  653.     register struct FileLock **flp;
  654.     DEVLIST       *volnode;
  655.  
  656.     volnode = (DEVLIST *)BTOC(lock->fl_Volume);
  657.     flp = (struct FileLock **) &volnode->dl_LockList;
  658.     for (fl = BTOC(*flp); fl && fl != lock; fl = BTOC(fl->fl_Link))
  659.     flp = (struct FileLock **)&fl->fl_Link;
  660.  
  661.     if (fl == lock) {
  662.     *(BPTR *)flp = fl->fl_Link;
  663.     dosfree(fl);
  664.     return DOSTRUE;
  665.     } else {
  666.     debug(("Huh?? Could not find filelock!\n"));
  667.     return DOSFALSE;
  668.     }
  669. }
  670.  
  671. /*
  672.  * Create Volume node and add to the device list.   This will
  673.  * cause the WORKBENCH to recognize us as a disk.   If we
  674.  * don't create a Volume node, Wb will not recognize us.
  675.  * However, we are a MESSYDOS: disk, Volume node or not.
  676.  */
  677.  
  678. DEVLIST        *
  679. NewVolNode(name, date)
  680. struct DateStamp *date;
  681. char *name;
  682. {
  683.     DOSINFO       *di;
  684.     register DEVLIST *volnode;
  685.     char       *volname;        /* This is my volume name */
  686.  
  687.     di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  688.  
  689.     if (volnode = dosalloc((ulong)sizeof (DEVLIST))) {
  690.     if (volname = dosalloc(32L)) {
  691.         volname[0] = strlen(name);
  692.         strcpy(volname + 1, name);      /* Make sure \0 terminated */
  693.  
  694.         volnode->dl_Type = DLT_VOLUME;
  695.         volnode->dl_Task = DosPort;
  696.         volnode->dl_DiskType = IDDiskType;
  697.         volnode->dl_Name = CTOB(volname);
  698.         volnode->dl_VolumeDate = *date;
  699.         volnode->dl_MSFileLockList = NULL;
  700.  
  701.         Forbid();
  702.         volnode->dl_Next = di->di_DevInfo;
  703.         di->di_DevInfo = (long) CTOB(volnode);
  704.         Permit();
  705.     } else {
  706.         dosfree(volnode);
  707.         volnode = NULL;
  708.     }
  709.     } else {
  710.     error = ERROR_NO_FREE_STORE;
  711.     }
  712.  
  713.     return volnode;
  714. }
  715.  
  716. /*
  717.  *  Get the current VolNode a new name from the volume label.
  718.  */
  719.  
  720. void
  721. NewVolNodeName()
  722. {
  723.     if (VolNode) {
  724.     register char *volname = BTOC(VolNode->dl_Name);
  725.  
  726.     strncpy(volname + 1, Disk.vollabel.de_Msd.msd_Name, 8+3);
  727.     volname[1+8+3] = '\0';      /* Make sure \0 terminated */
  728.     ZapSpaces(volname + 1, volname + 1 + 8+3);
  729.     volname[0] = strlen(volname+1);
  730.     }
  731. }
  732.  
  733. /*
  734.  *  Get the current VolNode a new date, from the last root directory.
  735.  */
  736.  
  737. void
  738. NewVolNodeDate()
  739. {
  740.     if (VolNode) {
  741.     ToDateStamp(&VolNode->dl_VolumeDate,
  742.             Disk.vollabel.de_Msd.msd_Date,
  743.             Disk.vollabel.de_Msd.msd_Time);
  744.     }
  745. }
  746.  
  747. /*
  748.  * Remove Volume entry.  Since DOS uses singly linked lists, we must
  749.  * (ugg) search it manually to find the link before our Volume entry.
  750.  */
  751.  
  752. void
  753. FreeVolNode(volnode)
  754. DEVLIST        *volnode;
  755. {
  756.     DOSINFO       *di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  757.     register DEVLIST *dl;
  758.     register void  *dlp;
  759.  
  760.     debug(("FreeVolNode %08lx\n", volnode));
  761.  
  762.     if (volnode == NULL)
  763.     return;
  764.  
  765.     dlp = &di->di_DevInfo;
  766.     Forbid();
  767.     for (dl = BTOC(di->di_DevInfo); dl && dl != volnode; dl = BTOC(dl->dl_Next))
  768.     dlp = &dl->dl_Next;
  769.     if (dl == volnode) {
  770.     *(BPTR *) dlp = dl->dl_Next;
  771.     dosfree(BTOC(dl->dl_Name));
  772.     dosfree(dl);
  773.     }
  774. #ifdef HDEBUG
  775.     else {
  776.     debug(("****PANIC: Unable to find volume node\n"));
  777.     }
  778. #endif                /* HDEBUG */
  779.     Permit();
  780.  
  781.     if (volnode == VolNode)
  782.     VolNode = NULL;
  783. }
  784.  
  785. /*
  786.  *  This is also called from the real handler when the last lock on a
  787.  *  volume is UnLock()ed, or the last file has been Close()d.
  788.  */
  789.  
  790. int
  791. MayFreeVolNode(volnode)
  792. DEVLIST *volnode;
  793. {
  794.     if (volnode->dl_LockList == NULL) {
  795.     FreeVolNode(volnode);
  796.     return 1;
  797.     }
  798.  
  799.     return 0;
  800. }
  801.  
  802. /*
  803.  *  Our disk has been removed. Save the FileLocks in the dl_LockList,
  804.  *  and let the handler save its MSFileLocks in the dl_MSFileLockList field.
  805.  *  If it has nothing to save, forget about the volume, and return
  806.  *  DOSTRUE.
  807.  *  There is one subtlety that MSDiskRemoved must know about:
  808.  *  If it MSUnLock()s the last lock on the volume, the VolNode is
  809.  *  deleted via FreeLockList().. MayFreeVolNode().. FreeVolNode().
  810.  *  But then there is no place anymore to put NULL in, so that needs
  811.  *  to be done first.
  812.  */
  813.  
  814. int
  815. DiskRemoved()
  816. {
  817.     debug(("DiskRemoved %08lx\n", VolNode));
  818.  
  819.     if (VolNode == NULL) {
  820.     IDDiskType = ID_NO_DISK_PRESENT;/* really business of MSDiskRemoved */
  821.     return DOSTRUE;
  822.     }
  823.  
  824.     VolNode->dl_Task = NULL;
  825.     MSDiskRemoved(&VolNode->dl_MSFileLockList);
  826.     if (VolNode == NULL) {  /* Could happen via MSDiskRemoved() */
  827.     return DOSTRUE;
  828.     }
  829.     NewVolNodeDate();       /* Fetch new date of root directory */
  830.     VolNode = NULL;
  831.     return DOSFALSE;
  832. }
  833.  
  834. /*
  835.  *  Reconstruct everything from a Volume node
  836.  */
  837.  
  838. void
  839. DiskInserted(volnode)
  840. register DEVLIST    *volnode;
  841. {
  842.     debug(("DiskInserted %08lx\n", volnode));
  843.  
  844.     VolNode = volnode;
  845.  
  846.     if (volnode) {
  847.     volnode->dl_Task = DosPort;
  848.     MSDiskInserted(&volnode->dl_MSFileLockList, volnode);
  849.     volnode->dl_MSFileLockList = NULL;
  850.     }
  851. }
  852.  
  853. DEVLIST *
  854. WhichDiskInserted()
  855. {
  856.     char name[34];
  857.     struct DateStamp date;
  858.     register DEVLIST *dl = NULL;
  859.  
  860.     if (!Inhibited && IdentifyDisk(name, &date) == 0) {
  861.     DOSINFO        *di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  862.     byte           *nodename;
  863.     int        namelen = strlen(name);
  864.  
  865.     for (dl = BTOC(di->di_DevInfo); dl; dl = BTOC(dl->dl_Next)) {
  866.         nodename = BTOC(dl->dl_Name);
  867.         if (nodename[0] != namelen || strncmp(nodename+1,name,namelen))
  868.         continue;
  869.         if (dl->dl_VolumeDate == date)  /* Non-standard! Structure compare! */
  870.         break;
  871.     }
  872.  
  873.     name[31] = '\0';
  874.     if (dl == NULL)
  875.         dl = NewVolNode(name, &date);
  876.     }
  877.  
  878.     return dl;
  879. }
  880.  
  881. void
  882. DiskChange()
  883. {
  884.     debug(("DiskChange\n"));
  885.     DiskChanged = 0;
  886.     DiskRemoved();
  887.     DiskInserted(WhichDiskInserted());
  888. }
  889.  
  890. int
  891. CheckRead(lock)
  892. struct FileLock *lock;
  893. {
  894.     if (lock && BTOC(lock->fl_Volume) != VolNode)
  895.     error = ERROR_DEVICE_NOT_MOUNTED;
  896.     else if (IDDiskType == ID_NO_DISK_PRESENT)
  897.     error = ERROR_NO_DISK;
  898.     else if (IDDiskType != ID_DOS_DISK)
  899.     error = ERROR_NOT_A_DOS_DISK;
  900.  
  901.     return error;
  902. }
  903.  
  904. int
  905. CheckWrite(lock)
  906. struct FileLock *lock;
  907. {
  908.     if (lock && BTOC(lock->fl_Volume) != VolNode)
  909.     error = ERROR_DEVICE_NOT_MOUNTED;
  910.     else if (IDDiskType == ID_NO_DISK_PRESENT)
  911.     error = ERROR_NO_DISK;
  912.     else if (IDDiskType != ID_DOS_DISK)
  913.     error = ERROR_NOT_A_DOS_DISK;
  914.     else if (IDDiskState == ID_VALIDATING)
  915.     error = ERROR_DISK_NOT_VALIDATED;
  916.     else if (IDDiskState != ID_VALIDATED)
  917.     error = ERROR_DISK_WRITE_PROTECTED;
  918.  
  919.     return error;
  920. }
  921.  
  922. #ifdef HDEBUG
  923.             /*    DEBUGGING            */
  924. PORT *Dbport;        /*    owned by the debug process    */
  925. PORT *Dback;        /*    owned by the DOS device driver    */
  926. short DBEnable;
  927.  
  928. /*
  929.  *  DEBUGGING CODE.    You cannot make DOS library calls that access other
  930.  *  devices from within a DOS device driver because they use the same
  931.  *  message port as the driver.  If you need to make such calls you must
  932.  *  create a port and construct the DOS messages yourself.  I do not
  933.  *  do this.  To get debugging info out another PROCESS is created to which
  934.  *  debugging messages can be sent.
  935.  */
  936.  
  937. extern void debugproc();
  938.  
  939. dbinit()
  940. {
  941.     TASK *task = FindTask(NULL);
  942.  
  943.     Dback = CreatePort("MSH:Dback", -1L);
  944.     CreateProc("MSH_DB", (long)task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096L);
  945.     WaitPort(Dback);                                /* handshake startup    */
  946.     GetMsg(Dback);                                  /* remove dummy msg     */
  947.     DBEnable = 1;
  948.     dbprintf("Debugger running V1.10\n");
  949. }
  950.  
  951. dbuninit()
  952. {
  953.     MSG killmsg;
  954.  
  955.     if (Dbport) {
  956.     killmsg.mn_Length = 0;        /*    0 means die        */
  957.     PutMsg(Dbport,  &killmsg);
  958.     WaitPort(Dback);            /*  He's dead jim!      */
  959.     GetMsg(Dback);
  960.     DeletePort(Dback);
  961.  
  962.     /*
  963.      *  Since the debug process is running at a greater priority, I
  964.      *  am pretty sure that it is guarenteed to be completely removed
  965.      *  before this task gets control again.  Still, it doesn't hurt...
  966.      */
  967.  
  968.     Delay(50L);                 /*  ensure he's dead    */
  969.     }
  970. }
  971.  
  972. dbprintf(a,b,c,d,e,f,g,h,i,j)
  973. long a,b,c,d,e,f,g,h,i,j;
  974. {
  975.     struct {
  976.     MSG    msg;
  977.     char    buf[256];
  978.     } msgbuf;
  979.     register MSG *msg = &msgbuf.msg;
  980.     register long len;
  981.  
  982.     if (Dbport && DBEnable) {
  983.     sprintf(msgbuf.buf,a,b,c,d,e,f,g,h,i,j);
  984.     len = strlen(msgbuf.buf)+1;
  985.     msg->mn_Length = len;    /*  Length NEVER 0  */
  986.     PutMsg(Dbport, msg);
  987.     WaitPort(Dback);
  988.     GetMsg(Dback);
  989.     }
  990. }
  991.  
  992. /*
  993.  *  BTW, the DOS library used by debugmain() was actually opened by
  994.  *  the device driver.
  995.  */
  996.  
  997. debugmain()
  998. {
  999.     register MSG *msg;
  1000.     register long len;
  1001.     register void *fh;
  1002.     void *fh2;
  1003.     MSG DummyMsg;
  1004.  
  1005.     Dbport = CreatePort("MSH:Dbport", -1L);
  1006.     fh = Open("CON:0/10/640/190/FileSystem debug", MODE_NEWFILE);
  1007.     fh2 = Open("PAR:", MODE_OLDFILE);
  1008.     PutMsg(Dback, &DummyMsg);
  1009.     for (;;) {
  1010.     WaitPort(Dbport);
  1011.     msg = GetMsg(Dbport);
  1012.     len = msg->mn_Length;
  1013.     if (len == 0)
  1014.         break;
  1015.     --len;                /*    Fix length up    */
  1016.     if (DBEnable & 1)
  1017.         Write(fh, msg+1, len);
  1018.     if (DBEnable & 2)
  1019.         Write(fh2, msg+1, len);
  1020.     PutMsg(Dback, msg);
  1021.     }
  1022.     Close(fh);
  1023.     Close(fh2);
  1024.     DeletePort(Dbport);
  1025.     PutMsg(Dback, msg);             /*  Kill handshake  */
  1026. }
  1027.  
  1028. /*
  1029.  *  The assembly tag for the DOS process:  CNOP causes alignment problems
  1030.  *  with the Aztec assembler for some reason.  I assume then, that the
  1031.  *  alignment is unknown.  Since the BCPL conversion basically zero's the
  1032.  *  lower two bits of the address the actual code may start anywhere
  1033.  *  within 8 bytes of address (remember the first longword is a segment
  1034.  *  pointer and skipped).  Sigh....  (see CreateProc() above).
  1035.  */
  1036.  
  1037. #asm
  1038.     public    _debugproc
  1039.     public    _debugmain
  1040.  
  1041.     cseg
  1042. _debugproc:
  1043.     nop
  1044.     nop
  1045.     nop
  1046.     nop
  1047.     nop
  1048.     movem.l D2-D7/A2-A6,-(sp)
  1049.     jsr    _debugmain
  1050.     movem.l (sp)+,D2-D7/A2-A6
  1051.     rts
  1052. #endasm
  1053.  
  1054. #endif                /* HDEBUG */
  1055.