home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff350.lzh / TrackUtils / src / tfile.c < prev    next >
C/C++ Source or Header  |  1990-04-16  |  38KB  |  1,342 lines

  1. /*
  2.  * TFILE.C
  3.  *
  4.  * (C) Copyright Eddy Carroll, January 1990
  5.  *
  6.  * This is a little utility which simply creates a "fake" file on a disk,
  7.  * which makes AmigaDos think that all the blocks on a given range of
  8.  * tracks are in use. I.e. it allows you to reserve a section of the disk
  9.  * for your own messing around, without fear of AmigaDos stomping over you
  10.  * at some later stage.
  11.  *
  12.  * Usage: tfile <pathname> <start> <end>
  13.  *
  14.  * <pathname>   The full pathname of the filename AmigaDOS will think
  15.  *              the blocks are stored in. This also specifies the device
  16.  *              on which the blocks are to be reserved.
  17.  *
  18.  * <start>      The starting track to reserve blocks on.
  19.  *
  20.  * <end>        The ending track to reserve blocks on.
  21.  *
  22.  * For example, to reserve tracks 70 to 79 on the disk in DF0:, you might
  23.  * give the command:
  24.  *
  25.  *      tfile df0:devs/Tracks70-79 70 79
  26.  *
  27.  * which will create the file devs/Tracks70-79 on the disk in DF0: If you
  28.  * try and actually access this file, you will find it only contains a brief
  29.  * message -- this is a safeguard to stop AmigaDOS trying to make sense
  30.  * of whatever data is actually on tracks 70 to 79.
  31.  *
  32.  * Tfile is primarily intended for use with the companion program tcopy,
  33.  * which allows tracks from a small device such as RAD: to be stored on
  34.  * part of a larger device like a floppy disk, and then read back in at
  35.  * a later time (and at high speed).
  36.  *
  37.  *
  38.  *        Note: The following assumptions are hardwired into the code --
  39.  *
  40.  *                -- Long's are at least 32 bits long
  41.  *                -- Blocks are 512 bytes long
  42.  *                -- Either the old or fast filing system is in use
  43.  */
  44.  
  45. #define TRUE            1
  46. #define FALSE            0
  47. #define LASTCHAR(s)        (s[strlen(s)-1])
  48.  
  49. #ifndef LATTICE_50
  50. #include "system.h"
  51. #endif
  52.  
  53. #include "dosheaders.h"
  54.  
  55. #define MIN(x,y) ((x) < (y) ? (x) : (y))
  56.  
  57. extern struct DosLibrary       *DOSBase;
  58.  
  59. typedef struct IORequest       IOREQ;
  60. typedef struct MsgPort         MSGPORT;
  61. typedef struct Process         PROC;
  62. typedef struct StandardPacket  STDPKT;
  63.  
  64. void inhibit(MSGPORT *devport, int mode);    /* Called by cleanup() */
  65.  
  66.  
  67. /*
  68.  *        This is the message that gets stored in the dummy file when
  69.  *        the disk being written to is an OFS disk. Max 488 characters please.
  70.  */
  71. char FileMessage[] = "\
  72. This file was created using TFile (C) Copyright Eddy Carroll 1990.\n\n\
  73. TFile creates special files which don't contain data, but instead prevent\n\
  74. AmigaDOS from overwriting the information on some tracks on this disk.\n\n";
  75.  
  76.  
  77. /*
  78.  *        Structure representing a disk device
  79.  */
  80. typedef struct {
  81.     char  *devname;            /* Name of exec device for this disk    */
  82.     int   isfloppy;            /* True if device is trackdisk.device    */
  83.     int   isffs;            /* True if device is using FFS            */
  84.     int   isknown;            /* True if filesystem is known            */
  85.     ULONG unit;                /* Unit number of above exec device        */
  86.     ULONG blocksize;        /* Number of bytes per block            */
  87.     ULONG blockspertrack;    /* Number of blocks/sectors per track    */
  88.     ULONG surfaces;            /* Number of tracks per cylinder        */
  89.     ULONG lowcyl;            /* Starting cylinder of disk on device     */
  90.     ULONG numcyl;            /* Number of cylinders on this disk        */
  91.     ULONG numblocks;        /* Number of blocks on this disk        */
  92.     ULONG reserved;            /* Number of blocks reserved at start    */
  93.                             /* (included in numblocks count)        */
  94. } DISKDEV;
  95.  
  96. /*
  97.  *        Global variables
  98.  *        ----------------
  99.  */
  100.  
  101. BPTR    filehandle;                /* Filehandle used when creating dummy file    */
  102. BPTR    lock;                    /* Lock on dummy file used to store tracks    */
  103. LONG    filekey;                /* AmigaDOS block of dummy file header        */
  104. char    *pathname;                /* Full AmigaDOS path of file to create        */
  105. char    devname[300];            /* AmigaDOS device we are operating on        */
  106. DISKDEV    diskdev[1];                /* Description of disk device we are using    */
  107. struct    IOStdReq *req;            /* Standard request for source device        */
  108. MSGPORT    *reqport;                /* Message port for replies from disk dev.    */
  109. MSGPORT    *diskport;                /* Message port of process of disk device     */
  110. int        devopen;                /* True if disk exec device is open            */
  111. int        inhibited;                /* True if destination device is inhibited    */
  112. void     *readbuf;                /* Buffer to read a single disk block into    */
  113. void    *writebuf;                /* Buffer to write a single disk block from    */
  114. ULONG    *bitmap;                /* Array of longwords holding bitmap        */
  115. ULONG    *bitmapblocks;            /* Array of block numbers for disk bitmap    */
  116. ULONG    bitmapsize;                /* Size of bitmap in bytes                    */
  117. ULONG    bitmapblocksize;        /* Size of bitmap blocks array in bytes        */
  118. ULONG    numbitmapblocks;        /* Number of blocks storing bitmap on disk    */
  119. struct  FileHeaderBlock *headers;    /* Array of file headers/extensions        */
  120. struct    DataBlock        *datablock;    /* Datablock used if accessing OFS        */
  121. struct    RootBlock         *rootblock;    /* Rootblock of current disk            */
  122. ULONG    headersize;                /* Size of array of file headers in bytes    */
  123. ULONG    datasize;                /* Size of datablock in bytes                */
  124. ULONG    rootsize;                /* Size of rootblock in bytes                */
  125. ULONG    datablocknum;            /* Block # to store front data block at        */
  126.  
  127.  
  128. /*
  129.  *        print()
  130.  *        -------
  131.  *        Outputs a message to stdout
  132.  */
  133. void print(char *s)
  134. {
  135.     Write(Output(), s, strlen(s));
  136. }
  137. #define print2(s1,s2)    (print(s1),print(s2))
  138. #define print3(s1,s2,s3) (print(s1),print(s2),print(s3))
  139.  
  140. /*
  141.  *        numtostr()
  142.  *        ----------
  143.  *        Simple little function which returns a pointer to a static string
  144.  *        representation of the passed in number.
  145.  */
  146. char *numtostr(int n)
  147. {
  148.     static char s[20];
  149.     int i = 19;
  150.  
  151.     s[19] = '\0';
  152.     if (n)
  153.         while (n) {
  154.             s[--i] = '0' + (n % 10);
  155.             n /= 10;
  156.         }
  157.     else
  158.         s[--i] = '0';
  159.     return(&s[i]);
  160. }
  161.  
  162.  
  163. /*
  164.  *        cleanup()
  165.  *        ---------
  166.  *        Closes all opened resources, and exits with specified error code.
  167.  */
  168. void cleanup(int code)
  169. {
  170.     if (devopen) {
  171.         if (diskdev->isfloppy) {    /* Turn off drive motor if floppy disk */
  172.             req->io_Command = TD_MOTOR;
  173.             req->io_Length = 0;
  174.             DoIO(req);
  175.         }
  176.         CloseDevice((IOREQ *)req);
  177.     }
  178.     if (inhibited)
  179.         inhibit(diskport, FALSE);
  180.     if (readbuf)
  181.         FreeMem(readbuf, diskdev->blocksize);
  182.     if (writebuf)
  183.         FreeMem(writebuf, diskdev->blocksize);
  184.     if (req)
  185.         DeleteStdIO(req);
  186.     if (reqport)
  187.         DeletePort(reqport);
  188.     if (lock)
  189.         UnLock(lock);
  190.     if (filehandle)
  191.         Close(filehandle);
  192.     if (bitmap)
  193.         FreeMem(bitmap, bitmapsize);
  194.     if (bitmapblocks)
  195.         FreeMem(bitmapblocks, bitmapblocksize);
  196.     if (headers)
  197.         FreeMem(headers, headersize);
  198.     if (datablock)
  199.         FreeMem(datablock, datasize);
  200.     if (rootblock)
  201.         FreeMem(rootblock, rootsize);
  202.     exit(code);
  203. }
  204.  
  205.  
  206. /*
  207.  *        chkabort()
  208.  *        ----------
  209.  *        A replacement for Lattice's chkabort(), which doesn't carry all
  210.  *        the extra baggage. If CTRL-C is detected, this function never
  211.  *        returns but instead calls cleanup. Since Lattice's exit() code
  212.  *        may call chkabort(), a check is made to ensure that cleanup()
  213.  *        only gets called once, otherwise there would be a problem if the
  214.  *        user pressed Ctrl-C twice in quick succession.
  215.  */
  216. void chkabort(void)
  217. {
  218.     static int gotctrlc = FALSE;
  219.     if (!gotctrlc && (SetSignal(0,0) & SIGBREAKF_CTRL_C)) {
  220.         gotctrlc = TRUE;
  221.         print("^C\n");
  222.         cleanup(10);
  223.     }
  224. }
  225.  
  226.  
  227. /*
  228.  *        GetVolume()
  229.  *        -----------
  230.  *        This function searches the device list looking for a physical device
  231.  *        that currently contains the specified disk volume. When it finds it,
  232.  *        it fills in the DISKDEV structure with information about the physical
  233.  *        device which can then be used to access it at the block level.
  234.  */
  235. int GetVolume(char *devname, DISKDEV *dev)
  236. {
  237.     struct RootNode *rootnode;
  238.     struct DosInfo *dosinfo;
  239.     struct DeviceNode *devnode;
  240.     struct FileSysStartupMsg *startup;
  241.     struct DosEnvec *dosenvec;
  242.     unsigned char *p;
  243.     int namelen = strlen(devname);
  244.  
  245.     if (LASTCHAR(devname) != ':')    /* Device names must end with ':' */
  246.         return (FALSE);
  247.     /*
  248.      *        First of all, find the device
  249.      */
  250.     rootnode = (struct RootNode *)DOSBase->dl_Root;
  251.     dosinfo = (struct DosInfo *)BADDR(rootnode->rn_Info);
  252.     devnode = (struct DeviceNode *)BADDR(dosinfo->di_DevInfo);
  253.  
  254.     Forbid();    /* Make sure list doesn't change while we scan it */
  255.  
  256.     while (devnode != NULL) {
  257.         p = (unsigned char *)BADDR(devnode->dn_Name)+1;
  258.         if (!strnicmp(devname, p, namelen-1)) {    /* Don't compare the ':' */
  259.             /*
  260.              *        Matched name successfully. Now check if it's a device.
  261.              *        Note that we carry on searching if it's not a device
  262.              *        (rather than returning FALSE immediately) since there
  263.              *        may be a volume called RAD: as well as a device called
  264.              *        RAD:, for example.
  265.              */
  266.             if (devnode->dn_Type == DLT_DEVICE) {
  267.                 if (devnode->dn_Startup < 20)    /* Is there a startup bit?    */
  268.                     goto notfound;                /* If not, not disk device    */
  269.                     /* Eek! A GOTO! */
  270.  
  271.                 startup = (struct FileSysStartupMsg *)
  272.                                         BADDR(devnode->dn_Startup);
  273.  
  274.                 if (dev) {
  275.                     dev->devname = ((char *)BADDR(startup->fssm_Device))+1;
  276.                     dev->isfloppy = (!strcmp(TD_NAME, dev->devname));
  277.                     dev->unit = startup->fssm_Unit;
  278.                 }
  279.  
  280.                 if (startup->fssm_Environ < 20)
  281.                     goto notfound;
  282.                 /* Another GOTO! The world will end in 5 seconds... */
  283.  
  284.                 dosenvec = (struct DosEnvec *)BADDR(startup->fssm_Environ);
  285.  
  286.                 if (dev) {
  287.                     dev->isffs            = dosenvec->de_DosType == 0x444F5301;
  288.                     /*
  289.                      *        Since dosenvec->de_DosType does NOT equal
  290.                      *        0x444F5300 for standard OFS AmigaDOS disks,
  291.                      *        I can't check it to see if the filing system
  292.                      *        is "known". Hence, for now, just assume its
  293.                      *        always known (since it can currently only be
  294.                      *        OFS or FFS, and I can't think of any other way
  295.                      *        of checking).
  296.                      */
  297.                     dev->isknown        = 1;
  298.                     dev->blocksize        = dosenvec->de_SizeBlock << 2;
  299.                     dev->blockspertrack    = dosenvec->de_BlocksPerTrack;
  300.                     dev->surfaces        = dosenvec->de_Surfaces;
  301.                     dev->lowcyl            = dosenvec->de_LowCyl;
  302.                     dev->numcyl            = (dosenvec->de_HighCyl -
  303.                                                 dosenvec->de_LowCyl) + 1;
  304.                     dev->numblocks = dev->blockspertrack * dev->surfaces
  305.                                                           * dev->numcyl;
  306.                     dev->reserved = dosenvec->de_Reserved;
  307.                 }
  308.                 Permit();
  309.                 return (TRUE);
  310.             }
  311.         }
  312.         devnode = (struct DeviceNode *)BADDR(devnode->dn_Next);
  313.     }
  314. notfound:
  315.     Permit();
  316.     return (FALSE);
  317. }
  318.  
  319. /*
  320.  *        help()
  321.  *        ------
  322.  *        Prints out a help message about trackfile
  323.  */
  324. void help(void)
  325. {
  326.     print3(
  327. "Trackfile (C) Copyright Eddy Carroll, January 1990. Freely distributable.\n",
  328. "Creates an AmigaDos file which reserves specified tracks on a disk.\n\n",
  329. "Usage: tfile <pathname> <start> <end>\n\n"); print3(
  330. "  <pathname>  The full AmigaDOS path of the dummy file that will be \
  331. created\n",
  332. "              to hold the reserved tracks, to stop AmigaDOS using them.\n\n",
  333. "  <start>     The starting track to be reserved on the disk.\n\n" ); print(
  334. "  <end>       The ending track to be reserved on the disk.\n\n" );
  335. }
  336.  
  337.  
  338. /*
  339.  *        opendev()
  340.  *        ---------
  341.  *        Opens the disk device, allocates stdreqs etc. Two buffers are
  342.  *        also allocated, one for reading a single block and one for
  343.  *        writing a single block.
  344.  */
  345. void opendev(void)
  346. {
  347.     ULONG memflags = MEMF_PUBLIC;
  348.  
  349.     if (diskdev->isfloppy)
  350.         memflags |= MEMF_CHIP;
  351.  
  352.     reqport = (MSGPORT *)CreatePort(0,0);
  353.     if (!reqport) {
  354.         print("Couldn't allocate message port\n");
  355.         cleanup(10);
  356.     }
  357.  
  358.     readbuf = AllocMem(diskdev->blocksize, memflags);
  359.     if (!readbuf) {
  360.         print("Couldn't allocate memory for read buffer\n");
  361.         cleanup(10);
  362.     }
  363.  
  364.     writebuf = AllocMem(diskdev->blocksize, memflags);
  365.     if (!writebuf) {
  366.         print("Couldn't allocate memory for write buffer\n");
  367.         cleanup(10);
  368.     }
  369.  
  370.     req = CreateStdIO(reqport);
  371.     if (!req) {
  372.         print("Couldn't allocate IO request - memory is low!\n");
  373.         cleanup(10);
  374.     }
  375.  
  376.     if (OpenDevice(diskdev->devname, diskdev->unit, (IOREQ *)req, 0L)) {
  377.         print3("Can't open device ", diskdev->devname, "\n");
  378.         cleanup(10);
  379.     }
  380.     devopen = TRUE;
  381. }
  382.  
  383. /*
  384.  *        readblock()   &   writeblock()
  385.  *        -----------       ------------
  386.  *
  387.  *        These two functions read or write a block from the disk.
  388.  *        See the definition of transferblocks() below for more information.
  389.  */
  390. #define BLOCK_READ        0
  391. #define BLOCK_WRITE        1
  392.  
  393. #define readblock(buffer, s)  transferblocks(buffer, s, 1, BLOCK_READ)
  394. #define writeblock(buffer, s) transferblocks(buffer, s, 1, BLOCK_WRITE)
  395.  
  396. /*
  397.  *        transferblocks()
  398.  *        ----------------
  399.  *        Transfers n blocks to/from the disk into the buffer indicated,
  400.  *        starting at block s. Note that if you are using a floppy drive, the
  401.  *        buffer MUST be allocated in CHIP ram! You can ensure this by
  402.  *        including MEMF_CHIP in the flags to AllocMem() if diskdev->isfloppy
  403.  *        is true. Zero is returned if an error occurred, else non-zero.
  404.  *        Up to three retries are done before failure is accepted.
  405.  *
  406.  *        The direction of transfer is BLOCK_READ to read blocks in, or
  407.  *        BLOCK_WRITE to write blocks out.
  408.  */
  409. int transferblocks(void *buffer, int s, int n, int direction)
  410. {
  411.     int retry, parstart;
  412.  
  413.     /*
  414.      *        Because AmigaDOS works with partitions, Block 0 of an AmigaDOS
  415.      *        device may in fact be block 12345 of an exec device, depending
  416.      *        where the partition starts. Hence, before trying to access an
  417.      *        Amiga-DOS numbered block, we need to add in the block at which
  418.      *        the current partition starts.
  419.      */
  420.     parstart = diskdev->lowcyl * diskdev->blockspertrack * diskdev->surfaces;
  421.  
  422.     /*
  423.      *        Now read in blocks from disk
  424.      */
  425.     for (retry = 0; retry < 3; retry++) {
  426.         if (direction == BLOCK_READ)
  427.             req->io_Command = CMD_READ;
  428.         else
  429.             req->io_Command = CMD_WRITE;
  430.         req->io_Length  = diskdev->blocksize * n;
  431.         req->io_Offset  = diskdev->blocksize * (s + parstart);
  432.         req->io_Data    = buffer;
  433.         if (!DoIO((IOREQ *)req))
  434.             break;        /* Succeeded, so break out of loop */
  435.     }
  436.     if (retry == 3)
  437.         return (0);
  438.     else
  439.         return (1);
  440. }
  441.  
  442. /*
  443.  *        SendPacket()
  444.  *        ------------
  445.  *        ``Sort of'' simulates the ARP SendPacket() routine which sends
  446.  *        a packet to AmigaDos, and gets a reply if appropriate. What is
  447.  *        passed in is the action to be executed (one of the ACTION_xxx
  448.  *        definitions in dosextens.h), a pointer to a longword array of 7
  449.  *        arguments to be passed to the device, and the msgport of the device
  450.  *        as returned by DeviceProc("DF0:") for example. If result is non-NULL
  451.  *        then it should be a pointer to a two element array of ULONGs, and it
  452.  *        fills in the 0th element with the primary result, and the the
  453.  *        1st element with the secondary result.
  454.  */
  455. int SendPacket(ULONG action, void *args, MSGPORT *devport, ULONG *result)
  456. {
  457.     PROC *proc = (PROC *)FindTask(NULL);
  458.     STDPKT *packet;
  459.  
  460.     packet = (STDPKT *)AllocMem(sizeof(STDPKT), MEMF_CLEAR | MEMF_PUBLIC);
  461.     if (!packet)
  462.         return (FALSE);
  463.     packet->sp_Msg.mn_Node.ln_Name = (char *)&packet->sp_Pkt;
  464.     packet->sp_Pkt.dp_Link         = &packet->sp_Msg;
  465.     packet->sp_Pkt.dp_Port         = &proc->pr_MsgPort;
  466.     packet->sp_Pkt.dp_Type         = action;
  467.     memcpy(&packet->sp_Pkt.dp_Arg1, args, sizeof(ULONG) * 7);
  468.  
  469.     /*
  470.      *        Okay, we've done the necessary magic to create an AmigaDos
  471.      *        packet lookalike (thanks to Matt Dillon in Transactor V1.1).
  472.      *        Now we send the message to the Dos process, and get the reply.
  473.      *        Then our message will be filled in with the response from the
  474.      *        Dos process.
  475.      */
  476.     PutMsg(devport, (struct Message *)packet);
  477.     WaitPort(&proc->pr_MsgPort);
  478.     GetMsg(&proc->pr_MsgPort);
  479.     if (result) {
  480.         result[0] = packet->sp_Pkt.dp_Res1;
  481.         result[1] = packet->sp_Pkt.dp_Res2;
  482.     }
  483.     FreeMem(packet, sizeof(STDPKT));
  484.     return (TRUE);
  485. }
  486.  
  487.  
  488. /*
  489.  *        inhibit()
  490.  *        ---------
  491.  *        This function inhibits (if mode is TRUE) or uninhibits (if mode is
  492.  *        FALSE) the specified device.
  493.  */
  494. void inhibit(MSGPORT *devport, int mode)
  495. {
  496.     ULONG pktargs[7];
  497.     int i;
  498.  
  499.     pktargs[0] = mode;            /* Select inhibit or opposite */
  500.     for (i = 1; i < 7; i++)        /* Clear other arguments      */
  501.         pktargs[i] = 0;
  502.  
  503.     if (!SendPacket(ACTION_INHIBIT, pktargs, devport, NULL)) {
  504.         print("Couldn't send inhibit packet to device\n");
  505.         cleanup(10);
  506.     }
  507. }
  508.  
  509.  
  510. /*
  511.  *        flushdisk()
  512.  *        -----------
  513.  *        This function flushes the specified DOS device, ensuring that all
  514.  *        dirty buffers are written to disk and the bitmap is up to date.
  515.  */
  516. void flushdisk(MSGPORT *devport)
  517. {
  518.     ULONG pktargs[7];
  519.     int i;
  520.  
  521.     for (i = 0; i < 7; i++)        /* Clear arguments */
  522.         pktargs[i] = 0;
  523.  
  524.     if (!SendPacket(ACTION_FLUSH, pktargs, devport, NULL)) {
  525.         print("Couldn't send flush packet to device\n");
  526.         cleanup(10);
  527.     }
  528. }
  529.  
  530. /*
  531.  *        fixchecksum()
  532.  *        -------------
  533.  *        Calculates the checksum for the specified block, and stores it
  534.  *        in the indicated place, which will usually be a pointer into the
  535.  *        block itself. The block is assumed to be 512 bytes long.
  536.  */
  537. void fixchecksum(void *block, ULONG *checksum)
  538. {
  539.     ULONG *blk = block, *start, *end;
  540.     ULONG sum = 0;
  541.  
  542.     end = blk + 128;
  543.     *checksum = 0;            /* Clear checksum so it won't affect count */
  544.  
  545.     for (start = blk; start < end; start++)
  546.         sum += *start;
  547.  
  548.     *checksum = -sum;        /* Real checksum is complement of total */
  549. }
  550.  
  551. /*
  552.  *        readrootblock()
  553.  *        ---------------
  554.  *        This function simply reads in the root block of the disk into
  555.  *        the global 'root' structure for the rest of the program to access.
  556.  */
  557. void readrootblock(void)
  558. {
  559.     ULONG rootblocknum = diskdev->numblocks / 2;
  560.     ULONG memflags = MEMF_PUBLIC;
  561.  
  562.     if (diskdev->isfloppy)
  563.         memflags |= MEMF_CHIP;
  564.  
  565.     rootsize  = 512;
  566.     rootblock = AllocMem(rootsize, memflags);
  567.     if (!rootblock) {
  568.         print("Out of memory allocating space for root block\n");
  569.         cleanup(10);
  570.     }
  571.     if (!readblock(rootblock, rootblocknum)) {
  572.         print("Error reading root block from disk\n");
  573.         cleanup(10);
  574.     }
  575. }
  576.  
  577.  
  578. #ifdef DEBUG
  579. /*
  580.  *        writerootblock()
  581.  *        ----------------
  582.  *        This function writes the rootblock back to disk.
  583.  *        Temporarily, it zaps the "validated" flag to force a validation
  584.  *        to occur.
  585.  */
  586. void writerootblock(void)
  587. {
  588.     ULONG rootblocknum = diskdev->numblocks / 2;
  589.  
  590.     rootblock->BitmapFlag = 0;
  591.     fixchecksum(rootblock, &rootblock->Checksum);
  592.     writeblock(rootblock, rootblocknum);
  593. }
  594.  
  595. #endif
  596.  
  597.  
  598. /*
  599.  *        readbitmap()
  600.  *        ------------
  601.  *
  602.  *        This function creates a memory copy of the disks's bitmap, by
  603.  *        reading in all the disk's bitmap blocks. Two arrays are created;
  604.  *        The first holds the bitmap data itself, the second is a longword
  605.  *        array holding the block numbers that the bitmap is stored on, for
  606.  *        use when it is being written out again.
  607.  *
  608.  *        If an error occurs, the function prints a message and exits to dos.
  609.  *        It is assumed that the root block has been read in to 'root' before
  610.  *        calling this function.
  611.  */
  612. void readbitmap(void)
  613. {
  614.     int i, end;
  615.     ULONG nextblock;
  616.     ULONG *block = readbuf;
  617.  
  618.     /*
  619.      *        First let's calculate the size of each array. The size of the
  620.      *        bitmap array is simply the number of blocks on the disk divided
  621.      *        by 8 (since a single byte can represent 8 blocks). The size of
  622.      *        the array to hold the locations of the bitmap blocks is the
  623.      *        number of blocks divided by 4064, since each bitmap block
  624.      *        can represent 4064 disk blocks (with 32 bits left over for
  625.      *        the block checksum).
  626.      */
  627.  
  628.     /*
  629.      *        To calculate the number of DOS-usable blocks on the disk, we need
  630.      *        to subtract the number of blocks reserved at the start of the
  631.      *        partition. In addition, we add on 4063 so that the result after
  632.      *        division will be rounded up to the next integral block number.
  633.      */
  634.     numbitmapblocks = (diskdev->numblocks + 4063 - diskdev->reserved) / 4064;
  635.     bitmapsize        = numbitmapblocks * 508;   /* 4 bytes used for checksum */
  636.     bitmapblocksize    = numbitmapblocks * 4;
  637.  
  638.     /*
  639.      *        Now, allocate the arrays
  640.      */
  641.     bitmap = AllocMem(bitmapsize, 0L);
  642.     if (!bitmap) {
  643.         print("Can't allocate memory to store disk bitmap.\n");
  644.         cleanup(10);
  645.     }
  646.     bitmapblocks = AllocMem(bitmapblocksize, 0L);
  647.     if (!bitmapblocks) {
  648.         print("Can't allocate memory to store disk bitmap sector numbers.\n");
  649.         cleanup(10);
  650.     }
  651.  
  652.     /*
  653.      *        Now, read in all the sector numbers from the root block
  654.      */
  655.     end = MIN(numbitmapblocks, 25);
  656.     for (i = 0; i < end; i++)
  657.         bitmapblocks[i] = rootblock->BitmapKeys[i];
  658.  
  659.     /*
  660.      *        If we are using a large disk partition (larger than 52 Megs or so)
  661.      *        we also need to read in the bitmap extension block(s). Each
  662.      *        extension block contains 127 sector numbers.
  663.      *
  664.      *        Note: Since I am unsure of the extension bitmap format used,
  665.      *        this code is being commented out for now, and a check has been
  666.      *        included in main() to ensure no disk big enough to have an
  667.      *        bitmap extension is allowed to get here; when I find out the
  668.      *        format, it will be trivial to add support for it here, since the
  669.      *        rest of the program just deals with an array of bitmap sector
  670.      *        numbers (and the bitmap array itself of course).
  671.      *
  672.      *        For the code, I'm assuming the bitmap is stored back to front
  673.      *        (i.e. first sector last), based on Betty Clay's article in
  674.      *        Transactor. I want to verify this first though before letting
  675.      *        it loose on the unsuspecting public (after all, a bug that screws
  676.      *        up a 50 Mb disk is not going to go down well with people who
  677.      *        have 50 Mb disks... :-)
  678.      */
  679.  
  680.     nextblock = rootblock->BitmapExtend;
  681.  
  682. #ifdef FOUND_OUT_HOW_THE_BITMAP_IS_STORED
  683.  
  684.     while (i < numbitmapblocks) {
  685.         int p = 127;
  686.  
  687.         if (!readblock(block, nextblock)) {
  688.             print("Error reading bitmap extension block from disk\n");
  689.             cleanup(10);
  690.         }
  691.         nextblock = block[0];
  692.         end    = MIN(i + 127, numbitmapblocks);
  693.         while (i < end)
  694.             bitmapblocks[i++] = blocks[p--];
  695.     }
  696.  
  697. #endif
  698.  
  699.     /*
  700.      *        Now I know what sectors the bitmap itself is stored on, so
  701.      *        I can read it in to memory.
  702.      */
  703.     for (i = 0; i < numbitmapblocks; i++) {
  704.         if (!readblock(block, bitmapblocks[i])) {
  705.             print("Error reading in bitmap from disk\n");
  706.             cleanup(10);
  707.         }
  708.         /*
  709.          *        Remember, bitmap is pointer to ULONG so we use longword
  710.          *        offsets when copying the bitmap data into the bitmap array.
  711.          */
  712.         memcpy(bitmap + (127 * i), block + 1, 508);
  713.     }
  714. }
  715.  
  716. /*
  717.  *        writebitmap()
  718.  *        -------------
  719.  *        Writes the disk bitmap back to disk, storing it on the sectors
  720.  *        it was read in from earlier.
  721.  */
  722. void writebitmap(void)
  723. {
  724.     ULONG *diskblock = (ULONG *)writebuf;
  725.     int i;
  726.  
  727.     for (i = 0; i < numbitmapblocks; i++) {
  728.         /*
  729.          *        For each bitmap block, copy the 127 longwords into write
  730.          *        buffer, correct checksum, then write to disk.
  731.          */
  732.         memcpy(diskblock + 1, bitmap + (i * 127), 508);
  733.         fixchecksum(diskblock, &diskblock[0]);
  734.         if (!writeblock(diskblock, bitmapblocks[i])) {
  735.             print(
  736. "Error writing updated bitmap to disk! Copy important files to a new disk!\n");
  737.             cleanup(10);
  738.         }
  739.     }
  740. }
  741.  
  742. #ifdef DEBUG
  743. /*
  744.  *        dumpbitmap()
  745.  *        ------------
  746.  *        A quick hack function to display the bitmap on screen, to allow
  747.  *        visual confirmation that it was read in correctly, altered
  748.  *        properly etc.
  749.  */
  750. void dumpbitmap(void)
  751. {
  752.     int t, s, c, blocknum, i;
  753.     static char buf[300];
  754.  
  755.     for (c = 0; c < diskdev->numcyl; c++) {
  756.         for (t = 0; t < diskdev->surfaces; t++) {
  757.  
  758.             blocknum = (((c * diskdev->surfaces) + t)
  759.                         * diskdev->blockspertrack);
  760.             chkabort();
  761.             print3(numtostr(c),",",numtostr(t));
  762.             print3(": ",numtostr(blocknum),";  ");
  763.             i = 0;
  764.             for (s = 0; s < diskdev->blockspertrack; s++) {
  765.                 blocknum = (((c * diskdev->surfaces) + t)
  766.                             * diskdev->blockspertrack) + s;
  767.                 if (blocknum < diskdev->reserved ||
  768.                         blocknum >= diskdev->numblocks)
  769.                     buf[i++] = 'O';    /* Block reserved */
  770.                 else {
  771.                     blocknum = blocknum - diskdev->reserved;
  772.                     if (bitmap[blocknum >> 5] & (1 << (blocknum & 31)))
  773.                         buf[i++] = '-';    /* Block unused */
  774.                     else
  775.                         buf[i++] = 'O';    /* Block in use    */
  776.                 }
  777.             }
  778.             buf[i] = '\0';
  779.             print2(buf, "\n");
  780.         }
  781.     }
  782. }
  783. #endif
  784.  
  785. /*
  786.  *        filltracks()
  787.  *        ------------
  788.  *        Tries to mark the specified cylinders as used in the memory copy
  789.  *        of the disk bitmap. 1 is returned if successful, 0 if any of the
  790.  *        blocks in the cylinders were already in use.
  791.  */
  792. int filltracks(int lowcyl, int highcyl)
  793. {
  794.     long startblock, endblock;                /* Adjusted block numbers        */
  795.     long startblockindex, endblockindex;    /* Indexes into bitmap array    */
  796.     long startoffset, endoffset;            /* Bit offsets into bitmap word    */
  797.     long lastblock;                            /* Last bitmap block on disk    */
  798.     int i, warn = 0;
  799.  
  800.     lastblock = diskdev->numblocks - diskdev->reserved;
  801.  
  802.     startblock = lowcyl * diskdev->surfaces * diskdev->blockspertrack
  803.                         - diskdev->reserved;
  804.     if (startblock < 0) {
  805.         warn = 1;
  806.         startblock = 0;
  807.     }
  808.     if (startblock >= lastblock) {
  809.         warn = 1;
  810.         startblock = lastblock;
  811.     }
  812.     startblockindex = startblock >> 5;
  813.     startoffset        = startblock & 31;
  814.  
  815.     endblock   = (highcyl + 1) * diskdev->surfaces * diskdev->blockspertrack
  816.                          - diskdev->reserved;
  817.     if (endblock < 0) {
  818.         warn = 1;
  819.         endblock = 0;
  820.     }
  821.     if (endblock > lastblock) {
  822.         warn = 1;
  823.         endblock = lastblock;
  824.     }
  825.     endblockindex = endblock   >> 5;
  826.     endoffset      = endblock   & 31;
  827.  
  828.     if (warn)
  829.         print("(Warning: Track range includes reserved portion of disk.)\n");
  830.     
  831.     if (startblockindex == endblockindex) {
  832.         /*
  833.          *        Start and stop in same bitmap word, so set the bits manually
  834.          */
  835.         for (i = startoffset; i < endoffset; i++) {
  836.             if ((bitmap[startblockindex] & (1 << i)) == 0)
  837.                 return (0);                        /* Block already in use */
  838.             else
  839.                 bitmap[startblockindex] &= ~(1 << i); /* Clear bit in bitmap */
  840.         }
  841.         return (1);
  842.     }
  843.  
  844.     /*
  845.      *        Allocate first few blocks a bit at a time up to end of longword
  846.      */
  847.     for (i = startoffset; i < 32; i++) {
  848.         if ((bitmap[startblockindex] & (1 << i)) == 0)
  849.             return (0);                            /* Block already in use */
  850.         else
  851.             bitmap[startblockindex] &= ~(1 << i);    /* Clear bit in bitmap    */
  852.     }
  853.  
  854.     /*
  855.      *        Now allocate inbetween blocks a longword at a time for speed
  856.      */
  857.     for (i = startblockindex + 1; i < endblockindex; i++) {
  858.         if (bitmap[i] != 0xffffffff)
  859.             return (0);                            /* Block already in use    */
  860.         else
  861.             bitmap[i] = 0;                        /* Set all blocks used    */
  862.     }
  863.  
  864.     /*
  865.      *        Finally, allocate last few blocks a bit at a time
  866.      */
  867.     for (i = 0; i < endoffset; i++) {
  868.         if ((bitmap[endblockindex] & (1 << i)) == 0)
  869.             return (0);                            /* Block already in use */
  870.         else
  871.             bitmap[endblockindex] &= ~(1 << i);        /* Clear bit in bitmap    */
  872.     }
  873.     return (1);
  874. }
  875.  
  876. /*
  877.  *        allocblock()
  878.  *        ------------
  879.  *        Tries to allocate a block as close to block `key' as possible,
  880.  *        from the remaining free blocks in the disk bitmap. The allocation
  881.  *        algorithm is as follows:
  882.  *
  883.  *            - Find the nearest free block before the key
  884.  *            - Find the nearest free block after the key
  885.  *            - Allocate whichever one is closest
  886.  *
  887.  *        If the allocation was successful, the number of the new block is
  888.  *        stored in newkey.
  889.  */
  890. int allocblock(ULONG key, ULONG *newkey)
  891. {
  892.     ULONG curblock  = key - diskdev->reserved;
  893.     ULONG endblock  = diskdev->numblocks - diskdev->reserved;
  894.     ULONG endindex  = endblock >> 5;
  895.     ULONG useblock;
  896.     long  i, j, tp;                        /* Must be signed */
  897.     long  curindex  = curblock >> 5;
  898.     long  curoffset = curblock & 31;
  899.     int   backblock = -1, forblock = -1;
  900.  
  901.     /*
  902.      *        Find nearest block before current key. Remember that in the
  903.      *        bitmap, a `1' means the block is free, a `0' means its allocated.
  904.      *
  905.      *        First of all, search back within current bitmap word
  906.      */
  907.     tp = bitmap[curindex];
  908.     for (i = curoffset; i >= 0; i--) {
  909.         if (tp & (1 << i)) {
  910.             backblock = (curindex << 5) + i;
  911.             break;
  912.         }
  913.     }
  914.  
  915.     if (backblock < 0) {
  916.         /*
  917.          *        Didn't find room in initial word, so carry on search
  918.          */
  919.         for (i = curindex - 1; i >= 0; i--) {
  920.             if (bitmap[i] != 0) {
  921.                 tp = bitmap[i];
  922.                 /*
  923.                  *        Found free block word; now find what bit it is;
  924.                  *        Note that because of the way we entered this
  925.                  *        loop (with tp != 0), termination of the next
  926.                  *        loop is guaranteed.
  927.                  */
  928.                 for (j = 31; (tp & (1 << j)) == 0; j--)
  929.                     ;
  930.                 backblock = (i << 5) + j;
  931.                 break;
  932.             }
  933.         }
  934.     }
  935.  
  936.     /*
  937.      *        Now find nearest block after current key
  938.      */
  939.     tp = bitmap[curindex];
  940.     for (i = curoffset; i < 32; i++) {
  941.         if (tp & (1 << i)) {
  942.             forblock = (curindex << 5) + i;
  943.             break;
  944.         }
  945.     }
  946.  
  947.     if (forblock < 0) {
  948.         /*
  949.          *        Didn't find room in initial word, so carry on search
  950.          */
  951.         for (i = curindex + 1; i <= endindex; i--) {
  952.             if (bitmap[i] != 0) {
  953.                 tp = bitmap[i];
  954.                 /*
  955.                  *        Found free room; now find what bit it is;
  956.                  *        Note that because of the way we entered this
  957.                  *        loop (with tp != 0), termination of the next
  958.                  *        loop is guaranteed.
  959.                  */
  960.                 for (j = 0; (tp & (1 << j)) == 0; j++)
  961.                     ;
  962.                 forblock = (i << 5) + j;
  963.                 break;
  964.             }
  965.         }
  966.     }
  967.  
  968.     /*
  969.      *        Now, forblock and backblock hold block numbers which are free
  970.      *        in the bitmap (or -1 if none was found). We just have to
  971.      *        work out which one to use.
  972.      */
  973.     if (forblock < 0) {
  974.         if (backblock < 0)
  975.             return (0);
  976.         else
  977.             useblock = backblock;    
  978.     } else {
  979.         if (backblock < 0)
  980.             useblock = forblock;
  981.         else {
  982.             if ((key - backblock) < (forblock - key))
  983.                 useblock = backblock;
  984.             else
  985.                 useblock = forblock;
  986.         }
  987.     }
  988.  
  989.     /*
  990.      *        At this stage, useblock is the block number to allocate and
  991.      *        return.
  992.      */
  993.     bitmap[useblock >> 5] &= ~(1 << (useblock & 31));
  994.     *newkey = useblock + diskdev->reserved;
  995.     /*
  996.      *        Finally, a brief sanity check to ensure the number is in range
  997.      *        It SHOULD be but it doesn't do any harm to check, in case we
  998.      *        ran off the end of the bitmap or something...
  999.      */
  1000.     if (*newkey < diskdev->numblocks)
  1001.         return (1);
  1002.     else
  1003.         return (0);
  1004. }
  1005.  
  1006.  
  1007. /*
  1008.  *        createfileheaders()
  1009.  *        -------------------
  1010.  *        Allocates an array of file headers and extension blocks, and
  1011.  *        fills them in with the appropriate values to make AmigaDOS think
  1012.  *        a file exists on the tracks the user indictated. The key is
  1013.  *        the block number of the file header which is to be modified to
  1014.  *        hold the dummy file.
  1015.  *
  1016.  *        As well as allocating the blocks on the tracks to be reserved,
  1017.  *        an additional `frontend' data block is stuck at the front of the
  1018.  *        file containing a brief message. This stops DOS from getting
  1019.  *        confused if the user tries to access the file. Under the FFS it
  1020.  *        isn't needed, but under the OFS, a series crash results. To stop
  1021.  *        the code getting overly complicated, the FFS gets it too.
  1022.  *
  1023.  *        After the headers have been initialised, they are written back to
  1024.  *        the disk and hey presto, a new file is born :-)
  1025.  */
  1026. void createfileheaders(int key, int lowcyl, int highcyl)
  1027. {
  1028.     static char msgbuf[488];
  1029.     ULONG lastblock, startblock, endblock, numblocks, filesize;
  1030.     ULONG curblock;
  1031.     ULONG memflags = MEMF_PUBLIC | MEMF_CLEAR;
  1032.     int i, j, numheaders;
  1033.  
  1034.     lastblock = diskdev->numblocks;
  1035.  
  1036.     startblock = lowcyl * diskdev->surfaces * diskdev->blockspertrack;
  1037.     if (startblock < diskdev->reserved)
  1038.         startblock = diskdev->reserved;
  1039.  
  1040.     endblock   = (highcyl + 1) * diskdev->surfaces * diskdev->blockspertrack;
  1041.     if (endblock > lastblock)
  1042.         endblock = lastblock;
  1043.  
  1044.     numblocks = 1 + endblock - startblock;    /* 1 extra for front data block */
  1045.  
  1046.     /*
  1047.      *        Now, we know how many blocks the file will have (we've been
  1048.      *        careful not to count blocks which are reserved at the start
  1049.      *        or end of the partition). Next, let's calculate how many
  1050.      *        bytes our pretend file will have. This depends on whether
  1051.      *        the filing system is OFS or FFS.
  1052.      */
  1053.     if (diskdev->isffs)
  1054.         filesize = numblocks * 512;
  1055.     else
  1056.         filesize = numblocks * 488;
  1057.  
  1058.     /*
  1059.      *        Now allocate the file header/extensions to hold the file.
  1060.      *        Each header/extension holds 72 block keys.
  1061.      */
  1062.     numheaders = (numblocks + 71) / 72;
  1063.     headersize = numheaders * 512;
  1064.  
  1065.     if (diskdev->isfloppy)
  1066.         memflags |= MEMF_CHIP;
  1067.  
  1068.     headers = AllocMem(headersize, memflags);
  1069.     if (!headers) {
  1070.         print("Error allocating memory for file header/extension blocks\n");
  1071.         cleanup(10);
  1072.     }
  1073.     /*
  1074.      *        Read in file header block, for file to be modified.
  1075.      */
  1076.     if (!readblock(headers, key)) {
  1077.         print("Error reading file header block from disk\n");
  1078.         cleanup(10);
  1079.     }
  1080.     /*
  1081.      *        Now fill in the details for all the file extension blocks.
  1082.      */        
  1083.  
  1084.     curblock = startblock - 1;    /* Adjust to allow for front data block    */
  1085.  
  1086.     for (i = 0; i < numheaders; i++) {
  1087.         int end = MIN(72, endblock - curblock);
  1088.  
  1089.         for (j = 0; j < end; j++)
  1090.             headers[i].DataBlocks[71-j] = curblock++;
  1091.     }
  1092.  
  1093.     for (i = 1; i < numheaders; i++) {
  1094.  
  1095.         headers[i].Type = Type_List;
  1096.         headers[i].SecondaryType = SecType_File;
  1097.         if (!allocblock(headers[i-1].OwnKey, &headers[i].OwnKey)) {
  1098.             print("Not enough room on disk to store dummy file.\n");
  1099.             cleanup(10);
  1100.         }
  1101.         headers[i-1].Extension    = headers[i].OwnKey;
  1102.         headers[i].HighSeq        = 72;
  1103.         headers[i].DataSize        = 72;
  1104.         headers[i].Parent        = key;
  1105.     }
  1106.     headers[numheaders-1].Extension  = 0;
  1107.     headers[numheaders-1].HighSeq     = numblocks % 72;
  1108.     headers[numheaders-1].DataSize     = numblocks % 72;
  1109.  
  1110.     headers[0].FileSize      = filesize;
  1111.     headers[0].HighSeq    = numblocks;
  1112.  
  1113.     /*
  1114.      *        Now, allocate and save the dummy data block containing the
  1115.      *        brief message. Under the FFS, users can actually access the
  1116.      *        raw track data by seeking to (offset + 512), where offset is
  1117.      *        the desired byte offset from the first reserved cylinder.
  1118.      */
  1119.     datasize  = 512;
  1120.     datablock = AllocMem(datasize, memflags);
  1121.     if (!datablock) {
  1122.         print("Out of memory allocating temporary disk data block.\n");
  1123.         cleanup(10);
  1124.     }
  1125.     if (!allocblock(key, &datablocknum)) {
  1126.         print("Not enough room on disk to store dummy file.\n");
  1127.         cleanup(10);
  1128.     }
  1129.     /*
  1130.      *        Now generate message containing track data.
  1131.      */
  1132.     strcpy(msgbuf, FileMessage);
  1133.     if (lowcyl == highcyl) {
  1134.         strcat(msgbuf, "This file contains disk track ");
  1135.         strcat(msgbuf, numtostr(lowcyl));
  1136.     } else {
  1137.         strcat(msgbuf, "This file contains disk tracks ");
  1138.         strcat(msgbuf, numtostr(lowcyl));
  1139.         strcat(msgbuf, " to ");
  1140.         strcat(msgbuf, numtostr(highcyl));
  1141.     }
  1142.     strcat(msgbuf, "\n\n");
  1143.  
  1144.     if (diskdev->isffs) {
  1145.         /*
  1146.          *        For FFS, just put raw data into block.
  1147.          */
  1148.         strcpy((char *)datablock, msgbuf);
  1149.     } else {
  1150.         /*
  1151.          *        For OFS, fill in appropriate header details
  1152.          */
  1153.         datablock->Header    = key;
  1154.         datablock->Type        = Type_Data;
  1155.         datablock->SeqNum    = 1;
  1156.         datablock->NextData    = 0;
  1157.         datablock->DataSize = strlen(msgbuf);
  1158.         strcpy((char *)datablock->Data, msgbuf);
  1159.  
  1160.         fixchecksum(datablock, &datablock->Checksum);
  1161.     }
  1162.  
  1163.     if (!writeblock(datablock, datablocknum)) {
  1164.         print("Error writing file data block to disk\n");
  1165.         cleanup(10);
  1166.     }
  1167.  
  1168.     /*
  1169.      *        Now fix up datablock pointers in file header
  1170.      */
  1171.     headers[0].FirstBlock      = datablocknum;
  1172.     headers[0].DataBlocks[71] = datablocknum;
  1173.  
  1174.     /*
  1175.      *        All the data blocks have been allocated correctly; now
  1176.      *        fix up the data checksums for each block. When the checksum
  1177.      *        is correct, all the longwords in the block will add up to zero
  1178.      *        (no carry when overflow occurs).
  1179.      */
  1180.     for (i = 0; i < numheaders; i++)
  1181.         fixchecksum(&headers[i], &headers[i].Checksum);
  1182.  
  1183.     /*
  1184.      *        Finally, write all the file blocks back to disk. Note that
  1185.      *        they are written back to disk in reverse order. This way, the
  1186.      *        file header itself is the last thing to get written, so if an
  1187.      *        error occurs before hand, it won't be left in an inconsistent
  1188.      *        state.
  1189.      */
  1190.     chkabort();                        /* Give user a final chance to abort */
  1191.     for (i = numheaders - 1; i >= 0; i--) {
  1192.         if (!writeblock(&headers[i], headers[i].OwnKey)) {
  1193.             print("Error writing file headers to disk\n");
  1194.             cleanup(10);
  1195.         }
  1196.     }
  1197. }
  1198.  
  1199.  
  1200. /*
  1201.  *        mainline()
  1202.  *        ----------
  1203.  */
  1204. void main(argc,argv)
  1205. int argc;
  1206. char **argv;
  1207. {
  1208.     unsigned int start, end;            /* Cylinder numbers */
  1209.     char *p;
  1210.  
  1211. #define NONUM(x) (!isdigit(argv[x][0]))
  1212.  
  1213.     if (argc != 4 || NONUM(2) || NONUM(3)) {
  1214.         help();
  1215.         cleanup(10);
  1216.     }
  1217.  
  1218.     /*
  1219.      *        Strip off trailing dir and filenames to get device name
  1220.      */
  1221.     pathname = argv[1];
  1222.     strcpy(devname, pathname);
  1223.  
  1224.     for (p = devname; *p && *p != ':'; p++)
  1225.         ;
  1226.     if (*p != ':') {
  1227.         print("The pathname must include both a device and a filename.\n");
  1228.         cleanup(10);
  1229.     }
  1230.     p++;            /* Skip over colon at end of device name */
  1231.     *p = '\0';
  1232.  
  1233.     if (strlen(pathname) <= strlen(devname)) {
  1234.         print("The pathname must include both a device and a filename.\n");
  1235.         cleanup(10);
  1236.     }
  1237.     start = atoi(argv[2]);
  1238.     end   = atoi(argv[3]);
  1239.  
  1240.     if (!GetVolume(devname, diskdev)) {
  1241.         print2(devname, " is not a valid disk device\n");
  1242.         cleanup(10);
  1243.     }
  1244.  
  1245.     if (start > end) {
  1246.         print("Start track is greater than end track.\n");
  1247.         cleanup(10);
  1248.     }
  1249.  
  1250.     if (end >= diskdev->numcyl) {
  1251.         print3("Maximum end track on ", devname, " is ");
  1252.         print2(numtostr(diskdev->numcyl - 1), ".\n");
  1253.         cleanup(10);
  1254.     }
  1255.  
  1256.     if (!diskdev->isknown) {
  1257.         print(
  1258. "Sorry, only Old Filing System and Fast Filing System are supported.\n");
  1259.         cleanup(10);
  1260.     }
  1261.  
  1262.     if (diskdev->blocksize != 512) {
  1263.         print(
  1264. "Sorry, only devices with 512 byte blocks can be handled at present.\n");
  1265.         cleanup(10);
  1266.     }
  1267.  
  1268.     if (diskdev->numblocks > (25 * 4064)) {
  1269.         print("Sorry, this version doesn't support drives > 50 Mb\n");
  1270.         cleanup(10);
  1271.     }
  1272.  
  1273.     diskport = (MSGPORT *)DeviceProc(devname);
  1274.     if (!diskport) {
  1275.         print3("Can't locate process for device ", devname, "\n");
  1276.         cleanup(10);
  1277.     }
  1278.  
  1279.     /*
  1280.      *        Everything seems in order, so lets try and create the dummy file.
  1281.      *        After creating it, we flush the disk buffers etc. to ensure that
  1282.      *        the disk bitmap is current.
  1283.      */
  1284.     filehandle = Open(pathname, MODE_NEWFILE);
  1285.     if (!filehandle) {
  1286.         print3("Couldn't open file ", pathname, ".\n");
  1287.         cleanup(10);
  1288.     }
  1289.     Close(filehandle); filehandle = NULL;
  1290.     lock = Lock(pathname, ACCESS_READ);
  1291.     if (!lock) {
  1292.         print3("Strangely, file ", pathname, " can no longer be accessed.\n");
  1293.         cleanup(314);    /* pi -- let's be weird */
  1294.     }
  1295.     filekey = ((struct FileLock *)BTOC(lock))->fl_Key;
  1296.     flushdisk(diskport);
  1297.  
  1298.     /*
  1299.      *        Assuming everthing is still okay, the next step is to read in
  1300.      *        the root block and do some checks to make sure we can do the
  1301.      *        allocation.
  1302.      */
  1303.     opendev();
  1304.     inhibit(diskport, TRUE);
  1305.     inhibited = TRUE;
  1306.     readrootblock();
  1307.     if (rootblock->BitmapFlag != -1) {
  1308.         print3("tfile: Bitmap for ", devname, " is not up to date.\n");
  1309.         cleanup(10);
  1310.     }
  1311.  
  1312.     /*
  1313.      *        Read in bitmap, and mark all the blocks on the desired tracks
  1314.      *        as in-use. If any of these blocks are already in use, then
  1315.      *        abort with an error.
  1316.      */
  1317.     readbitmap();
  1318.     if (!filltracks(start, end)) {
  1319.         print3("Tracks ",numtostr(start)," to ");
  1320.         print2(numtostr(end)," contain AmigaDOS data.\n");
  1321.         cleanup(10);
  1322.     }
  1323.  
  1324.     /*
  1325.      *        Now allocate file header blocks to store the AmigaDOS pointers
  1326.      *        to each block in the reserved tracks in. The memory copy of
  1327.      *        the bitmap is modified to reflect these additional blocks.
  1328.      *        Then the new blocks are written back to disk, and the
  1329.      *        file header of the existing file is updated to reflect the
  1330.      *        additional data blocks.
  1331.      */
  1332.     createfileheaders(filekey,start,end);
  1333.  
  1334.     /*
  1335.      *        Everything is now complete, so all that remains to be done
  1336.      *        is to write back the new bitmap, update the root block and
  1337.      *        exit.
  1338.      */
  1339.     writebitmap();
  1340.     cleanup(0);
  1341. }
  1342.