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

  1. /*
  2.     FS1541
  3.  
  4.     volume.c
  5.  
  6.  
  7.     Volume, BAM and lock handling.
  8.  
  9. */
  10.  
  11. #include <stdio.h> /* contains decl of sprintf, but will be linked from amiga.lib! */
  12. #include <string.h>
  13.  
  14. #include <exec/types.h>
  15. #include <exec/execbase.h>
  16. #include <exec/memory.h>
  17. #include <dos/dosextens.h>
  18. #include <dos/filehandler.h>
  19. #include <devices/trackdisk.h>
  20. #include <devices/timer.h>
  21.  
  22. #include <proto/exec.h>
  23. #include <proto/dos.h>
  24. #include <proto/alib.h>
  25. #include <proto/utility.h>
  26.  
  27. #include "main.h"
  28. #include "volume.h"
  29. #include "disk.h"
  30. #include "packet.h"
  31. #include "support.h"
  32.  
  33. BYTE diskchgintbit = -1;
  34. struct VolumeNode *curvolumenode = NULL;
  35. struct DosList *curdoslist = NULL;
  36.  
  37. int disk_inserted = FALSE;
  38.  
  39. struct BAM *bam;
  40. struct DirEntry directory[144];
  41. int dirsize;
  42.  
  43. UBYTE interleave = 4;
  44.  
  45. static struct MinList volumelist;
  46.  
  47. static struct IOExtTD *diskchgint_req;
  48. static void diskchginthandler(void)
  49. {
  50.     Signal(ourtask, 1<<diskchgintbit);
  51. }
  52. static struct Interrupt diskchgint =
  53. {
  54.     { NULL, NULL, NT_INTERRUPT, 0, "FS1541" },
  55.     NULL,
  56.     (APTR)&diskchginthandler
  57. };
  58.  
  59. static struct MsgPort *UDStimerport;
  60. struct timerequest *UDStimer;
  61. static int timeropen = 0;
  62.  
  63. static void CreateDollar(struct VolumeNode *node);
  64.  
  65. /*-------------------------------------------------------------------------*/
  66.  
  67. LONG InitVolumeSS(void)
  68. {
  69.     LONG error = 0;
  70.  
  71.     if((UDStimerport = CreateMsgPort()))
  72.     {
  73.         if((UDStimer = CreateIORequest(UDStimerport, sizeof(struct timerequest))))
  74.         {
  75.             if((timeropen = (!OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)UDStimer,0))))
  76.             {
  77.                 if((diskchgintbit = AllocSignal(-1))>=0)
  78.                 {
  79.                     if((diskchgint_req = AllocVec(sizeof(struct IOExtTD), MEMF_PUBLIC)))
  80.                     {
  81.                         NewList((struct List*)&volumelist);
  82.             
  83.                         CopyMem(diskreq, diskchgint_req, sizeof(struct IOExtTD));
  84.                         diskchgint_req->iotd_Req.io_Command = TD_ADDCHANGEINT;
  85.                         diskchgint_req->iotd_Req.io_Data = &diskchgint;
  86.                         diskchgint_req->iotd_Req.io_Length = sizeof(struct Interrupt);
  87.                         diskchgint_req->iotd_Req.io_Flags = 0;
  88.                         SendIO((struct IORequest*)diskchgint_req);
  89.             
  90.                         return(0);
  91.             
  92.                     } else error = ERROR_NO_FREE_STORE;
  93.                 } else error = ERROR_NO_FREE_STORE;
  94.             } else error = ERROR_DEVICE_NOT_MOUNTED;
  95.         } else error = ERROR_NO_FREE_STORE;
  96.     } else error = ERROR_NO_FREE_STORE;
  97.  
  98.     QuitVolumeSS();
  99.     return(error);
  100. }
  101.  
  102. void QuitVolumeSS(void)
  103. {
  104.     if(diskchgint_req)
  105.     {
  106.         diskchgint_req->iotd_Req.io_Command = TD_REMCHANGEINT;
  107.         diskchgint_req->iotd_Req.io_Data = &diskchgint;
  108.         diskchgint_req->iotd_Req.io_Length = sizeof(struct Interrupt);
  109.         diskchgint_req->iotd_Req.io_Flags = 0;
  110.         DoIO((struct IORequest*)diskchgint_req);
  111.  
  112.         FreeVec(diskchgint_req);
  113.     }
  114.  
  115.     if(diskchgintbit >= 0)
  116.         FreeSignal(diskchgintbit);
  117.  
  118.     if(timeropen) {
  119.         StopUDSTimer();
  120.         CloseDevice((struct IORequest*)UDStimer);
  121.     }
  122.  
  123.     if(UDStimer)
  124.         DeleteIORequest(UDStimer);
  125.  
  126.     if(UDStimerport)
  127.         DeleteMsgPort(UDStimerport);
  128. }
  129.  
  130. /*-------------------------------------------------------------------------*/
  131.  
  132. void DoDiskInsert(void)
  133. {
  134.     diskreq->iotd_Req.io_Command = TD_CHANGESTATE;
  135.     diskreq->iotd_Req.io_Flags = IOF_QUICK;
  136.     DoIO((struct IORequest*)diskreq);
  137.  
  138.     if(diskreq->iotd_Req.io_Actual)
  139.     {
  140.         /* Switch off the motor. */
  141.         diskreq->iotd_Req.io_Command = TD_MOTOR;
  142.         diskreq->iotd_Req.io_Flags = 0;
  143.         diskreq->iotd_Req.io_Length = 0;
  144.         DoIO((struct IORequest*)diskreq);
  145.     }
  146.     else
  147.     {
  148.         /* Disk has been inserted. */
  149.         int i,t,s;
  150.         UBYTE diskname[20];
  151.         struct VolumeNode *node;
  152.  
  153.         disk_inserted = TRUE;
  154.  
  155.         ResetDisk();
  156.         wprotected = hardwprot;
  157.  
  158.         /* Read Block Allocation Map */
  159.         if(!(bam = (struct BAM*)getblock_ts(18,0)))
  160.             return;
  161.  
  162.         if(bam->id != 'A')
  163.             wprotected = TRUE;
  164.  
  165.         /* Read directory */
  166.         for(i=0, dirsize=0, t=18/*bam->dirt*/, s=1/*bam->dirs*/; /* 1541 always uses 18,1 */
  167.             i<18;
  168.             t=directory[8*i].t, s=directory[8*i].s, i++)
  169.         {
  170.             struct DataBlock *block;
  171.  
  172.             if(!(block = getblock_ts(t, s)))
  173.                 return;
  174.             CopyMem(block, &directory[8*i], 256);
  175.  
  176.             dirsize += 8;
  177.  
  178.             if(!directory[8*i].t)
  179.                 break;
  180.         }
  181.  
  182.         /* Strip trailing type 0x00 entries */
  183.         for(i=dirsize; --i>=0 && directory[i].type == 0x00; dirsize--);
  184.  
  185.         /* Check if this is a volume we know */
  186.         copy64name(diskname, bam->name, 16);
  187.         for(node=(struct VolumeNode*)volumelist.mlh_Head;
  188.             node->node.mln_Succ;
  189.             node=(struct VolumeNode*)(node->node.mln_Succ))
  190.         {
  191.             if(!Stricmp(diskname,&node->name[1]))
  192.             {
  193.                 while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  194.                     DoPackets();
  195.                 curvolumenode = node;
  196.                 curdoslist = node->volnode;
  197.                 curdoslist->dol_Task = ourport;
  198.                 curdoslist->dol_misc.dol_volume.dol_LockList = NULL;
  199.                 UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  200.                 SendEvent(TRUE);
  201.                 return;
  202.             }
  203.         }
  204.  
  205.         /* Create a new volume node */
  206.         if((node = AllocVec(sizeof(struct VolumeNode), MEMF_PUBLIC|MEMF_CLEAR)))
  207.         {
  208.             struct DosList *newvol;
  209.  
  210.             if((newvol = AllocVec(sizeof(struct DosList), MEMF_PUBLIC|MEMF_CLEAR)))
  211.             {
  212.                 /* Generate DosList entry (Volume) */
  213.                 LONG rc;
  214.  
  215.                 newvol->dol_Type = DLT_VOLUME;
  216.                 newvol->dol_Task = ourport;
  217.                 newvol->dol_misc.dol_volume.dol_DiskType = ID_DOS_DISK;
  218.                 newvol->dol_Name = (BSTR)MKBADDR(&node->name);
  219.  
  220.                 copy64name(&node->name[1], bam->name, 16);
  221.                 node->name[0] = strlen(&node->name[1]);
  222.  
  223.                 node->volnode = newvol;
  224.                 AddHead((struct List*)&volumelist, (struct Node*)node);
  225.  
  226.                 while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  227.                     DoPackets();
  228.                 rc = AddDosEntry(newvol);
  229.                 UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  230.                 if(rc)
  231.                 {
  232.                     curvolumenode = node;
  233.                     curdoslist = newvol; 
  234.  
  235.                     CreateDollar(node);
  236.  
  237.                     SendEvent(TRUE);
  238.                     MotorOff();
  239.                     return;
  240.                 }
  241.                 FreeVec(newvol);
  242.             }
  243.             FreeVec(node);
  244.         }
  245.     }
  246.  
  247.     MotorOff();
  248. }
  249.  
  250. void DoDiskRemove(void)
  251. {
  252.     disk_inserted = FALSE;
  253.  
  254.     if(curvolumenode)
  255.     {
  256.         if(!curvolumenode->locklist)
  257.         {
  258.             /* No locks -> remove completely */
  259.             while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  260.                 DoPackets();
  261.             RemDosEntry(curdoslist);
  262.             Remove((struct Node*)curvolumenode);
  263.             FreeVec(curvolumenode);
  264.             UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  265.             SendEvent(FALSE);
  266.         }
  267.         else
  268.         {
  269.             /* Do not remove completely, leave disk icon on Workbench. */
  270.             while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  271.                 DoPackets();
  272.             curdoslist->dol_Task = NULL;
  273.             curdoslist->dol_misc.dol_volume.dol_LockList = (BPTR)curvolumenode->locklist;
  274.             UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  275.             SendEvent(FALSE);
  276.         }
  277.  
  278.         curvolumenode = NULL;
  279.         curdoslist = NULL;
  280.     }
  281. }
  282.  
  283. /*-------------------------------------------------------------------------*/
  284.  
  285. static void CreateDollar(struct VolumeNode *node)
  286. {
  287.     UBYTE buf[32], *p=node->dollarbuf;
  288.     int i,j;
  289.     static char *types[8] = { "DEL", "SEQ", "PRG", "USR", "REL", "???", "???", "???" };
  290.  
  291.     copy64name(buf, bam->name2, 5);
  292.     if(bam->name2[2] == 0xA0)
  293.     {
  294.         buf[2] = ' ';
  295.         copy64name(&buf[3], &bam->name2[3], 2);
  296.     }
  297.  
  298.     sprintf(p, "0 \033[7m\"%-16s\" %-5s\033[0m\n", &node->name[1], buf);
  299.     p += strlen(p);
  300.  
  301.     for(i=0;i<dirsize;i++)
  302.     {
  303.         UBYTE type;
  304.  
  305.         if((type=directory[i].type) == 0x00)
  306.             continue;
  307.  
  308.         copy64name(buf, directory[i].name, 16);
  309.         sprintf(p, "%-5ld\"%s\"", (ULONG)(directory[i].lengthh<<8)|directory[i].lengthl, buf);
  310.         p += strlen(p);
  311.         for(j=0;j<=(16-strlen(buf));j++)
  312.             *p++ = ' ';
  313.         sprintf(p, "%s%lc\n", types[type&7], type&0x80 ? (type&0x40 ? '<' : ' ') : '*');
  314.         p += strlen(p);
  315.     }
  316.  
  317.     sprintf(p, "%ld BLOCKS FREE.\n", (ULONG)(683-UsedBlocks()));
  318.     p += strlen(p);
  319.  
  320.     node->dollarlen = (ULONG)(p - node->dollarbuf);
  321. }
  322.  
  323. /*-------------------------------------------------------------------------*/
  324.  
  325. static ULONG bam_secmask[21] = {
  326.     1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
  327.     1<<8,  1<<9,  1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
  328.     1<<0,  1<<1,  1<<2,  1<<3,  1<<4
  329. };
  330.  
  331. static BYTE SearchFreeBlockOnTrack(UBYTE track, UBYTE froms)
  332. {
  333.     UBYTE i,s,numsecs;
  334.     ULONG mask, plan=bam->tracks[track-1];
  335.  
  336.     if(plan>>24 > 0)
  337.     {
  338.         if(track<=17)
  339.             numsecs = 21;
  340.         else if(track<=24)
  341.             numsecs = 19;
  342.         else if(track<=30)
  343.             numsecs = 18;
  344.         else
  345.             numsecs = 17;
  346.  
  347.         s = froms + interleave;
  348.  
  349.         for(i=0;i<numsecs;i++,s++)
  350.         {
  351.             s = s % numsecs;
  352.             mask = bam_secmask[s];
  353.  
  354.             if(plan & mask)
  355.             {
  356.                 /* Free sector found. */
  357.                 plan &= ~mask;
  358.                 plan -= (1<<24);
  359.                 bam->tracks[track-1] = plan;
  360.                 return(s);
  361.             }
  362.         }
  363.  
  364.         /* If we reach this point, the BAM is corrupted... */
  365.     }
  366.  
  367.     return(-1);
  368. }
  369.  
  370. UWORD AllocBlock(UBYTE fromt, UBYTE froms)
  371. {
  372.     UBYTE track = fromt;
  373.     BYTE sector;
  374.     BOOL flag = 0;
  375.     BYTE dir = track<18 ? -1 : 1;
  376.  
  377.     while(1)
  378.     {
  379.         if(track == 18)
  380.             track += dir;
  381.  
  382.         if((sector = SearchFreeBlockOnTrack(track, track==fromt ? froms : 0)) >= 0)
  383.             return((track<<8)|sector);
  384.  
  385.         track += dir;
  386.  
  387.         if(track == 0)
  388.         {
  389.             if(flag)
  390.                 return(0);
  391.             flag++;
  392.             dir = 1;
  393.             track = fromt+1;
  394.         }
  395.  
  396.         if(track == 36)
  397.         {
  398.             if(flag)
  399.                 return(0);
  400.             flag++;
  401.             dir = -1;
  402.             track = fromt-1;
  403.         }
  404.     }
  405. }
  406.  
  407. void FreeBlock(UBYTE t, UBYTE s)
  408. {
  409.     if(t>=1 && t<=35)
  410.     {
  411.         UBYTE numsecs;
  412.  
  413.         if(t<=17)
  414.             numsecs = 21;
  415.         else if(t<=24)
  416.             numsecs = 19;
  417.         else if(t<=30)
  418.             numsecs = 18;
  419.         else
  420.             numsecs = 17;
  421.  
  422.         if(s<numsecs)
  423.         {
  424.             ULONG plan = bam->tracks[t-1];
  425.  
  426.             plan |= bam_secmask[s];
  427.             plan += (1<<24);
  428.             bam->tracks[t-1] = plan;
  429.         }
  430.     }
  431. }
  432.  
  433. UWORD UsedBlocks(void)
  434. {
  435.     int i;
  436.     UWORD r=683;
  437.  
  438.     if(curvolumenode)
  439.     {
  440.         for(i=1;i<=17;i++)
  441.             r -= bam->tracks[i-1]>>24;
  442.         for(i=19;i<=35;i++)
  443.             r -= bam->tracks[i-1]>>24;
  444.     }
  445.  
  446.     return(r);
  447. }
  448.  
  449. /*-------------------------------------------------------------------------*/
  450.  
  451. void OptimizeDirectory(void)
  452. {
  453.     int i, newdirsize=0;
  454.  
  455.     /* Throw out all DEL files */
  456.     for(i=0;i<dirsize;i++)
  457.         if(((directory[i].type) & 0x7) != 0x00)
  458.             memmove(&directory[newdirsize++], &directory[i], sizeof(struct DirEntry));
  459.  
  460.     dirsize = newdirsize;
  461.     memset(&directory[dirsize], 0, (144-newdirsize)*sizeof(struct DirEntry));
  462.  
  463.     /* Clear all Track/Sector fields */
  464.     for(i=0;i<dirsize;i++) {
  465.         directory[i].t = 0;
  466.         directory[i].s = 0;
  467.     }
  468. }
  469.  
  470. /*-------------------------------------------------------------------------*/
  471.  
  472. void StopUDSTimer(void)
  473. {
  474.     if(!CheckIO((struct IORequest*)UDStimer)) {
  475.         AbortIO((struct IORequest*)UDStimer);
  476.         WaitIO((struct IORequest*)UDStimer);
  477.     }
  478.     SetSignal(0, 1<<(UDStimerport->mp_SigBit));
  479. }
  480.  
  481. void StartUDSTimer(void)
  482. {
  483.     StopUDSTimer();
  484.  
  485.     UDStimer->tr_time.tv_secs = 1;
  486.     UDStimer->tr_time.tv_micro = 0;
  487.     UDStimer->tr_node.io_Command = TR_ADDREQUEST;
  488.     SendIO((struct IORequest*)UDStimer);
  489. }
  490.  
  491. void UpdateDiskStructure(void)
  492. {
  493.     int i,n;
  494.     UBYTE s,s2;
  495.  
  496.     if(!CheckIO((struct IORequest*)UDStimer))
  497.         return;
  498.  
  499.     StopUDSTimer();
  500.  
  501.     /* Strip trailing type 0x00 entries */
  502.     for(i=dirsize; --i>=0 && directory[i].type == 0x00; dirsize--);
  503.  
  504.     /* Write BAM and directory blocks */
  505.     bam->dirt = 18;
  506.     bam->dirs = 1;
  507.     bam->tracks[18-1] = 0x11fcff07; /* Block 0 is BAM and Block 1 is first directory block */
  508.     i = dirsize>>3;
  509.     s2 = 1;
  510.     for(n=0;n<=i;n++)
  511.     {
  512.         s = s2;
  513.  
  514.         if(n<i)
  515.         {
  516.             s2 = SearchFreeBlockOnTrack(18,s); /* will always succeed */
  517.             directory[n<<3].t = 18;
  518.             directory[n<<3].s = s2;
  519.         }
  520.         else
  521.         {
  522.             directory[n<<3].t = 0;
  523.             directory[n<<3].s = 0xff;
  524.         }
  525.  
  526.         putblock_ts(18,s,&directory[n<<3]);
  527.     }
  528.     putblock_ts(18,0,bam);
  529.     MotorOff();
  530.  
  531.     CreateDollar(curvolumenode);
  532. }
  533.  
  534. /*-------------------------------------------------------------------------*/
  535.  
  536. BPTR makelock(LONG flkey, LONG axs)
  537. {
  538.     struct FileLock *fl;
  539.  
  540.     if((fl = AllocVec(sizeof(struct FileLock), MEMF_PUBLIC|MEMF_CLEAR)))
  541.     {
  542.         fl->fl_Key = flkey;
  543.         fl->fl_Access = axs;
  544.         fl->fl_Task = ourport;
  545.         fl->fl_Volume = MKBADDR(curdoslist);
  546.         fl->fl_Link = (BPTR)curvolumenode->locklist;
  547.         curvolumenode->locklist = fl;
  548.     }
  549.  
  550.     return(MKBADDR(fl));
  551. }
  552.  
  553. void freelock(struct FileLock *fl)
  554. {
  555.     struct VolumeNode *node;
  556.  
  557.     for(node=(struct VolumeNode*)volumelist.mlh_Head;
  558.         node->node.mln_Succ;
  559.         node=(struct VolumeNode*)(node->node.mln_Succ))
  560.     {
  561.         struct FileLock *cur,*last;
  562.  
  563.         for(cur=node->locklist, last=(struct FileLock*)&node->locklist;
  564.             cur;
  565.             last=cur, cur=(struct FileLock*)last->fl_Link)
  566.         {
  567.             if(cur == fl)
  568.             {
  569.                 last->fl_Link = cur->fl_Link;
  570.                 fl->fl_Task = NULL;
  571.                 FreeVec(fl);
  572.  
  573.                 if(!node->locklist && !node->volnode->dol_Task)
  574.                 {
  575.                     /* An unmounted volume does not have any locks open
  576.                        any more, so we can safely remove the volume node. */
  577.  
  578.                     while(!AttemptLockDosList(LDF_VOLUMES|LDF_WRITE))
  579.                         DoPackets();
  580.                     RemDosEntry((struct DosList*)node->volnode);
  581.                     Remove((struct Node*)node);
  582.                     FreeVec(node);
  583.                     UnLockDosList(LDF_VOLUMES|LDF_WRITE);
  584.                     SendEvent(FALSE);
  585.                 }
  586.  
  587.                 return;
  588.             }
  589.         }
  590.     }
  591. }
  592.  
  593. /* Is an object still lockable with the respective access mode? */
  594. BOOL lockable(UBYTE t, UBYTE s, LONG mode)
  595. {
  596.     struct FileLock *fl;
  597.     LONG searchkey = t<<8|s;
  598.  
  599.     for(fl=curvolumenode->locklist; fl; fl=(struct FileLock*)fl->fl_Link)
  600.     {
  601.         if(fl->fl_Key == searchkey)
  602.         {
  603.             if(mode == EXCLUSIVE_LOCK)
  604.                 return(FALSE);
  605.             else
  606.             {
  607.                 if(fl->fl_Access == EXCLUSIVE_LOCK)
  608.                     return(FALSE);
  609.             }
  610.         }
  611.     }
  612.  
  613.     return(TRUE);
  614. }
  615.  
  616.