/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1987 The Software Distillery.  All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of   */
/* | .  | || the authors:                                          BBS:      */
/* | o  | ||   John Toebes     Dave Baker                                    */
/* |  . |//                                                                  */
/* ======                                                                    */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Volume Manipulation */
/* mount */
#include "handler.h"

void DisMount(global)
GLOBAL global;
{
   struct DeviceList *volume;
   struct DosInfo *info;
   struct RootNode *root;

   BUG(("Dismount\n"));

   /* start at the root of the device list */
   root   = (struct RootNode   *)DOSBase->dl_Root;
   info   = (struct DosInfo    *)BADDR(root->rn_Info);
   volume = (struct DeviceList *)BADDR(info->di_DevInfo);

   /* Flush and purge all buffers */
   FlushBuffers(global, 1);

   /* Free bitmap storage for this disk */
   FreeBitMap(global);

   /* See if we have a current volume that we have to get rid of ? */
   /* Make sure there are no outstanding locks for the volume */
   if ((global->volume != NULL) && (global->volume->dl_Lock == NULL))
      {
      /* This volume needs to be removed from the list */
      /* First locate it on the list */
      Forbid();

      /* is it at the head of the list? */
      if (volume == global->volume)
         /* sure enough, just get rid of it */
         info->di_DevInfo = volume->dl_Next;
      else
         {
         /* Find it in the list */
         while(volume != NULL &&
               (struct DeviceList *)(BADDR(volume->dl_Next)) != global->volume)
            volume = (struct DeviceList *)BADDR(volume->dl_Next);

         /* if we found it then take it out of the chain */
         if (volume != NULL)
            volume->dl_Next = global->volume->dl_Next;
         }
      Permit();

      if (global->volume)
         {
         DosFreeMem((char *)global->volume);
         }
      }

   global->volume = NULL;
   global->diskstate  = ID_VALIDATING;
}

void Mount(global)
GLOBAL global;
{
   struct RootBlock *block;
   struct DeviceList *volume;
   struct DosInfo *info;
   struct RootNode *root;
   char *newname;
   short newlen; /* Cause memcmp to use the most efficient code */
   int rwflag;

   BUG(("Mount\n"));

   global->changedisk = 0;
   global->ErrorCount = 0;
   global->DiskChange = 0;
   rwflag = ResetDrive(global);

   DisMount(global);

   if (global->diskstatus == ID_NO_DISK_PRESENT)
      {
      /* If we don't have a disk, we might as well return */
      Motor(global, 0);
      return;
      }

   /* first see if anything is in the drive. */
   if ((block = (struct RootBlock *)GetBlock(global,0)) == NULL)
      {
      global->diskstatus = ID_UNREADABLE_DISK;
      global->diskstate  = ID_VALIDATING;
      return;
      }

   global->diskstatus = block->rb_Type;
   global->diskstate  = ID_VALIDATED;

   /* OK, something is there, hows about asking for more information on */
   /* the volume */
   if ((block = (struct RootBlock *)GetBlock(global,global->Root)) == NULL)
      return;

   /* Now make sure we have a valid block to write to */
   newname = (char *)(block->rb_Name);
   newlen = *newname + 1;

   /* Now find it on the device list. */
   /* First start at the root of the device list */
   root   = (struct RootNode   *)DOSBase->dl_Root;
   info   = (struct DosInfo    *)BADDR(root->rn_Info);
   volume = (struct DeviceList *)BADDR(info->di_DevInfo);

   BUGBSTR("Volume name is : ", newname);

   /* Can't let the system change the list underneath us...        */
   Forbid();
   
   /* Now run through the list until we come up empty OR we find it */
   while(volume != NULL)
      {
      if (volume->dl_Type == DLT_VOLUME                               &&
          !memcmp(newname, (char *)BADDR(volume->dl_Name), newlen)    &&
          volume->dl_VolumeDate.ds_Days   == block->rb_CreateDays     &&
          volume->dl_VolumeDate.ds_Minute == block->rb_CreateMinutes  &&
          volume->dl_VolumeDate.ds_Tick   == block->rb_CreateTicks)
         break;
      volume = (struct DeviceList *)BADDR(volume->dl_Next);
      }

   Permit();

   BUG(("mount: Volume is %08lx\n", volume));

   /* OK, now did we find it? */
   if (volume != NULL)
      {
      BUG(("Got a matching node\n"));

      /* Sure did, We probably need to check to see if another handler has */
      /* it to work with, but for now we assume only onw such volume can   */
      /* exist.  This was a problem with all but the latest version of 1.2 */
      /* If we have write access, we should probably nudge the ticks by one*/
      /* just to make it unique                                            */
      }
   else
      /* No such volume is known to the system.  So we will just have to   */
      /* allocate a node to put everything on.                             */
      {
      volume = (struct DeviceList *)
               DosAllocMem(global, sizeof(struct DeviceList)+newlen);

      BUG(("Created new node at %08lx\n", volume));

      /* Note that volume+1 gets us to the extra memory we allocated.  */
      /* Just a lot simpler to write that in C than ...+sizeof(...)    */
      memcpy((char *)(volume + 1), newname, newlen);
      volume->dl_VolumeDate.ds_Days   = block->rb_CreateDays;
      volume->dl_VolumeDate.ds_Minute = block->rb_CreateMinutes;
      volume->dl_VolumeDate.ds_Tick   = block->rb_CreateTicks;
      volume->dl_Name = (BSTR *)MKBADDR((volume + 1));
      volume->dl_Lock = NULL;
      volume->dl_Type = DLT_VOLUME;

      /* Also we need to link it into the list */
      Forbid();
      volume->dl_Next = info->di_DevInfo;
      info->di_DevInfo = MKBADDR(volume);
      Permit();
      }

   /* Now we can own the volume by giving it our task id */
   volume->dl_Task = global->port;
   volume->dl_DiskType = ID_DOS_DISK;
   global->diskstate = (rwflag) ? ID_WRITE_PROTECTED : ID_VALIDATED;

   /* all set up, remember what our base volume is */
   global->volume = volume;

   /* Initialize the bitmap */
   AllocBitMap(global);
}
