home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 18 / amigaformatcd18.iso / -in_the_mag- / emulation / emus / fs1541 / packet.c < prev    next >
C/C++ Source or Header  |  1997-07-31  |  28KB  |  1,178 lines

  1. /*
  2.     FS1541
  3.  
  4.     packet.c
  5.  
  6.  
  7.     This is the packet processor.
  8.  
  9.     If you are new to this subject and want to learn about it, you *must*
  10.     have the Amiga Guru Book next to you and compare the routines for each
  11.     packet with the specifications in the book -- then you will understand!
  12.  
  13. */
  14.  
  15. #include <string.h>
  16.  
  17. #include <exec/types.h>
  18. #include <exec/execbase.h>
  19. #include <exec/memory.h>
  20. #include <dos/dosextens.h>
  21. #include <dos/filehandler.h>
  22.  
  23. #include <proto/exec.h>
  24. #include <proto/dos.h>
  25. #include <proto/utility.h>
  26.  
  27. #include "main.h"
  28. #include "packet.h"
  29. #include "support.h"
  30. #include "volume.h"
  31. #include "disk.h"
  32.  
  33. static BOOL getfiledata(UBYTE entry, struct FHArg1 *fharg1);
  34. static BPTR trylockfile(LONG *err2, BSTR name, LONG access, struct FHArg1 *fharg1, BOOL allow_root);
  35.  
  36. static UBYTE fname1[20];
  37.  
  38. int inhibited = FALSE;
  39.  
  40. static LONG TestLock(struct FileLock *fl);
  41. static inline LONG TestLockRef(struct FileLock *fl);
  42.  
  43. static struct BAM empty_bam = {
  44.     0x12,0x01,0x41,0x00,
  45.  
  46.     {
  47.         0x15FFFF1F,0x15FFFF1F,0x15FFFF1F,
  48.         0x15FFFF1F,0x15FFFF1F,0x15FFFF1F,0x15FFFF1F,
  49.         0x15FFFF1F,0x15FFFF1F,0x15FFFF1F,0x15FFFF1F,
  50.         0x15FFFF1F,0x15FFFF1F,0x15FFFF1F,0x15FFFF1F,
  51.         0x15FFFF1F,0x15FFFF1F,0x11FCFF07,0x13FFFF07,
  52.         0x13FFFF07,0x13FFFF07,0x13FFFF07,0x13FFFF07,
  53.         0x13FFFF07,0x12FFFF03,0x12FFFF03,0x12FFFF03,
  54.         0x12FFFF03,0x12FFFF03,0x12FFFF03,0x11FFFF01,
  55.         0x11FFFF01,0x11FFFF01,0x11FFFF01,0x11FFFF01
  56.     },
  57.  
  58.     {
  59.         0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58
  60.     },
  61.  
  62.     {
  63.         0xA0,0xA0
  64.     },
  65.  
  66.     {
  67.         0x59,0x59,0xA0,0x32,0x41
  68.     },
  69.  
  70.     {
  71.         0xA0,0xA0,0xA0,0xA0,0x00,0x00,0x00,0x00,0x00,
  72.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  73.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  74.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  75.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  76.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  77.     }
  78. };
  79.  
  80. /*-------------------------------------------------------------------------*/
  81.  
  82. void DoPackets(void)
  83. {
  84.     struct DosPacket *packet;
  85.  
  86.     while((packet = GetPacket(ourport)))
  87.     {
  88.         LONG error = DOSFALSE;
  89.         LONG err2 = 0;
  90.         BOOL f = TRUE;
  91.  
  92.         dpsender = packet->dp_Port;
  93.  
  94.         if(inhibited)
  95.         {
  96.             switch(packet->dp_Type)
  97.             {
  98.                 case ACTION_DISK_INFO:
  99.                 case ACTION_INHIBIT:
  100.                 case ACTION_FORMAT:
  101.                     break;
  102.  
  103.                 default:
  104.                     f = FALSE;
  105.                     err2 = ERROR_NOT_A_DOS_DISK;
  106.                     break;
  107.             }
  108.         }
  109.  
  110.         if(f) switch(packet->dp_Type)
  111.         {
  112.             case ACTION_LOCATE_OBJECT:
  113.             {
  114.                 struct FileLock *fl = BADDR(packet->dp_Arg1);
  115.                 struct FHArg1 fharg1;
  116.  
  117.                 if((err2 = TestLock(fl)))
  118.                     break;
  119.                 else if(!curvolumenode)
  120.                 {
  121.                     err2 = disk_inserted ? ERROR_NOT_A_DOS_DISK : ERROR_NO_DISK;
  122.                     break;
  123.                 }
  124.  
  125.                 /* This FileSystem is easy since we don't have to take
  126.                    care of any FileLock path tracking and resolving */
  127.  
  128.                 error = trylockfile(&err2, packet->dp_Arg2, packet->dp_Arg3, &fharg1, TRUE);
  129.                 MotorOff();
  130.                 break;
  131.             }
  132.  
  133.             case ACTION_FREE_LOCK:
  134.             {
  135.                 struct FileLock *fl = BADDR(packet->dp_Arg1);
  136.  
  137.                 if(fl)
  138.                     freelock(fl);
  139.  
  140.                 MotorOff();
  141.                 error = DOSTRUE;
  142.                 break;
  143.             }
  144.  
  145.             case ACTION_COPY_DIR:
  146.             {
  147.                 struct FileLock *fl = BADDR(packet->dp_Arg1);
  148.  
  149.                 if(fl) {
  150.                     if(fl->fl_Access == EXCLUSIVE_LOCK) {
  151.                         /* Don't duplicate exclusive locks */
  152.                         err2 = ERROR_OBJECT_IN_USE;
  153.                     }
  154.                     else {
  155.                         if(fl->fl_Volume == MKBADDR(curdoslist)) {
  156.                             /* Try to duplicate it! */
  157.                             err2 = ERROR_NO_FREE_STORE;
  158.                             error = makelock(fl->fl_Key, SHARED_LOCK);
  159.                         }
  160.                         else {
  161.                             /* The reference disk is currently not inserted. */
  162.                             err2 = ERROR_DEVICE_NOT_MOUNTED;
  163.                         }
  164.                     }
  165.                 }
  166.                 else {
  167.                     if(curvolumenode) {
  168.                         /* Return shared lock on root directory */
  169.                         err2 = ERROR_NO_FREE_STORE;
  170.                         error = makelock(0, SHARED_LOCK);
  171.                     }
  172.                     else {
  173.                         err2 = ERROR_NO_DISK;
  174.                     }
  175.                 }
  176.  
  177.                 break;
  178.             }
  179.  
  180.             case ACTION_PARENT:
  181.             {
  182.                 struct FileLock *fl = BADDR(packet->dp_Arg1);
  183.  
  184.                 if(fl) {
  185.                     if(!(err2 = TestLockRef(fl))) {
  186.                         if(fl->fl_Key != 0) {
  187.                             /* Return shared lock on root directory */
  188.                             err2 = ERROR_NO_FREE_STORE;
  189.                             error = makelock(0, SHARED_LOCK);
  190.                         }
  191.                         else {
  192.                             err2 = 0;
  193.                         }
  194.                     }
  195.                 }
  196.                 else {
  197.                     err2 = 0;
  198.                 }
  199.  
  200.                 break;
  201.             }
  202.  
  203.             case ACTION_SAME_LOCK:
  204.             {
  205.                 struct FileLock *fl1 = BADDR(packet->dp_Arg1);
  206.                 struct FileLock *fl2 = BADDR(packet->dp_Arg2);
  207.  
  208.                 err2 = 0;
  209.  
  210.                 if(fl1 == fl2 || ((fl1->fl_Volume == fl2->fl_Volume) && (fl1->fl_Key == fl2->fl_Key)))
  211.                     error = DOSTRUE;
  212.  
  213.                 break;
  214.             }
  215.  
  216.             case ACTION_EXAMINE_OBJECT:
  217.             {
  218.                 struct FileLock *fl = BADDR(packet->dp_Arg1);
  219.                 struct FileInfoBlock *fib = BADDR(packet->dp_Arg2);
  220.  
  221.                 if(fl && fl->fl_Key != 0) {
  222.                     /* Examine file */
  223.                     struct FHArg1 fharg1;
  224.                     int entry;
  225.                     int special;
  226.  
  227.                     fib->fib_DiskKey = 0;
  228.                     fib->fib_DirEntryType = fib->fib_EntryType = ST_FILE;
  229.                     fib->fib_Protection = 0;
  230.                     fib->fib_Comment[0] = '\0';
  231.                     fib->fib_Date.ds_Days = 0;
  232.                     fib->fib_Date.ds_Minute = 0;
  233.                     fib->fib_Date.ds_Tick = 0;
  234.  
  235.                     if(fl->fl_Volume != MKBADDR(curdoslist)) {
  236.                         /* The reference disk is currently not inserted. */
  237.                         err2 = ERROR_DEVICE_NOT_MOUNTED;
  238.                         break;
  239.                     }
  240.  
  241.                     if((special = fl->fl_Key & FLKEY_SPECIALMASK)) {
  242.                         /* Examine virtual files */
  243.                         static struct { STRPTR s; ULONG l; } tbl[3] = {
  244.                             { VIRTUAL_FILE_D64, D64_SIZE },
  245.                             { VIRTUAL_FILE_OPT, 0 }
  246.                         };
  247.                         int index = (special>>FLKEY_SPECIALSHIFT)-2;
  248.  
  249.                         switch(special) {
  250.                             case FLKEY_DOLLAR:
  251.                                 strcpy(&fib->fib_FileName[1], VIRTUAL_FILE_DOLLAR);
  252.                                 fib->fib_FileName[0] = strlen(VIRTUAL_FILE_DOLLAR);
  253.                                 fib->fib_Size = curvolumenode->dollarlen;
  254.                                 error = DOSTRUE;
  255.                                 break;
  256.  
  257.                             case FLKEY_D64: case FLKEY_OPT:
  258.                                 strcpy(&fib->fib_FileName[1], tbl[index].s);
  259.                                 fib->fib_FileName[0] = strlen(tbl[index].s);
  260.                                 fib->fib_Size = tbl[index].l;
  261.                                 error = DOSTRUE;
  262.                                 break;
  263.  
  264.                             case FLKEY_DISKINFO:
  265.                                 strcpy(&fib->fib_FileName[1], VIRTUAL_FILE_DISKINFO);
  266.                                 fib->fib_FileName[0] = strlen(VIRTUAL_FILE_DISKINFO);
  267.                                 fib->fib_Size = diskiconlength;
  268.                                 error = DOSTRUE;
  269.                                 break;
  270.  
  271.                             default:
  272.                                 err2 = ERROR_OBJECT_NOT_FOUND;
  273.                                 break;
  274.                         }
  275.                     }
  276.                     else {
  277.                         for(entry=0;entry<dirsize;entry++)
  278.                             if(fl->fl_Key == ((directory[entry].datat<<8)|directory[entry].datas))
  279.                                 break;
  280.     
  281.                         if(entry<dirsize) {
  282.                             if(getfiledata(entry, &fharg1)) {
  283.                                 copy64name(&fib->fib_FileName[1], directory[entry].name, 16);
  284.                                 fib->fib_FileName[0] = strlen(&fib->fib_FileName[1]);
  285.                                 fib->fib_Size = fharg1.len;
  286.                                 error = DOSTRUE;
  287.                             }
  288.                             else err2 = ERROR_OBJECT_NOT_FOUND;
  289.                         }
  290.                         else err2 = ERROR_OBJECT_NOT_FOUND;
  291.                     }
  292.                 }
  293.                 else {
  294.                     /* Prepare for EXAMINE_NEXT, return volume name in
  295.                        fib_FileName */
  296.                     fib->fib_DiskKey = 0;
  297.                     fib->fib_DirEntryType = fib->fib_EntryType = ST_ROOT;
  298.                     strcpy(&fib->fib_FileName[1], &curvolumenode->name[1]);
  299.                     fib->fib_FileName[0] = strlen(&fib->fib_FileName[1]);
  300.                     fib->fib_Protection = 0;
  301.                     fib->fib_Comment[0] = '\0';
  302.                     fib->fib_Date.ds_Days = 0;
  303.                     fib->fib_Date.ds_Minute = 0;
  304.                     fib->fib_Date.ds_Tick = 0;
  305.                     error = DOSTRUE;
  306.                 }
  307.  
  308.                 break;
  309.             }
  310.  
  311.             case ACTION_EXAMINE_NEXT:
  312.             {
  313.                 struct FileLock *fl = BADDR(packet->dp_Arg1);
  314.                 struct FileInfoBlock *fib = BADDR(packet->dp_Arg2);
  315.  
  316.                 if((err2 = TestLock(fl)))
  317.                     break;
  318.  
  319.                 fib->fib_DirEntryType = fib->fib_EntryType = ST_FILE;
  320.  
  321.                 err2 = ERROR_NO_MORE_ENTRIES;
  322.  
  323.                 while(fib->fib_DiskKey < dirsize) {
  324.                     int entry;
  325.                     struct FHArg1 fharg1;
  326.  
  327.                     entry = fib->fib_DiskKey++;
  328.  
  329.                     if(getfiledata(entry, &fharg1)) {
  330.                         copy64name(&fib->fib_FileName[1], directory[entry].name, 16);
  331.                         fib->fib_FileName[0] = strlen(&fib->fib_FileName[1]);
  332.                         fib->fib_Size = fharg1.len;
  333.                         fib->fib_NumBlocks = fharg1.numblocks;
  334.                         error = DOSTRUE;
  335.                         break;
  336.                     }
  337.                 }
  338.  
  339.                 if(error == DOSFALSE)
  340.                     MotorOff();
  341.  
  342.                 break;
  343.             }
  344.  
  345.             case ACTION_FINDINPUT:
  346.             case ACTION_FINDOUTPUT:
  347.             case ACTION_FINDUPDATE:
  348.             {
  349.                 struct FileHandle *fh = BADDR(packet->dp_Arg1);
  350.                 struct FileLock *fl = BADDR(packet->dp_Arg2);
  351.                 struct FHArg1 *fharg1;
  352.                 LONG access = packet->dp_Type==ACTION_FINDINPUT ? SHARED_LOCK : EXCLUSIVE_LOCK;
  353.  
  354.                 if((err2 = TestLock(fl)))
  355.                     break;
  356.  
  357.                 if((fharg1 = AllocVec(sizeof(struct FHArg1), MEMF_ANY|MEMF_CLEAR))) {
  358.                     if(trylockfile(&err2, packet->dp_Arg3, access, fharg1, FALSE)) {
  359.                         if(fharg1->number!=NUM_VIRTUAL || access==SHARED_LOCK
  360.                         || (((struct FileLock*)BADDR(fharg1->lock))->fl_Key & FLKEY_SPECIALMASK) == FLKEY_D64) {
  361.                             /* Allow virtual files only for reading, exception is $d64 */
  362.                             fh->fh_Arg1 = (LONG)fharg1;
  363.                             fh->fh_Port = DOSFALSE;
  364.                             error = DOSTRUE;
  365.                         }
  366.                         else {
  367.                             /* But new files with virtual file names can be created,
  368.                                 which will be real then. */
  369.                             freelock((struct FileLock*)BADDR(fharg1->lock));
  370.                             err2 = ERROR_OBJECT_NOT_FOUND;
  371.                         }
  372.                     }
  373.  
  374.                     if((error==DOSFALSE && access==EXCLUSIVE_LOCK && err2!=ERROR_INVALID_COMPONENT_NAME) || packet->dp_Type==ACTION_FINDOUTPUT) {
  375.                         if(!wprotected) {
  376.                             if(error==DOSFALSE) {
  377.                                 /* Create new file */
  378.                                 UWORD dblk;
  379.     
  380.                                 if(dirsize < 144) {
  381.                                     if((dblk = AllocBlock(18,0))) {
  382.                                         UBYTE clrblk[256];
  383.     
  384.                                         memset(&clrblk, 0, sizeof(clrblk));
  385.                                         clrblk[1] = 1;
  386.     
  387.                                         if(putblock_ts(dblk>>8, dblk&0xff, &clrblk)) {
  388.                                             struct DirEntry *de = &directory[dirsize++];
  389.     
  390.                                             memset(de, 0, sizeof(struct DirEntry));
  391.                                             de->type = 0x82; /* PRG, closed */
  392.                                             de->datat = dblk>>8;
  393.                                             de->datas = dblk&0xff;
  394.                                             de->lengthl = 1;
  395.                                             asciito64(de->name, fname1, 16);
  396.                                             StartUDSTimer();
  397.     
  398.                                             if(trylockfile(&err2, packet->dp_Arg3, access, fharg1, FALSE)) {
  399.                                                 fh->fh_Arg1 = (LONG)fharg1;
  400.                                                 fh->fh_Port = DOSFALSE;
  401.                                                 error = DOSTRUE;
  402.                                             }
  403.                                         }
  404.                                         else {
  405.                                             err2 = ABORT_DISK_ERROR;
  406.                                             FreeBlock(dblk>>8, dblk&0xff);
  407.                                         }
  408.                                     }
  409.                                     else err2 = ERROR_DISK_FULL;
  410.                                 }
  411.                                 else err2 = ERROR_DISK_FULL;
  412.                             }
  413.                             else if(fharg1->number != NUM_VIRTUAL) /* trying to overwrite $d64 */ {
  414.                                 /* Overwrite existing file */
  415.                                 struct DataBlock *block;
  416.                                 UBYTE t,s;
  417.                                 int i;
  418.     
  419.                                 for(i=0,t=fharg1->t,s=fharg1->s; t; t=block->t,s=block->s,i++) {
  420.                                     block = getblock_ts(t,s);
  421.                                     if(i>0) FreeBlock(t,s);
  422.                                 }
  423.                                 fharg1->len = 0;
  424.                                 fharg1->numblocks = 1;
  425.                                 block = getblock_ts(fharg1->t, fharg1->s);
  426.                                 block->t = 0;
  427.                                 block->s = 1;
  428.                                 putblock_ts(fharg1->t, fharg1->s, block);
  429.                             }
  430.                         }
  431.                         else err2 = ERROR_DISK_WRITE_PROTECTED;
  432.                     }
  433.                     else {
  434.                         if(error==DOSTRUE) {
  435.                             /* Open existing file, already done. */
  436.                         }
  437.                         /* else err2 still set from first trylockfile() call */
  438.                     }
  439.  
  440.                     if(error == DOSFALSE) {
  441.                         FreeVec(fharg1);
  442.                         MotorOff();
  443.                     }
  444.                 }
  445.                 else err2 = ERROR_NO_FREE_STORE;
  446.  
  447.                 break;
  448.             }
  449.  
  450.             case ACTION_READ:
  451.             {
  452.                 struct FHArg1 *fharg1 = (struct FHArg1 *)packet->dp_Arg1;
  453.                 APTR buffer = (APTR)packet->dp_Arg2;
  454.                 ULONG togo = packet->dp_Arg3;
  455.                 struct DataBlock *block = NULL;
  456.  
  457.                 if((err2 = TestLockRef((struct FileLock*)BADDR(fharg1->lock)))) {
  458.                     error = -1;
  459.                     break;
  460.                 }
  461.  
  462.                 if(fharg1->pos + togo >= fharg1->len)
  463.                     togo = fharg1->len - fharg1->pos;
  464.  
  465.                 error = 0;
  466.  
  467.                 if(fharg1->number == NUM_VIRTUAL) {
  468.                     /* Handle virtual files */
  469.                     int special = ((struct FileLock*)BADDR(fharg1->lock))->fl_Key & FLKEY_SPECIALMASK;
  470.  
  471.                     switch(special) {
  472.                         case FLKEY_DOLLAR:
  473.                             CopyMem(&curvolumenode->dollarbuf[fharg1->pos], buffer, togo);
  474.                             fharg1->pos += togo;
  475.                             error += togo;
  476.                             break;
  477.  
  478.                         case FLKEY_DISKINFO:
  479.                             CopyMem(&diskiconimg[fharg1->pos], buffer, togo);
  480.                             fharg1->pos += togo;
  481.                             error += togo;
  482.                             break;
  483.  
  484.                         case FLKEY_D64:
  485.                             while(togo) {
  486.                                 ULONG size, offset;
  487.  
  488.                                 if(!(block = getputblock((fharg1->pos)>>8, FALSE)))
  489.                                     break;
  490.  
  491.                                 offset = (fharg1->pos) & 255;
  492.  
  493.                                 size = 256 - offset;
  494.                                 if(togo < size)
  495.                                     size = togo;
  496.  
  497.                                 CopyMem(&((UBYTE*)block)[offset], buffer, size);
  498.  
  499.                                 buffer += size;
  500.                                 fharg1->pos += size;
  501.                                 error += size;
  502.                                 togo -= size;
  503.                             }
  504.                             break;
  505.  
  506.                         default:
  507.                             break;
  508.                     }
  509.                 }
  510.                 else {
  511.                     /* Handle real files */
  512.                     while(togo) {
  513.                         ULONG size;
  514.     
  515.                         if(fharg1->p == 254) {
  516.                             if(!block)
  517.                                 if(!(block = getblock_ts(fharg1->t, fharg1->s)))
  518.                                     break;
  519.                             fharg1->p = 0;
  520.                             fharg1->t = block->t;
  521.                             fharg1->s = block->s;
  522.                         }
  523.     
  524.                         size = 254 - fharg1->p;
  525.                         if(togo < size)
  526.                             size = togo;
  527.     
  528.                         if(!(block = getblock_ts(fharg1->t, fharg1->s)))
  529.                             break;
  530.     
  531.                         CopyMem(&block->data[fharg1->p], buffer, size);
  532.                         buffer += size;
  533.                         fharg1->p += size;
  534.                         fharg1->pos += size;
  535.                         error += size;
  536.                         togo -= size;
  537.                     }
  538.                 }
  539.  
  540.                 break;
  541.             }
  542.  
  543.             case ACTION_WRITE:
  544.             {
  545.                 struct FHArg1 *fharg1 = (struct FHArg1 *)packet->dp_Arg1;
  546.                 APTR buffer = (APTR)packet->dp_Arg2;
  547.                 ULONG togo = packet->dp_Arg3;
  548.                 struct DataBlock *block = NULL;
  549.                 struct DataBlock newblk;
  550.  
  551.                 error = -1;
  552.  
  553.                 if((err2 = TestLockRef((struct FileLock*)BADDR(fharg1->lock))))
  554.                     break;
  555.  
  556.                 if(wprotected) {
  557.                     err2 = ERROR_DISK_WRITE_PROTECTED;
  558.                     break;
  559.                 }
  560.  
  561.                 error = 0;
  562.  
  563.                 if((((struct FileLock*)BADDR(fharg1->lock))->fl_Key & FLKEY_SPECIALMASK) == FLKEY_D64) {
  564.                     /* Handle writes to the $d64 file */
  565.                     if(fharg1->pos + togo >= D64_SIZE)
  566.                         togo = D64_SIZE - fharg1->pos;
  567.  
  568.                     while(togo) {
  569.                         ULONG size, offset;
  570.  
  571.                         if(!(block = getputblock((fharg1->pos)>>8, FALSE)))
  572.                             break;
  573.  
  574.                         offset = (fharg1->pos) & 255;
  575.  
  576.                         size = 256 - offset;
  577.                         if(togo < size)
  578.                             size = togo;
  579.  
  580.                         CopyMem(buffer, &((UBYTE*)block)[offset], size);
  581.                         getputblock((fharg1->pos)>>8, TRUE);
  582.  
  583.                         buffer += size;
  584.                         fharg1->pos += size;
  585.                         error += size;
  586.                         togo -= size;
  587.                     }
  588.                     break;
  589.                 }
  590.  
  591.                 while(togo) {
  592.                     ULONG size;
  593.  
  594.                     if(!block)
  595.                         block = getblock_ts(fharg1->t, fharg1->s);
  596.  
  597.                     if(fharg1->p == 254) {
  598.                         /* Switch to next block */
  599.                         if(!block->t) {
  600.                             /* Allocate new block */
  601.                             UWORD dblk;
  602.  
  603.                             if(!(dblk = AllocBlock(fharg1->t, fharg1->s))) {
  604.                                 err2 = ERROR_DISK_FULL;
  605.                                 break;
  606.                             }
  607.  
  608.                             fharg1->p = 0;
  609.                             block->t = dblk>>8;
  610.                             block->s = dblk&0xff;
  611.                             putblock_ts(fharg1->t, fharg1->s, block); /* link to previous block */
  612.                             fharg1->t = block->t;
  613.                             fharg1->s = block->s;
  614.                             fharg1->numblocks++;
  615.  
  616.                             block = &newblk;
  617.                             memset(&newblk, 0, sizeof(newblk));
  618.                             block->t = 0;
  619.                             block->s = 1;
  620.                         }
  621.                         else {
  622.                             /* Jump to existing next block */
  623.                             fharg1->p = 0;
  624.                             fharg1->t = block->t;
  625.                             fharg1->s = block->s;
  626.                             block = getblock_ts(fharg1->t, fharg1->s);
  627.                         }
  628.                     }
  629.  
  630.                     size = 254 - fharg1->p;
  631.                     if(togo < size)
  632.                         size = togo;
  633.  
  634.                     /* Insert data */
  635.                     CopyMem(buffer, &block->data[fharg1->p], size);
  636.                     buffer += size;
  637.  
  638.                     /* Advance block pointer and dump it */
  639.                     fharg1->p += size;
  640.                     if(!block->t)
  641.                         block->s = fharg1->p + 1;
  642.                     putblock_ts(fharg1->t, fharg1->s, block);
  643.  
  644.                     /* Adjust length field if necessary */
  645.                     fharg1->pos += size;
  646.                     if(fharg1->pos > fharg1->len)
  647.                         fharg1->len = fharg1->pos;
  648.  
  649.                     error += size;
  650.                     togo -= size;
  651.                 }
  652.  
  653.                 break;
  654.             }
  655.  
  656.             case ACTION_SET_FILE_SIZE: {
  657.                 error = -1;
  658.                 err2 = ERROR_ACTION_NOT_KNOWN;
  659.                 break;
  660.             }
  661.  
  662.             case ACTION_SEEK:
  663.             {
  664.                 struct FHArg1 fharg1bak, *fharg1 = (struct FHArg1 *)packet->dp_Arg1;
  665.                 LONG move = packet->dp_Arg2;
  666.  
  667.                 if((err2 = TestLockRef((struct FileLock*)BADDR(fharg1->lock))))
  668.                     break;
  669.  
  670.                 error = fharg1->pos;
  671.                 err2 = ERROR_SEEK_ERROR;
  672.  
  673.                 switch(packet->dp_Arg3) {
  674.                     case OFFSET_BEGINNING:
  675.                         move = move - error;
  676.                         break;
  677.  
  678.                     case OFFSET_CURRENT:
  679.                         break;
  680.  
  681.                     case OFFSET_END:
  682.                         move = move + fharg1->len - error;
  683.                         break;
  684.  
  685.                     default:
  686.                         error = -1;
  687.                         break;
  688.                 }
  689.  
  690.                 if(error != -1) {
  691.                     CopyMem(fharg1, &fharg1bak, sizeof(struct FHArg1));
  692.  
  693.                     if((error+move)<0 || (error+move)>fharg1->len)
  694.                         error = -1;
  695.                     else {
  696.                         if(((struct FileLock*)BADDR(fharg1->lock))->fl_Key & FLKEY_SPECIALMASK) {
  697.                             /* Virtual files are easy */
  698.                             fharg1->pos += move;
  699.                         }
  700.                         else {
  701.                             if(move<0) {
  702.                                 /* When moving back, we have to rescan the whole file */
  703.                                 move = move + error;
  704.                                 fharg1->p = 0;
  705.                                 fharg1->pos = 0;
  706.                                 fharg1->t = fharg1->t0;
  707.                                 fharg1->s = fharg1->s0;
  708.                             }
  709.     
  710.                             while(move) {
  711.                                 ULONG size;
  712.                                 struct DataBlock *block;
  713.     
  714.                                 if(fharg1->p == 254) {
  715.                                     block = getblock_ts(fharg1->t, fharg1->s);
  716.  
  717.                                     if(!block) {
  718.                                         CopyMem(&fharg1bak, fharg1, sizeof(struct FHArg1));
  719.                                         error = -1;
  720.                                         err2 = ABORT_DISK_ERROR;
  721.                                         break;
  722.                                     }
  723.  
  724.                                     fharg1->p = 0;
  725.                                     fharg1->t = block->t;
  726.                                     fharg1->s = block->s;
  727.                                 }
  728.     
  729.                                 size = 254 - fharg1->p;
  730.             
  731.                                 if(move < size)
  732.                                     size = move;
  733.             
  734.                                 fharg1->p += size;
  735.                                 fharg1->pos += size;
  736.                                 move -= size;
  737.                             }
  738.                         }
  739.                     }
  740.                 }
  741.  
  742.                 break;
  743.             }
  744.  
  745.             case ACTION_END:
  746.             {
  747.                 struct FHArg1 *fharg1 = (struct FHArg1 *)packet->dp_Arg1;
  748.  
  749.                 if((err2 = TestLockRef((struct FileLock*)BADDR(fharg1->lock))))
  750.                     break;
  751.  
  752.                 if(fharg1->len != fharg1->len0) {
  753.                     /* File has been modified, update disk structure */
  754.                     int i;
  755.  
  756.                     for(i=0;i<dirsize;i++)
  757.                         if(directory[i].datat == fharg1->t0
  758.                         && directory[i].datas == fharg1->s0)
  759.                         {
  760.                             UWORD blks = fharg1->numblocks;
  761.                             directory[i].lengthl = blks&0xff;
  762.                             directory[i].lengthh = blks>>8;
  763.                             directory[i].type |= 0x80;
  764.                         }
  765.  
  766.                     StartUDSTimer();
  767.                 }
  768.  
  769.                 freelock(BADDR(fharg1->lock));
  770.                 FreeVec(fharg1);
  771.  
  772.                 error = DOSTRUE;
  773.                 break;
  774.             }
  775.  
  776.             case ACTION_IS_FILESYSTEM:
  777.                 /* Yes, we are. */
  778.                 error = DOSTRUE;
  779.                 break;
  780.  
  781.             case ACTION_CURRENT_VOLUME:
  782.             {
  783.                 struct FHArg1 *fharg1 = (struct FHArg1 *)packet->dp_Arg1;
  784.  
  785.                 /* The packet name is somewhat misleading... */
  786.                 if(fharg1)
  787.                     error = ((struct FileLock*)BADDR(fharg1->lock))->fl_Volume;
  788.                 else {
  789.                     if(curvolumenode)
  790.                         error = (LONG)MKBADDR(curdoslist);
  791.                     else
  792.                         error = NULL;
  793.                 }
  794.  
  795.                 break;
  796.             }
  797.  
  798.             case ACTION_INFO:
  799.             case ACTION_DISK_INFO:
  800.             {
  801.                 struct InfoData *id;
  802.  
  803.                 if(packet->dp_Type == ACTION_INFO) {
  804.                     struct FileLock *fl = BADDR(packet->dp_Arg1);
  805.  
  806.                     if(fl && fl->fl_Volume != MKBADDR(curdoslist)) {
  807.                         /* The reference disk is currently not inserted. */
  808.                         err2 = ERROR_DEVICE_NOT_MOUNTED;
  809.                         break;
  810.                     }
  811.  
  812.                     id = BADDR(packet->dp_Arg2);
  813.                 }
  814.                 else {
  815.                     id = BADDR(packet->dp_Arg1);
  816.                 }
  817.  
  818.                 id->id_NumSoftErrors = numsofterrors;
  819.                 id->id_NumBlocks = 683;
  820.                 id->id_NumBlocksUsed = UsedBlocks();
  821.                 id->id_BytesPerBlock = 254;
  822.                 id->id_DiskState = hardwprot ? ID_WRITE_PROTECTED : (wprotected ? ID_VALIDATING : ID_VALIDATED);
  823.                 id->id_UnitNumber = fssm->fssm_Unit;
  824.  
  825.                 if(curvolumenode) {
  826.                     id->id_DiskType = ID_DOS_DISK;
  827.                     id->id_VolumeNode = MKBADDR(curdoslist);
  828.                     id->id_InUse = curvolumenode->locklist ? DOSTRUE : DOSFALSE;
  829.                 }
  830.                 else {
  831.                     #ifndef ID_BUSY /* My v40 header files don't */
  832.                     #define ID_BUSY 0x42555359
  833.                     #endif
  834.                     id->id_DiskType = inhibited ? ID_BUSY : (disk_inserted ? ID_UNREADABLE_DISK : ID_NO_DISK_PRESENT);
  835.                 }
  836.  
  837.                 error = DOSTRUE;
  838.  
  839.                 break;
  840.             }
  841.  
  842.             case ACTION_INHIBIT:
  843.             {
  844.                 /* We could have trouble here if the DosList is locked,
  845.                    but then again, one shouldn't lock it for INHIBIT. */
  846.  
  847.                 if(packet->dp_Arg1 == DOSTRUE) {
  848.                     if(inhibited == FALSE) {
  849.                         inhibited = TRUE;
  850.  
  851.                         StopUDSTimer();
  852.                         MotorOff();
  853.                         DoDiskRemove();
  854.                     }
  855.                 }
  856.                 else if(inhibited == TRUE) {
  857.                     DoDiskInsert();
  858.  
  859.                     inhibited = FALSE;
  860.                 }
  861.  
  862.                 error = DOSTRUE;
  863.  
  864.                 break;
  865.             }
  866.  
  867.             case ACTION_CREATE_DIR:
  868.                 err2 = ERROR_INVALID_COMPONENT_NAME;
  869.                 break;
  870.  
  871.             case ACTION_DELETE_OBJECT:
  872.             {
  873.                 struct FileLock *fl = BADDR(packet->dp_Arg1);
  874.                 struct FHArg1 fharg1;
  875.  
  876.                 if((err2 = TestLock(fl)))
  877.                     break;
  878.  
  879.                 if(!wprotected) {
  880.                     if(trylockfile(&err2, packet->dp_Arg2, EXCLUSIVE_LOCK, &fharg1, FALSE)) {
  881.                         struct DataBlock *block;
  882.                         UBYTE t,s;
  883.     
  884.                         freelock((struct FileLock*)BADDR(fharg1.lock));
  885.     
  886.                         if(fharg1.number != NUM_VIRTUAL) {
  887.                             /* We do this only for non-virtual files. */
  888.                             for(t=fharg1.t,s=fharg1.s; t; t=block->t,s=block->s) {
  889.                                 block = getblock_ts(t,s);
  890.                                 FreeBlock(t,s);
  891.                             }
  892.         
  893.                             directory[fharg1.number].type = 0x00;
  894.                             StartUDSTimer();
  895.                             error = DOSTRUE;
  896.                         }
  897.                         else err2 = ERROR_DELETE_PROTECTED;
  898.                     }
  899.                 }
  900.                 else err2 = ERROR_DISK_WRITE_PROTECTED;
  901.  
  902.                 MotorOff();
  903.                 break;
  904.             }
  905.  
  906.             case ACTION_FORMAT:
  907.             {
  908.                 UBYTE buf[18];
  909.                 STRPTR a;
  910.                 struct DataBlock blk1;
  911.  
  912.                 ResetDisk();
  913.  
  914.                 if(!hardwprot) {
  915.                     if((a = BADDR(packet->dp_Arg1))) {
  916.                         int l = a[0]>16 ? 16 : a[0];
  917.                         CopyMem(&a[1], buf, l);
  918.                         buf[l] = '\0';
  919.                     }
  920.                     else buf[0] = '\0';
  921.  
  922.                     asciito64(empty_bam.name, buf, 16);
  923.                     putblock_ts(18,0,&empty_bam);
  924.                     memset(&blk1, 0, sizeof(blk1));
  925.                     blk1.s = 0xff;
  926.                     putblock_ts(18,1,&blk1);
  927.  
  928.                     error = DOSTRUE;
  929.                 }
  930.                 else err2 = ERROR_DISK_WRITE_PROTECTED;
  931.  
  932.                 break;
  933.             }
  934.  
  935.             case ACTION_RENAME_DISK:
  936.             {
  937.                 UBYTE buf[18];
  938.                 STRPTR a;
  939.  
  940.                 if(curvolumenode) {
  941.                     if(!wprotected) {
  942.                         if((a = BADDR(packet->dp_Arg1))) {
  943.                             int l = a[0]>16 ? 16 : a[0];
  944.                             CopyMem(&a[1], buf, l);
  945.                             buf[l] = '\0';
  946.                         }
  947.                         else buf[0] = '\0';
  948.  
  949.                         asciito64(bam->name, buf, 16);
  950.  
  951.                         while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  952.                             DoPackets();
  953.                         copy64name(&curvolumenode->name[1], bam->name, 16);
  954.                         curvolumenode->name[0] = strlen(&curvolumenode->name[1]);
  955.                         UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  956.  
  957.                         StartUDSTimer();
  958.  
  959.                         error = DOSTRUE;
  960.                     }
  961.                     else err2 = ERROR_DISK_WRITE_PROTECTED;
  962.                 }
  963.                 else err2 = disk_inserted ? ERROR_NOT_A_DOS_DISK : ERROR_NO_DISK;
  964.  
  965.                 break;
  966.             }
  967.  
  968.             case ACTION_RENAME_OBJECT:
  969.             {
  970.                 struct FileLock *fl1 = BADDR(packet->dp_Arg1),
  971.                                 *fl2 = BADDR(packet->dp_Arg3);
  972.                 struct FHArg1 fharg1;
  973.  
  974.                 if(!((err2 = TestLock(fl1)) || (err2 = TestLock(fl2)))) {
  975.                     if(!wprotected) {
  976.                         if(trylockfile(&err2, packet->dp_Arg2, SHARED_LOCK, &fharg1, FALSE)) {
  977.                             freelock((struct FileLock*)BADDR(fharg1.lock));
  978.  
  979.                             if(fharg1.number != NUM_VIRTUAL) {
  980.                                 STRPTR a;
  981.                                 UBYTE buf[256];
  982.  
  983.                                 if((a = BADDR(packet->dp_Arg4))) {
  984.                                     CopyMem(&a[1], buf, a[0]);
  985.                                     buf[a[0]] = '\0';
  986.  
  987.                                     if(!strchr(buf, '/')) {
  988.                                         a = strchr(buf, ':');
  989.                                         strncpy(fname1, a ? a+1 : buf, 17);
  990.                                         fname1[16] = '\0';
  991.  
  992.                                         asciito64(directory[fharg1.number].name, fname1, 16);
  993.                                         StartUDSTimer();
  994.                                         error = DOSTRUE;
  995.                                     }
  996.                                     else err2 = ERROR_INVALID_COMPONENT_NAME;
  997.                                 }
  998.                                 else err2 = ERROR_INVALID_COMPONENT_NAME;
  999.                             }
  1000.                             else err2 = ERROR_OBJECT_NOT_FOUND;
  1001.                         }
  1002.                     }
  1003.                     else err2 = ERROR_DISK_WRITE_PROTECTED;
  1004.                 }
  1005.  
  1006.                 break;
  1007.             }
  1008.  
  1009.             default:
  1010.                 err2 = ERROR_ACTION_NOT_KNOWN;
  1011.                 break;
  1012.         }
  1013.     
  1014.         ReturnPacket(packet, error, err2);
  1015.     }
  1016. }
  1017.  
  1018. static LONG TestLock(struct FileLock *fl)
  1019. {
  1020.     if(fl) {
  1021.         if(fl->fl_Volume != MKBADDR(curdoslist))
  1022.             /* The reference disk is currently not inserted. */
  1023.             return(ERROR_DEVICE_NOT_MOUNTED);
  1024.         if(fl->fl_Key != 0)
  1025.             /* An invalid lock has been passed. */
  1026.             return(ERROR_OBJECT_WRONG_TYPE);
  1027.     }
  1028.     return(0);
  1029. }
  1030.  
  1031. static inline LONG TestLockRef(struct FileLock *fl)
  1032. {
  1033.     if(fl->fl_Volume != MKBADDR(curdoslist))
  1034.         /* The reference disk is currently not inserted. */
  1035.         return(ERROR_DEVICE_NOT_MOUNTED);
  1036.     return(0);
  1037. }
  1038.  
  1039. /*-------------------------------------------------------------------------*/
  1040.  
  1041. static BOOL getfiledata(UBYTE entry, struct FHArg1 *fharg1)
  1042. {
  1043.     if(directory[entry].name[0] != 0xa0) {
  1044.         UWORD type = (directory[entry].type) & 0x7;
  1045.  
  1046.         if(type!=0x00) { // anything but DEL-Files
  1047.             struct DataBlock *block;
  1048.             int i,t,s,size;
  1049.  
  1050.             for(i=0,t=directory[entry].datat,s=directory[entry].datas,size=0;
  1051.                 i<683; /* a primitive solution to overcome circular links */
  1052.                 t=block->t,s=block->s,i++)
  1053.             {
  1054.                 if(!(block = getblock_ts(t,s)))
  1055.                     return(FALSE);
  1056.  
  1057.                 if(block->t)
  1058.                     size+=254;
  1059.                 else {
  1060.                     size+=block->s-1;
  1061.                     break;
  1062.                 }
  1063.             }
  1064.  
  1065.             if(i<683) {
  1066.                 fharg1->len = fharg1->len0 = size;
  1067.                 fharg1->numblocks = i+1;
  1068.                 fharg1->t = fharg1->t0 = directory[entry].datat;
  1069.                 fharg1->s = fharg1->s0 = directory[entry].datas;
  1070.                 fharg1->number = entry;
  1071.                 return(TRUE);
  1072.             }
  1073.         }
  1074.     }
  1075.  
  1076.     return(FALSE);
  1077. }
  1078.  
  1079. /*-------------------------------------------------------------------------*/
  1080.  
  1081. /* May only be called if curvolumenode is valid! */
  1082. static BPTR trylockfile(LONG *err2, BSTR name, LONG access, struct FHArg1 *fharg1, BOOL allow_root)
  1083. {
  1084.     UBYTE buf[256];
  1085.     STRPTR a;
  1086.     LONG error;
  1087.  
  1088.     error = DOSFALSE;
  1089.  
  1090.     /* Convert BSTR argument into C string */
  1091.     if((a = BADDR(name))) {
  1092.         CopyMem(&a[1], buf, a[0]);
  1093.         buf[a[0]] = '\0';
  1094.  
  1095.         if(strchr(buf, '/')) {
  1096.             /* User tries to access subdirectories */
  1097.             *err2 = ERROR_INVALID_COMPONENT_NAME;
  1098.             return(error);
  1099.         }
  1100.  
  1101.         a = strchr(buf, ':');
  1102.         strncpy(fname1, a ? a+1 : buf, 17);
  1103.         fname1[16] = '\0';
  1104.     }
  1105.     else
  1106.         fname1[0] = '\0';
  1107.  
  1108.     if(fname1[0] == '\0') {
  1109.         if(allow_root) {
  1110.             /* Return lock on root directory */
  1111.             if(access == EXCLUSIVE_LOCK) {
  1112.                 *err2 = ERROR_OBJECT_IN_USE;
  1113.             }
  1114.             else {
  1115.                 *err2 = ERROR_NO_FREE_STORE;
  1116.                 error = makelock(0, access);
  1117.             }
  1118.         }
  1119.         else *err2 = ERROR_OBJECT_WRONG_TYPE;
  1120.     }
  1121.     else {
  1122.         int entry;
  1123.  
  1124.         *err2 = ERROR_OBJECT_NOT_FOUND;
  1125.  
  1126.         /* Look up file in directory and lock it */
  1127.         for(entry=0;entry<dirsize;entry++) {
  1128.             copy64name(buf, directory[entry].name, 16);
  1129.             if(!Stricmp(buf, fname1))
  1130.                 break;
  1131.         }
  1132.  
  1133.         if(entry == dirsize) {
  1134.             /* Perhaps we can provide a virtual file */
  1135.             fharg1->number = NUM_VIRTUAL;
  1136.  
  1137.             if(!Stricmp(VIRTUAL_FILE_DISKINFO,fname1)) {
  1138.                 *err2 = ERROR_NO_FREE_STORE;
  1139.                 error = fharg1->lock = makelock(FLKEY_DISKINFO, access);
  1140.                 fharg1->len = fharg1->len0 = diskiconlength;
  1141.             }
  1142.             else if(fname1[0] == '$') {
  1143.                 if(!Stricmp(VIRTUAL_FILE_DOLLAR,fname1)) {
  1144.                     *err2 = ERROR_NO_FREE_STORE;
  1145.                     error = fharg1->lock = makelock(FLKEY_DOLLAR, access);
  1146.                     fharg1->len = fharg1->len0 = curvolumenode->dollarlen;
  1147.                 }
  1148.                 else if(!Stricmp(VIRTUAL_FILE_D64,fname1)) {
  1149.                     *err2 = ERROR_NO_FREE_STORE;
  1150.                     error = fharg1->lock = makelock(FLKEY_D64, access);
  1151.                     fharg1->len = fharg1->len0 = D64_SIZE;
  1152.                 }
  1153.                 else if(!Stricmp(VIRTUAL_FILE_OPT,fname1)) {
  1154.                     if(!wprotected) {
  1155.                         *err2 = ERROR_NO_FREE_STORE;
  1156.                         error = fharg1->lock = makelock(FLKEY_OPT, access);
  1157.                         fharg1->len = fharg1->len0 = 0;
  1158.                         OptimizeDirectory();
  1159.                         StartUDSTimer();
  1160.                     }
  1161.                     else *err2 = ERROR_DISK_WRITE_PROTECTED;
  1162.                 }
  1163.             }
  1164.         }
  1165.         else {
  1166.             if(getfiledata(entry, fharg1)) {
  1167.                 if(lockable(fharg1->t, fharg1->s, access)) {
  1168.                     *err2 = ERROR_NO_FREE_STORE;
  1169.                     error = fharg1->lock = makelock(((fharg1->t)<<8)|fharg1->s, access);
  1170.                 }
  1171.                 else *err2 = ERROR_OBJECT_IN_USE;
  1172.             }
  1173.         }
  1174.     }
  1175.  
  1176.     return(error);
  1177. }
  1178.