home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 1 / FishNMoreVol1.bin / more / code_examples / device / device.c < prev    next >
C/C++ Source or Header  |  1987-10-23  |  27KB  |  1,044 lines

  1.  
  2. /*
  3.  *  DOSDEVICE.C
  4.  *
  5.  *  EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C   PUBLIC DOMAIN.
  6.  *
  7.  *  By Matthew Dillon.
  8.  *
  9.  *  Debugging routines are disabled by simply attempting to access the
  10.  *  file "debugoff"
  11.  */
  12.  
  13. #include "dos.h"
  14.  
  15. /*
  16.  *  Since this code might be called as a processes multiple times, or
  17.  *  might exit and be recalled later by DOS, you CANNOT ASSUME GLOBALS
  18.  *  HAVE BEEN ZERO'D!!!.    This also goes for static assignments that
  19.  *  running the code might change.
  20.  */
  21.  
  22. PROC    *DosProc;
  23. DEVNODE *DosNode;
  24.  
  25. long    SysBase;
  26. long    DOSBase;
  27. RAMFILE RFRoot;     /*    Directory/File structure    (root node) */
  28. LIST    FHBase;     /*    Open Files                */
  29. LIST    LCBase;     /*    Open Locks                */
  30.  
  31. long    TotalBytes;
  32.  
  33.  
  34.             /*    DEBUGGING            */
  35. PORT *Dbport;        /*    owned by the debug process    */
  36. PORT *Dback;        /*    owned by the DOS device driver    */
  37. short DBDisable;
  38. MSG DummyMsg;
  39.  
  40. void
  41. noname()
  42. {
  43.     register PACKET *packet;
  44.     register short   error;
  45.     MSG     *msg;
  46.     ubyte   notdone;
  47.     ubyte   buf[256];
  48.     void    *tmp;
  49.  
  50.     /*
  51.      *    Initialize all global variables.  SysBase MUST be initialized before
  52.      *    we can make Exec calls.  AbsExecBase is a library symbol
  53.      *    referencing absolute memory location 4.  The DOS library is openned
  54.      *    for the debug process.
  55.      */
  56.  
  57.     DBDisable = 0;
  58.     Dbport = Dback = NULL;
  59.     TotalBytes = 0;
  60.     SysBase = AbsExecBase;
  61.     DOSBase = OpenLibrary("dos.library",0);
  62.     DosProc = FindTask(NULL);
  63.     {
  64.     WaitPort(&DosProc->pr_MsgPort);     /*  Startup Packet  */
  65.     msg = GetMsg(&DosProc->pr_MsgPort);
  66.     packet = (PACKET *)msg->mn_Node.ln_Name;
  67.  
  68.     /*
  69.      *  Loading DosNode->dn_Task causes DOS *NOT* to startup a new
  70.      *  instance of the device driver for every reference.    E.G. if
  71.      *  you were writing a CON device you would want this field to
  72.      *  be NULL.
  73.      */
  74.  
  75.     if (DOSBase) {
  76.         DosNode = BTOC(packet->dp_Arg3);
  77.         DosNode->dn_Task = &DosProc->pr_MsgPort;
  78.         packet->dp_Res1 = DOS_TRUE;
  79.         packet->dp_Res2 = 0;
  80.     } else {
  81.         packet->dp_Res1 = DOS_FALSE;
  82.         returnpacket(packet);
  83.         return;
  84.     }
  85.     returnpacket(packet);
  86.     }
  87.  
  88.     /*    DEBUGGING   */
  89.  
  90.     dbinit();        /* this can be removed  */
  91.  
  92.     /*    Initialize  RAM disk    */
  93.  
  94.     {
  95.     ubyte *ptr = BTOC(DosNode->dn_Name);
  96.     short len = *ptr;
  97.  
  98.     NewList(&FHBase);
  99.     NewList(&LCBase);
  100.     bzero(&RFRoot,sizeof(RFRoot));
  101.     RFRoot.type = FILE_DIR;
  102.     NewList(&RFRoot.list);
  103.     RFRoot.name = AllocMem(len+1, MEMF_PUBLIC);
  104.     bmov(ptr+1,RFRoot.name,len);
  105.     RFRoot.name[len] = 0;
  106.     dbprintf("ROOT NAME: %ld '%s'\n", len, RFRoot.name);
  107.     }
  108.  
  109. top:
  110.     for (notdone = 1; notdone;) {
  111.     WaitPort(&DosProc->pr_MsgPort);
  112.     stats();
  113.     while (msg = GetMsg(&DosProc->pr_MsgPort)) {
  114.         register ubyte *ptr;
  115.         packet = (PACKET *)msg->mn_Node.ln_Name;
  116.         packet->dp_Res1 = DOS_TRUE;
  117.         packet->dp_Res2 = 0;
  118.         error = 0;
  119.         dbprintf("Packet: %3ld %08lx %08lx %08lx %08lx\n",
  120.         packet->dp_Type, packet->dp_Arg1, packet->dp_Arg2, packet->dp_Arg3, packet->dp_Arg4
  121.         );
  122.  
  123.         switch(packet->dp_Type) {
  124.         case ACTION_DIE:        /*    attempt to die?             */
  125.         notdone = 0;
  126.         break;
  127.         case ACTION_OPENRW:     /*    FileHandle,Lock,Name        Bool    */
  128.         case ACTION_OPENOLD:    /*    FileHandle,Lock,Name        Bool    */
  129.         case ACTION_OPENNEW:    /*    FileHandle,Lock,Name        Bool    */
  130.         {
  131.             register RAMFILE *ramfile;
  132.             RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
  133.             char    *ptr;
  134.  
  135.             btos(packet->dp_Arg3,buf);
  136.             if (strcmp(buf,"debugoff") == 0)
  137.             DBDisable = 1;
  138.             if (strcmp(buf,"debugon") == 0)
  139.             DBDisable = 0;
  140.             if (ramfile = searchpath(&parentdir,buf,&ptr)) {
  141.             dbprintf("Found: parentdir %08lx  tail '%s'\n", parentdir, ptr);
  142.             if (ramfile->type == FILE_DIR) {
  143.                 error = ERROR_OBJECT_WRONG_TYPE;
  144.                 goto openbreak;
  145.             }
  146.             if (ramfile->locks < 0) {
  147.                 error = ERROR_OBJECT_IN_USE;
  148.                 goto openbreak;
  149.             }
  150.             if (packet->dp_Type == ACTION_OPENOLD) {
  151.                 ++ramfile->locks;
  152.             } else {
  153.                 if (ramfile->locks > 0) {
  154.                 error = ERROR_OBJECT_IN_USE;
  155.                 } else {
  156.                 if (packet->dp_Type == ACTION_OPENNEW)
  157.                     freedata(ramfile);
  158.                 --ramfile->locks;
  159.                 }
  160.             }
  161.             } else {
  162.             dbprintf("Not found..");
  163.             if (!parentdir) {
  164.                 error = ERROR_INVALID_COMPONENT_NAME;
  165.                 goto openbreak;
  166.             }
  167.             if (packet->dp_Type == ACTION_OPENNEW) {
  168.                 ramfile = createramfile(parentdir, FILE_FILE, ptr);
  169.                 --ramfile->locks;
  170.                 dbprintf("adding file %08lx '%s'\n", ramfile, ramfile->name);
  171.             } else {
  172.                 error = ERROR_OBJECT_NOT_FOUND;
  173.             }
  174.             }
  175.             if (!error) {
  176.             register MYFH *mfh = AllocMem(sizeof(MYFH), MEMF_PUBLIC|MEMF_CLEAR);
  177.             ((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long)mfh;
  178.             dbprintf("SET FH-ARG1 to %08lx\n", mfh);
  179.             mfh->file = ramfile;
  180.             mfh->fentry = GetHead(&ramfile->list);
  181.             AddHead(&FHBase,mfh);
  182.             }
  183.         }
  184.           openbreak:
  185.         if (!GetHead(&FHBase) && !GetHead(&LCBase))
  186.             notdone = 0;
  187.         break;
  188.         case ACTION_READ:        /*     FHArg1,CPTRBuffer,Length   ActLength  */
  189.         {
  190.             register MYFH   *mfh = (MYFH *)packet->dp_Arg1;
  191.             register FENTRY *fen = mfh->fentry;
  192.             register ubyte  *ptr = (ubyte *)packet->dp_Arg2;
  193.             register long   left = packet->dp_Arg3;
  194.             register long   scr;
  195.  
  196.             dbprintf("READ Seek:%ld MFH:%08lx FEN:%08lx\n", mfh->base + mfh->offset, mfh, fen);
  197.             while (left && fen) {
  198.             scr = fen->bytes - mfh->offset;
  199.             dbprintf(" %ld bytes avail to read. req %ld\n", scr, left);
  200.             if (left < scr) {
  201.                 bmov(fen->buf + mfh->offset, ptr, left);
  202.                 mfh->offset += left;
  203.                 left = 0;
  204.             } else {
  205.                 bmov(fen->buf + mfh->offset, ptr, scr);
  206.                 left -= scr;
  207.                 ptr += scr;
  208.                 mfh->base += fen->bytes;
  209.                 mfh->offset = 0;
  210.                 fen = NextNode(fen);
  211.             }
  212.             }
  213.             mfh->fentry = fen;
  214.             packet->dp_Res1 = packet->dp_Arg3 - left;
  215.         }
  216.         break;
  217.         case ACTION_WRITE:        /*     FHArg1,CPTRBuffer,Length   ActLength  */
  218.         {
  219.             register MYFH   *mfh = (MYFH *)packet->dp_Arg1;
  220.             register FENTRY *fen = (FENTRY *)mfh->fentry;
  221.             register ubyte  *ptr = (ubyte *)packet->dp_Arg2;
  222.             register long   left = packet->dp_Arg3;
  223.             register long   scr;
  224.  
  225.             dbprintf("MFH: %08lx\n", mfh);
  226.             while (left) {
  227.             if (fen) {
  228.                 dbprintf("WRITE: %ld FEN %ld\n", left, fen->bytes);
  229.                 scr = fen->bytes - mfh->offset;
  230.                 if (left < scr) {
  231.                 bmov(ptr, fen->buf + mfh->offset, left);
  232.                 mfh->offset += left;
  233.                 left = 0;
  234.                 } else {
  235.                 bmov(ptr, fen->buf + mfh->offset, scr);
  236.                 ptr += scr;
  237.                 left -= scr;
  238.                 mfh->base += fen->bytes;
  239.                 mfh->offset = 0;
  240.                 fen = NextNode(fen);
  241.                 }
  242.             } else {
  243.                 dbprintf("WRITE: %ld NOFEN\n", left);
  244.                 fen = AllocMem(sizeof(FENTRY), MEMF_PUBLIC);
  245.                 fen->buf = AllocMem(left, MEMF_PUBLIC);
  246.                 fen->bytes = left;
  247.                 mfh->file->bytes += left;
  248.                 mfh->base  += left;
  249.                 mfh->offset = 0;
  250.                 TotalBytes += left;
  251.                 AddTail(&mfh->file->list, fen);
  252.                 bmov(ptr, fen->buf, left);
  253.                 left = 0;
  254.                 fen = NULL;     /*    cause append    */
  255.             }
  256.             }
  257.             packet->dp_Res1 = packet->dp_Arg3 - left;
  258.             mfh->fentry = fen;
  259.         }
  260.         break;
  261.         case ACTION_CLOSE:        /*     FHArg1             Bool:TRUE  */
  262.         {
  263.             register MYFH   *mfh = (MYFH *)packet->dp_Arg1;
  264.             register RAMFILE *file = mfh->file;
  265.  
  266.             Remove(mfh);
  267.             FreeMem(mfh,sizeof(*mfh));
  268.             if (--file->locks < 0)
  269.             file->locks = 0;
  270.         }
  271.         if (!GetHead(&FHBase) && !GetHead(&LCBase))
  272.             notdone = 0;
  273.         break;
  274.         case ACTION_SEEK:        /*     FHArg1,Position,Mode        OldPosition*/
  275.         {
  276.             register MYFH *mfh = (MYFH *)packet->dp_Arg1;
  277.             register FENTRY *fen;
  278.             register long absseek;
  279.  
  280.             packet->dp_Res1 = mfh->base + mfh->offset;
  281.             absseek = packet->dp_Arg2;
  282.             if (packet->dp_Arg3 == 0)
  283.             absseek += mfh->base + mfh->offset;
  284.             if (packet->dp_Arg3 == 1)
  285.             absseek = mfh->file->bytes + absseek;
  286.             if (absseek < 0 || absseek > mfh->file->bytes) {
  287.             error = ERROR_SEEK_ERROR;
  288.             break;
  289.             }
  290.             mfh->base = mfh->offset = 0;
  291.  
  292.             /*
  293.              *    Stupid way to do it but....
  294.              */
  295.  
  296.             for (fen = GetHead(&mfh->file->list); fen; fen = NextNode(fen)) {
  297.             if (mfh->base + fen->bytes > absseek) {
  298.                 mfh->offset = absseek - mfh->base;
  299.                 break;
  300.             }
  301.             mfh->base += fen->bytes;
  302.             }
  303.             mfh->fentry = fen;
  304.         }
  305.         break;
  306.         case ACTION_EXAMINE_NEXT: /*   Lock,Fib              Bool     */
  307.         {
  308.             register FIB *fib = BTOC(packet->dp_Arg2);
  309.             register RAMFILE *file = getlockfile(packet->dp_Arg1);
  310.  
  311.             if (file->type == FILE_FILE) {
  312.             error = ERROR_OBJECT_WRONG_TYPE;
  313.             break;
  314.             }
  315.             if (fib->fib_DiskKey == NULL) {
  316.             error = ERROR_NO_MORE_ENTRIES;
  317.             break;
  318.             }
  319.             file = (RAMFILE *)fib->fib_DiskKey;
  320.             fib->fib_DiskKey = (long)NextNode(file);
  321.             tmp = file;
  322.             error = -1;
  323.         }
  324.         /*  fall through    */
  325.         case ACTION_EXAMINE_OBJECT: /*   Lock,Fib            Bool       */
  326.         {
  327.             register FIB *fib;
  328.             register RAMFILE *file;
  329.  
  330.             fib = BTOC(packet->dp_Arg2);
  331.             if (error) {
  332.             file = tmp;
  333.             } else {
  334.             file = getlockfile(packet->dp_Arg1);
  335.             fib->fib_DiskKey = (long)GetHead(&file->list);
  336.             }
  337.             error = 0;
  338.             fib->fib_DirEntryType = file->type;
  339.             strcpy(fib->fib_FileName+1, file->name);
  340.             fib->fib_FileName[0] = strlen(file->name);
  341.             fib->fib_Protection = file->protection;
  342.             fib->fib_EntryType = NULL;
  343.             fib->fib_Size = file->bytes;
  344.             fib->fib_NumBlocks = file->bytes >> 9;
  345.             fib->fib_Date = file->date;
  346.             if (file->comment) {
  347.             strcpy(fib->fib_Comment+1, file->comment);
  348.             fib->fib_Comment[0] = strlen(file->comment);
  349.             } else {
  350.             fib->fib_Comment[0] = 0;
  351.             }
  352.         }
  353.         break;
  354.         case ACTION_INFO:        /*    Lock, InfoData      Bool:TRUE    */
  355.         tmp = BTOC(packet->dp_Arg2);
  356.         error = -1;
  357.         /*  fall through    */
  358.         case ACTION_DISK_INFO:  /*    InfoData      Bool:TRUE    */
  359.         {
  360.             register INFODATA *id;
  361.  
  362.             /*
  363.              *    Note:    id_NumBlocks is never 0, but only to get
  364.              *    around a bug I found in my shell (where I divide
  365.              *    by id_NumBlocks)
  366.              */
  367.  
  368.             (error) ? (id = tmp) : (id = BTOC(packet->dp_Arg1));
  369.             error = 0;
  370.             bzero(id, sizeof(*id));
  371.             id->id_DiskState = ID_VALIDATED;
  372.             id->id_NumBlocks     = (TotalBytes >> 9) + 1;
  373.             id->id_NumBlocksUsed = (TotalBytes >> 9) + 1;
  374.             id->id_BytesPerBlock = 512;
  375.             id->id_DiskType = ID_DOS_DISK;
  376.             id->id_VolumeNode = (long)CTOB(DosNode);
  377.             id->id_InUse = (long)GetHead(&LCBase);
  378.         }
  379.         break;
  380.         case ACTION_PARENT:     /*     Lock                ParentLock */
  381.         {
  382.             register RAMFILE *file = getlockfile(packet->dp_Arg1);
  383.             if (file->type == FILE_FILE) {
  384.             error = ERROR_OBJECT_NOT_FOUND;
  385.             break;
  386.             }
  387.             if (file->locks < 0) {
  388.             error = ERROR_OBJECT_IN_USE;
  389.             break;
  390.             }
  391.             if (file->parent)
  392.             packet->dp_Res1 = (long)CTOB(ramlock(file->parent, ACCESS_READ));
  393.             else
  394.             error = ERROR_OBJECT_NOT_FOUND;
  395.         }
  396.         break;
  397.         case ACTION_DELETE_OBJECT: /*Lock,Name            Bool       */
  398.         {
  399.             RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
  400.             RAMFILE *ramfile;
  401.  
  402.             btos(packet->dp_Arg2, buf);
  403.             if (ramfile = searchpath(&parentdir,buf,NULL)) {
  404.             if (ramfile->locks || ramfile == &RFRoot) {
  405.                 error = ERROR_OBJECT_IN_USE;
  406.                 break;
  407.             }
  408.             if (ramfile->type == FILE_DIR) {
  409.                 if (GetHead(&ramfile->list))
  410.                 error = ERROR_DIRECTORY_NOT_EMPTY;
  411.             } else {
  412.                 freedata(ramfile);
  413.             }
  414.             if (!error)
  415.                 freeramfile(ramfile);
  416.             } else {
  417.             if (!parentdir)
  418.                 error = ERROR_INVALID_COMPONENT_NAME;
  419.             else
  420.                 error = ERROR_OBJECT_NOT_FOUND;
  421.             }
  422.         }
  423.         if (!GetHead(&FHBase) && !GetHead(&LCBase))
  424.             notdone = 0;
  425.         break;
  426.         case ACTION_CREATE_DIR: /*     Lock,Name            Lock       */
  427.         {
  428.             RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
  429.             RAMFILE *ramfile;
  430.             char *ptr;
  431.  
  432.             btos(packet->dp_Arg2, buf);
  433.             if (ramfile = searchpath(&parentdir,buf,&ptr)) {
  434.             error = ERROR_OBJECT_EXISTS;
  435.             break;
  436.             }
  437.             if (!parentdir) {
  438.             error = ERROR_INVALID_COMPONENT_NAME;
  439.             break;
  440.             }
  441.             ramfile = createramfile(parentdir, FILE_DIR, ptr);
  442.             packet->dp_Res1 = (long)CTOB(ramlock(ramfile, ACCESS_WRITE));
  443.         }
  444.         break;
  445.         case ACTION_LOCATE_OBJECT:    /*   Lock,Name,Mode        Lock       */
  446.         {
  447.             RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
  448.             RAMFILE *ramfile;
  449.  
  450.             btos(packet->dp_Arg2, buf);
  451.             if (ramfile = searchpath(&parentdir,buf,NULL)) {
  452.             if (ramfile->locks < 0 || (ramfile->locks && packet->dp_Arg3 == ACCESS_WRITE)) {
  453.                 error = ERROR_OBJECT_IN_USE;
  454.                 break;
  455.             }
  456.             packet->dp_Res1 = (long)CTOB(ramlock(ramfile, packet->dp_Arg3));
  457.             } else {
  458.             if (!parentdir)
  459.                 error = ERROR_INVALID_COMPONENT_NAME;
  460.             else
  461.                 error = ERROR_OBJECT_NOT_FOUND;
  462.             }
  463.         }
  464.         break;
  465.         case ACTION_COPY_DIR:   /*     Lock,                Lock       */
  466.         {
  467.             register RAMFILE *ramfile = getlockfile(packet->dp_Arg1);
  468.             if (ramfile->locks < 0)
  469.             error = ERROR_OBJECT_IN_USE;
  470.             else
  471.             packet->dp_Res1 = (long)CTOB(ramlock(ramfile, ACCESS_READ));
  472.         }
  473.         break;
  474.         case ACTION_FREE_LOCK:  /*     Lock,                Bool       */
  475.         if (packet->dp_Arg1);
  476.             ramunlock(BTOC(packet->dp_Arg1));
  477.         if (!GetHead(&FHBase) && !GetHead(&LCBase))
  478.             notdone = 0;
  479.         break;
  480.         case ACTION_SET_PROTECT:/*     -,Lock,Name,Mask       Bool       */
  481.         {
  482.             register RAMFILE *ramfile;
  483.             RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
  484.             char *ptr;
  485.  
  486.             btos(packet->dp_Arg3, buf);
  487.             if (ramfile = searchpath(&parentdir,buf,&ptr)) {
  488.             ramfile->protection = packet->dp_Arg4;
  489.             } else {
  490.             if (parentdir)
  491.                 error = ERROR_OBJECT_NOT_FOUND;
  492.             else
  493.                 error = ERROR_INVALID_COMPONENT_NAME;
  494.             }
  495.         }
  496.         break;
  497.         case ACTION_SET_COMMENT:/*     -,Lock,Name,Comment       Bool       */
  498.         {
  499.             register RAMFILE *ramfile;
  500.             RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
  501.             char *ptr;
  502.  
  503.             btos(packet->dp_Arg3, buf);
  504.             if (ramfile = searchpath(&parentdir,buf,&ptr)) {
  505.             btos(packet->dp_Arg4, buf);
  506.             if (ramfile->comment)
  507.                 FreeMem(ramfile->comment,strlen(ramfile->comment)+1);
  508.             ramfile->comment = AllocMem(strlen(buf)+1, MEMF_PUBLIC);
  509.             strcpy(ramfile->comment, buf);
  510.             } else {
  511.             if (parentdir)
  512.                 error = ERROR_OBJECT_NOT_FOUND;
  513.             else
  514.                 error = ERROR_INVALID_COMPONENT_NAME;
  515.             }
  516.         }
  517.         break;
  518.         case ACTION_RENAME_OBJECT:/* SLock,SName,DLock,DName    Bool       */
  519.         {
  520.             register RAMFILE *file1, *file2;
  521.             RAMFILE *sourcedir = getlockfile(packet->dp_Arg1);
  522.             RAMFILE *destdir   = getlockfile(packet->dp_Arg3);
  523.             char *ptr;
  524.  
  525.             btos(packet->dp_Arg2,buf);
  526.             if (file1 = searchpath(&sourcedir,buf,NULL)) {
  527.             btos(packet->dp_Arg4,buf);
  528.             if (file2 = searchpath(&destdir,buf,&ptr)) {
  529.                 error = ERROR_OBJECT_EXISTS;
  530.             } else {
  531.                 if (destdir) {
  532.                 Remove(file1);
  533.                 AddTail(&destdir->list, file1);
  534.                 FreeMem(file1->name,strlen(file1->name)+1);
  535.                 file1->name = AllocMem(strlen(ptr)+1,MEMF_PUBLIC);
  536.                 strcpy(file1->name,ptr);
  537.                 } else {
  538.                 error = ERROR_INVALID_COMPONENT_NAME;
  539.                 }
  540.             }
  541.             } else {
  542.             if (sourcedir)
  543.                 error = ERROR_OBJECT_NOT_FOUND;
  544.             else
  545.                 error = ERROR_INVALID_COMPONENT_NAME;
  546.             }
  547.         }
  548.         break;
  549.         /*
  550.          *    A few other packet types which we do not support
  551.          */
  552.         case ACTION_RENAME_DISK:/*     BSTR:NewName            Bool       */
  553.         case ACTION_MORECACHE:  /*     #BufsToAdd            Bool       */
  554.         case ACTION_INHIBIT:    /*     Bool                Bool       */
  555.         case ACTION_WAIT_CHAR:  /*     Timeout, ticks         Bool       */
  556.         case ACTION_FLUSH:        /*     writeout bufs, disk motor off           */
  557.         case ACTION_RAWMODE:    /*     Bool(-1:RAW 0:CON)        OldState   */
  558.         default:
  559.         error = ERROR_ACTION_NOT_KNOWN;
  560.         break;
  561.         }
  562.         if (packet) {
  563.         if (error) {
  564.             packet->dp_Res1 = DOS_FALSE;
  565.             packet->dp_Res2 = error;
  566.         }
  567.         returnpacket(packet);
  568.         }
  569.     }
  570.     }
  571.     dbprintf("REMOVING DOS DEVICE");
  572.     Delay(50);        /*    I wanna even see the debug message! */
  573.     Forbid();
  574.     if (packetsqueued(DosProc) || GetHead(&FHBase) || GetHead(&LCBase)
  575.       || GetHead(&RFRoot.list)) {
  576.     Permit();
  577.     dbprintf("Not ready to die yet!\n");
  578.     goto top;        /*  sorry... can't exit     */
  579.     }
  580.     DosNode->dn_Task = FALSE;
  581.     dbuninit();
  582.     CloseLibrary(DOSBase);
  583. }
  584.  
  585. /*
  586.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  587.  *  can see by this and how the PACKET structure is extracted in the
  588.  *  GetMsg() of the main routine.
  589.  */
  590.  
  591. void
  592. returnpacket(packet)
  593. register struct DosPacket *packet;
  594. {
  595.     register struct Message *mess;
  596.     register struct MsgPort *replyport;
  597.  
  598.     replyport             = packet->dp_Port;
  599.     mess             = packet->dp_Link;
  600.     packet->dp_Port         = &DosProc->pr_MsgPort;
  601.     mess->mn_Node.ln_Name    = (char *)packet;
  602.     mess->mn_Node.ln_Succ    = NULL;
  603.     mess->mn_Node.ln_Pred    = NULL;
  604.     PutMsg(replyport, mess);
  605. }
  606.  
  607. /*
  608.  *  Are there any packets queued to our device?
  609.  */
  610.  
  611. packetsqueued()
  612. {
  613.     return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
  614.         (void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
  615. }
  616.  
  617. /*
  618.  *  DOS MEMORY ROUTINES
  619.  *
  620.  *  DOS makes certain assumptions about LOCKS.    A lock must minimally be
  621.  *  a FileLock structure, with additional private information after the
  622.  *  FileLock structure.  The longword before the beginning of the structure
  623.  *  must contain the length of structure + 4.
  624.  */
  625.  
  626. void *
  627. dosalloc(bytes)
  628. register ulong bytes;
  629. {
  630.     register ulong *ptr;
  631.  
  632.     bytes += 4;
  633.     ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
  634.     *ptr = bytes;
  635.     return(ptr+1);
  636. }
  637.  
  638. dosfree(ptr)
  639. register ulong *ptr;
  640. {
  641.     --ptr;
  642.     FreeMem(ptr, *ptr);
  643. }
  644.  
  645. /*
  646.  *  Convert a BSTR into a normal string.. copying the string into buf
  647.  */
  648.  
  649. void
  650. btos(bstr,buf)
  651. ubyte *bstr;
  652. ubyte *buf;
  653. {
  654.     bstr = BTOC(bstr);
  655.     bmov(bstr+1,buf,*bstr);
  656.     buf[*bstr] = 0;
  657.     dbprintf("btos: %ld %s\n", *bstr, buf);
  658. }
  659.  
  660. void *
  661. NextNode(node)
  662. NODE *node;
  663. {
  664.     node = node->mln_Succ;
  665.     if (node->mln_Succ == NULL)
  666.     return(NULL);
  667.     return(node);
  668. }
  669.  
  670. void *
  671. GetHead(list)
  672. LIST *list;
  673. {
  674.     if ((void *)list->mlh_Head != (void *)&list->mlh_Tail)
  675.     return(list->mlh_Head);
  676.     return(NULL);
  677. }
  678.  
  679. nccmp(p1,p2,n)
  680. register ubyte *p1, *p2;
  681. register short n;
  682. {
  683.     while (--n >= 0) {
  684.     if ((p1[n]|0x20) != (p2[n]|0x20))
  685.         return(0);
  686.     }
  687.     return(1);
  688. }
  689.  
  690. /*
  691.  *  Create a file or directory and link it into it's parent directory.
  692.  */
  693.  
  694. RAMFILE *
  695. createramfile(parentdir, type, name)
  696. RAMFILE *parentdir;
  697. char *name;
  698. {
  699.     register RAMFILE *ramfile;
  700.  
  701.     ramfile = AllocMem(sizeof(RAMFILE), MEMF_CLEAR|MEMF_PUBLIC);
  702.     AddTail(&parentdir->list, ramfile);
  703.     ramfile->parent = parentdir;
  704.     ramfile->name = AllocMem(strlen(name)+1, MEMF_PUBLIC);
  705.     strcpy(ramfile->name, name);
  706.     ramfile->type = type;
  707.     ramfile->protection = 0;
  708.     NewList(&ramfile->list);
  709.     /*    SET DATE!   */
  710.     return(ramfile);
  711. }
  712.  
  713. /*
  714.  *  Free all data associated with a file
  715.  */
  716.  
  717. void
  718. freedata(ramfile)
  719. RAMFILE *ramfile;
  720. {
  721.     FENTRY *fen;
  722.  
  723.     TotalBytes -= ramfile->bytes;
  724.     while (fen = RemHead(&ramfile->list)) {
  725.     FreeMem(fen->buf, fen->bytes);
  726.     FreeMem(fen, sizeof(*fen));
  727.     }
  728.     ramfile->bytes = 0;
  729. }
  730.  
  731. /*
  732.  *  Any data associated with the file or directory has already been
  733.  *  freed up.
  734.  */
  735.  
  736. void
  737. freeramfile(ramfile)
  738. RAMFILE *ramfile;
  739. {
  740.     Remove(ramfile);        /*  unlink from parent directory    */
  741.     FreeMem(ramfile->name,strlen(ramfile->name)+1);
  742.     if (ramfile->comment)
  743.     FreeMem(ramfile->comment,strlen(ramfile->comment)+1);
  744.     FreeMem(ramfile,sizeof(*ramfile));
  745. }
  746.  
  747. MYLOCK *
  748. ramlock(ramfile, mode)
  749. RAMFILE *ramfile;
  750. {
  751.     MYLOCK *lock = dosalloc(sizeof(MYLOCK));
  752.     AddHead(&LCBase,&lock->node);
  753.     lock->lock.fl_Access = mode;
  754.     lock->lock.fl_Task = &DosProc->pr_MsgPort;
  755.     lock->lock.fl_Volume = (BPTR)CTOB(DosNode);
  756.     lock->file = ramfile;
  757.     if (mode == ACCESS_READ)
  758.     ++ramfile->locks;
  759.     else
  760.     ramfile->locks = -1;
  761.     return(lock);
  762. }
  763.  
  764. void
  765. ramunlock(lock)
  766. MYLOCK *lock;
  767. {
  768.     RAMFILE *file = lock->file;
  769.     Remove(&lock->node);
  770.     if (lock->lock.fl_Access == ACCESS_READ)
  771.     --file->locks;
  772.     else
  773.     file->locks = 0;
  774.     dosfree(lock);
  775. }
  776.  
  777. /*
  778.  *  GETLOCKFILE(bptrlock)
  779.  *
  780.  *  Return the RAMFILE entry (file or directory) associated with the
  781.  *  given lock, which is passed as a BPTR.
  782.  *
  783.  *  According to the DOS spec, the only way a NULL lock will ever be
  784.  *  passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
  785.  *  In anycase, If a NULL lock is passed to me I simply assume it means
  786.  *  the root directory of the RAM disk.
  787.  */
  788.  
  789. RAMFILE *
  790. getlockfile(lock)
  791. void *lock;        /*  actually BPTR to MYLOCK */
  792. {
  793.     if (lock)
  794.     return(((MYLOCK *)BTOC(lock))->file);
  795.     return(&RFRoot);
  796. }
  797.  
  798. /*
  799.  *  Search the specified path beginning at the specified directory.
  800.  *  The directory pointer is updated to the directory containing the
  801.  *  actual file.  Return the file node or NULL if not found.  If the
  802.  *  path is illegal (an intermediate directory was not found), set *ppar
  803.  *  to NULL and return NULL.
  804.  *
  805.  *  *ppar may also be set to NULL if the search path IS the root.
  806.  *
  807.  *  If pptr not NULL, Set *pptr to the final component in the path.
  808.  */
  809.  
  810. RAMFILE *
  811. searchpath(ppar,buf,pptr)
  812. RAMFILE **ppar;
  813. char *buf;
  814. char **pptr;
  815. {
  816.     RAMFILE *file = *ppar;
  817.     RAMFILE *srch;
  818.     short len;
  819.     char *ptr;
  820.  
  821.     dbprintf("searchpath: '%s'\n", buf);
  822.     *ppar = NULL;
  823.     for (;*buf && file;) {
  824.     ptr = getpathelement(&buf,&len);
  825.     if (buf[0] == ':') {    /*  go to root          */
  826.         dbprintf("colon element\n");
  827.         ++buf;
  828.         file = &RFRoot;
  829.         continue;
  830.     }
  831.     if (*ptr == '/') {          /*  go back a directory */
  832.         if (!file->parent) {    /*    no parent directory */
  833.         dbprintf("Backdir.. no parent\n");
  834.         return(NULL);
  835.         }
  836.         file = file->parent;
  837.         dbprintf("backdir: file %08lx (%s)\n", file, file->name);
  838.         continue;
  839.     }
  840.     if (file->type == FILE_FILE)
  841.         return(NULL);
  842.     for (srch = GetHead(&file->list); srch; srch = NextNode(srch)) {
  843.         if (strlen(srch->name) == len && nccmp(srch->name, ptr, len)) {
  844.         file = srch;        /*    element found        */
  845.         break;
  846.         }
  847.     }
  848.     if (srch == NULL) {
  849.         if (*buf == 0) {    /*  Element not found.    If it was the final */
  850.         *ppar = file;    /*  element the parent directory is valid   */
  851.         dbprintf("element not found.. ok\n");
  852.         } else {
  853.         dbprintf("element not found.. path error\n");
  854.         }
  855.         if (pptr)
  856.         *pptr = ptr;
  857.         return(NULL);
  858.     }
  859.     }
  860.     if (pptr)
  861.     *pptr = ptr;
  862.     *ppar = file->parent;
  863.     dbprintf("DONE. File %08lx (%s) parent %08lx\n", file, file->name, file->parent);
  864.     return(file);
  865. }
  866.  
  867. /*
  868.  *  Return the next path element in the string.  The routine effectively
  869.  *  removes any trailing '/'s, but treats ':' as part of the next component
  870.  *  (i.e. ':' is checked and skipped in SEARCHPATH()).
  871.  */
  872.  
  873. char *
  874. getpathelement(pstr,plen)
  875. char **pstr;
  876. short *plen;
  877. {
  878.     char *base;
  879.     register char *ptr = *pstr;
  880.     register short len = 0;
  881.  
  882.     if (*(base = ptr)) {
  883.     if (*ptr == '/') {
  884.         ++ptr;
  885.         ++len;
  886.     } else {
  887.         while (*ptr && *ptr != '/' && *ptr != ':') {
  888.         ++ptr;
  889.         ++len;
  890.         }
  891.         if (*ptr == '/')
  892.         ++ptr;
  893.     }
  894.     }
  895.     *pstr = ptr;
  896.     *plen = len;
  897.     dbprintf("PATH ELEMENT: %ld '%s' next@ '%s'\n", len, base, ptr);
  898.     return(base);
  899. }
  900.  
  901.  
  902. stats()
  903. {
  904.     register RAMFILE *file;
  905.     register MYFH *mfh;
  906.  
  907.     for (file = GetHead(&RFRoot.list); file; file = NextNode(file)) {
  908.     dbprintf("Root entry: %08lx %s %ld\n", file, file->name, file->bytes);
  909.     }
  910.     for (mfh = GetHead(&FHBase); mfh; mfh = NextNode(mfh)) {
  911.     dbprintf("Openfile: %08lx %s @%ld %ld\n", mfh->file, mfh->file->name, mfh->base, mfh->offset);
  912.     }
  913.     /*
  914.      *    Note that the NODE entry in the MYLOCK structure is not (cannot) be
  915.      *    at the beginning of the structure and thus if you want to traverse
  916.      *    the active lock list you must subtract it's position in the
  917.      *    structure from any list pointers.
  918.      */
  919.     if (GetHead(&LCBase)) {
  920.     dbprintf("ACTIVE LOCKS DO EXIST\n");
  921.     }
  922.     dbprintf("\n");
  923. }
  924.  
  925. /*
  926.  *  DEBUGGING CODE.    You cannot make DOS library calls that access other
  927.  *  devices from within a DOS device driver because they use the same
  928.  *  message port as the driver.  If you need to make such calls you must
  929.  *  create a port and construct the DOS messages yourself.  I do not
  930.  *  do this.  To get debugging info out another PROCESS is created to which
  931.  *  debugging messages can be sent.
  932.  *
  933.  *  You want the priority of the debug process to be larger than the
  934.  *  priority of your DOS handler.  This is so if your DOS handler crashes
  935.  *  you have a better idea of where it died from the debugging messages
  936.  *  (remember that the two processes are asyncronous from each other).
  937.  */
  938.  
  939. extern void debugproc();
  940.  
  941. dbinit()
  942. {
  943.     TASK *task = FindTask(NULL);
  944.  
  945.     Dback = CreatePort(NULL,NULL);
  946.     CreateProc("DEV_DB", task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096);
  947.     WaitPort(Dback);                    /* handshake startup    */
  948.     GetMsg(Dback);                    /* remove dummy msg     */
  949.     dbprintf("Debugger running V1.00\n");
  950. }
  951.  
  952. dbuninit()
  953. {
  954.     MSG killmsg;
  955.  
  956.     if (Dbport) {
  957.     killmsg.mn_Length = 0;        /*    0 means die        */
  958.     PutMsg(Dbport,&killmsg);
  959.     WaitPort(Dback);        /*    He's dead jim!      */
  960.     GetMsg(Dback);
  961.     DeletePort(Dback);
  962.  
  963.     /*
  964.      *  Since the debug process is running at a greater priority, I
  965.      *  am pretty sure that it is guarenteed to be completely removed
  966.      *  before this task gets control again.  Still, it doesn't hurt...
  967.      */
  968.  
  969.     Delay(50);            /*    ensure he's dead    */
  970.     }
  971. }
  972.  
  973. dbprintf(a,b,c,d,e,f,g,h,i,j)
  974. {
  975.     char buf[256];
  976.     MSG *msg;
  977.  
  978.     if (Dbport && !DBDisable) {
  979.     sprintf(buf,a,b,c,d,e,f,g,h,i,j);
  980.     msg = AllocMem(sizeof(MSG)+strlen(buf)+1, MEMF_PUBLIC|MEMF_CLEAR);
  981.     msg->mn_Length = strlen(buf)+1;     /*    Length NEVER 0    */
  982.     strcpy(msg+1,buf);
  983.     PutMsg(Dbport,msg);
  984.     }
  985. }
  986.  
  987. /*
  988.  *  BTW, the DOS library used by debugmain() was actually openned by
  989.  *  the device driver.    Note: DummyMsg cannot be on debugmain()'s stack
  990.  *  since debugmain() goes away on the final handshake.
  991.  */
  992.  
  993. debugmain()
  994. {
  995.     MSG *msg;
  996.     short len;
  997.     void *fh;
  998.  
  999.     Dbport = CreatePort(NULL,NULL);
  1000.     fh = Open("con:0/0/640/100/debugwindow", 1006);
  1001.     PutMsg(Dback, &DummyMsg);
  1002.     for (;;) {
  1003.     WaitPort(Dbport);
  1004.     msg = GetMsg(Dbport);
  1005.     len = msg->mn_Length;
  1006.     if (len == 0)
  1007.         break;
  1008.     --len;                /*    Fix length up    */
  1009.     Write(fh, msg+1, len);
  1010.     FreeMem(msg,sizeof(MSG)+len+1);
  1011.     }
  1012.     Close(fh);
  1013.     DeletePort(Dbport);
  1014.     PutMsg(Dback,&DummyMsg);          /*  Kill handshake  */
  1015. }
  1016.  
  1017. /*
  1018.  *  The assembly tag for the DOS process:  CNOP causes alignment problems
  1019.  *  with the Aztec assembler for some reason.  I assume then, that the
  1020.  *  alignment is unknown.  Since the BCPL conversion basically zero's the
  1021.  *  lower two bits of the address the actual code may start anywhere
  1022.  *  within 8 bytes of address (remember the first longword is a segment
  1023.  *  pointer and skipped).  Sigh....  (see CreatProc() above).
  1024.  */
  1025.  
  1026. #asm
  1027.     public    _debugproc
  1028.     public    _debugmain
  1029.  
  1030.     cseg
  1031. _debugproc:
  1032.     nop
  1033.     nop
  1034.     nop
  1035.     nop
  1036.     nop
  1037.     movem.l D2-D7/A2-A6,-(sp)
  1038.     jsr    _debugmain
  1039.     movem.l (sp)+,D2-D7/A2-A6
  1040.     rts
  1041. #endasm
  1042.  
  1043.  
  1044.