home *** CD-ROM | disk | FTP | other *** search
- /*
- * TFILE.C
- *
- * (C) Copyright Eddy Carroll, January 1990
- *
- * This is a little utility which simply creates a "fake" file on a disk,
- * which makes AmigaDos think that all the blocks on a given range of
- * tracks are in use. I.e. it allows you to reserve a section of the disk
- * for your own messing around, without fear of AmigaDos stomping over you
- * at some later stage.
- *
- * Usage: tfile <pathname> <start> <end>
- *
- * <pathname> The full pathname of the filename AmigaDOS will think
- * the blocks are stored in. This also specifies the device
- * on which the blocks are to be reserved.
- *
- * <start> The starting track to reserve blocks on.
- *
- * <end> The ending track to reserve blocks on.
- *
- * For example, to reserve tracks 70 to 79 on the disk in DF0:, you might
- * give the command:
- *
- * tfile df0:devs/Tracks70-79 70 79
- *
- * which will create the file devs/Tracks70-79 on the disk in DF0: If you
- * try and actually access this file, you will find it only contains a brief
- * message -- this is a safeguard to stop AmigaDOS trying to make sense
- * of whatever data is actually on tracks 70 to 79.
- *
- * Tfile is primarily intended for use with the companion program tcopy,
- * which allows tracks from a small device such as RAD: to be stored on
- * part of a larger device like a floppy disk, and then read back in at
- * a later time (and at high speed).
- *
- *
- * Note: The following assumptions are hardwired into the code --
- *
- * -- Long's are at least 32 bits long
- * -- Blocks are 512 bytes long
- * -- Either the old or fast filing system is in use
- */
-
- #define TRUE 1
- #define FALSE 0
- #define LASTCHAR(s) (s[strlen(s)-1])
-
- #ifndef LATTICE_50
- #include "system.h"
- #endif
-
- #include "dosheaders.h"
-
- #define MIN(x,y) ((x) < (y) ? (x) : (y))
-
- extern struct DosLibrary *DOSBase;
-
- typedef struct IORequest IOREQ;
- typedef struct MsgPort MSGPORT;
- typedef struct Process PROC;
- typedef struct StandardPacket STDPKT;
-
- void inhibit(MSGPORT *devport, int mode); /* Called by cleanup() */
-
-
- /*
- * This is the message that gets stored in the dummy file when
- * the disk being written to is an OFS disk. Max 488 characters please.
- */
- char FileMessage[] = "\
- This file was created using TFile (C) Copyright Eddy Carroll 1990.\n\n\
- TFile creates special files which don't contain data, but instead prevent\n\
- AmigaDOS from overwriting the information on some tracks on this disk.\n\n";
-
-
- /*
- * Structure representing a disk device
- */
- typedef struct {
- char *devname; /* Name of exec device for this disk */
- int isfloppy; /* True if device is trackdisk.device */
- int isffs; /* True if device is using FFS */
- int isknown; /* True if filesystem is known */
- ULONG unit; /* Unit number of above exec device */
- ULONG blocksize; /* Number of bytes per block */
- ULONG blockspertrack; /* Number of blocks/sectors per track */
- ULONG surfaces; /* Number of tracks per cylinder */
- ULONG lowcyl; /* Starting cylinder of disk on device */
- ULONG numcyl; /* Number of cylinders on this disk */
- ULONG numblocks; /* Number of blocks on this disk */
- ULONG reserved; /* Number of blocks reserved at start */
- /* (included in numblocks count) */
- } DISKDEV;
-
- /*
- * Global variables
- * ----------------
- */
-
- BPTR filehandle; /* Filehandle used when creating dummy file */
- BPTR lock; /* Lock on dummy file used to store tracks */
- LONG filekey; /* AmigaDOS block of dummy file header */
- char *pathname; /* Full AmigaDOS path of file to create */
- char devname[300]; /* AmigaDOS device we are operating on */
- DISKDEV diskdev[1]; /* Description of disk device we are using */
- struct IOStdReq *req; /* Standard request for source device */
- MSGPORT *reqport; /* Message port for replies from disk dev. */
- MSGPORT *diskport; /* Message port of process of disk device */
- int devopen; /* True if disk exec device is open */
- int inhibited; /* True if destination device is inhibited */
- void *readbuf; /* Buffer to read a single disk block into */
- void *writebuf; /* Buffer to write a single disk block from */
- ULONG *bitmap; /* Array of longwords holding bitmap */
- ULONG *bitmapblocks; /* Array of block numbers for disk bitmap */
- ULONG bitmapsize; /* Size of bitmap in bytes */
- ULONG bitmapblocksize; /* Size of bitmap blocks array in bytes */
- ULONG numbitmapblocks; /* Number of blocks storing bitmap on disk */
- struct FileHeaderBlock *headers; /* Array of file headers/extensions */
- struct DataBlock *datablock; /* Datablock used if accessing OFS */
- struct RootBlock *rootblock; /* Rootblock of current disk */
- ULONG headersize; /* Size of array of file headers in bytes */
- ULONG datasize; /* Size of datablock in bytes */
- ULONG rootsize; /* Size of rootblock in bytes */
- ULONG datablocknum; /* Block # to store front data block at */
-
-
- /*
- * print()
- * -------
- * Outputs a message to stdout
- */
- void print(char *s)
- {
- Write(Output(), s, strlen(s));
- }
- #define print2(s1,s2) (print(s1),print(s2))
- #define print3(s1,s2,s3) (print(s1),print(s2),print(s3))
-
- /*
- * numtostr()
- * ----------
- * Simple little function which returns a pointer to a static string
- * representation of the passed in number.
- */
- char *numtostr(int n)
- {
- static char s[20];
- int i = 19;
-
- s[19] = '\0';
- if (n)
- while (n) {
- s[--i] = '0' + (n % 10);
- n /= 10;
- }
- else
- s[--i] = '0';
- return(&s[i]);
- }
-
-
- /*
- * cleanup()
- * ---------
- * Closes all opened resources, and exits with specified error code.
- */
- void cleanup(int code)
- {
- if (devopen) {
- if (diskdev->isfloppy) { /* Turn off drive motor if floppy disk */
- req->io_Command = TD_MOTOR;
- req->io_Length = 0;
- DoIO(req);
- }
- CloseDevice((IOREQ *)req);
- }
- if (inhibited)
- inhibit(diskport, FALSE);
- if (readbuf)
- FreeMem(readbuf, diskdev->blocksize);
- if (writebuf)
- FreeMem(writebuf, diskdev->blocksize);
- if (req)
- DeleteStdIO(req);
- if (reqport)
- DeletePort(reqport);
- if (lock)
- UnLock(lock);
- if (filehandle)
- Close(filehandle);
- if (bitmap)
- FreeMem(bitmap, bitmapsize);
- if (bitmapblocks)
- FreeMem(bitmapblocks, bitmapblocksize);
- if (headers)
- FreeMem(headers, headersize);
- if (datablock)
- FreeMem(datablock, datasize);
- if (rootblock)
- FreeMem(rootblock, rootsize);
- exit(code);
- }
-
-
- /*
- * chkabort()
- * ----------
- * A replacement for Lattice's chkabort(), which doesn't carry all
- * the extra baggage. If CTRL-C is detected, this function never
- * returns but instead calls cleanup. Since Lattice's exit() code
- * may call chkabort(), a check is made to ensure that cleanup()
- * only gets called once, otherwise there would be a problem if the
- * user pressed Ctrl-C twice in quick succession.
- */
- void chkabort(void)
- {
- static int gotctrlc = FALSE;
- if (!gotctrlc && (SetSignal(0,0) & SIGBREAKF_CTRL_C)) {
- gotctrlc = TRUE;
- print("^C\n");
- cleanup(10);
- }
- }
-
-
- /*
- * GetVolume()
- * -----------
- * This function searches the device list looking for a physical device
- * that currently contains the specified disk volume. When it finds it,
- * it fills in the DISKDEV structure with information about the physical
- * device which can then be used to access it at the block level.
- */
- int GetVolume(char *devname, DISKDEV *dev)
- {
- struct RootNode *rootnode;
- struct DosInfo *dosinfo;
- struct DeviceNode *devnode;
- struct FileSysStartupMsg *startup;
- struct DosEnvec *dosenvec;
- unsigned char *p;
- int namelen = strlen(devname);
-
- if (LASTCHAR(devname) != ':') /* Device names must end with ':' */
- return (FALSE);
- /*
- * First of all, find the device
- */
- rootnode = (struct RootNode *)DOSBase->dl_Root;
- dosinfo = (struct DosInfo *)BADDR(rootnode->rn_Info);
- devnode = (struct DeviceNode *)BADDR(dosinfo->di_DevInfo);
-
- Forbid(); /* Make sure list doesn't change while we scan it */
-
- while (devnode != NULL) {
- p = (unsigned char *)BADDR(devnode->dn_Name)+1;
- if (!strnicmp(devname, p, namelen-1)) { /* Don't compare the ':' */
- /*
- * Matched name successfully. Now check if it's a device.
- * Note that we carry on searching if it's not a device
- * (rather than returning FALSE immediately) since there
- * may be a volume called RAD: as well as a device called
- * RAD:, for example.
- */
- if (devnode->dn_Type == DLT_DEVICE) {
- if (devnode->dn_Startup < 20) /* Is there a startup bit? */
- goto notfound; /* If not, not disk device */
- /* Eek! A GOTO! */
-
- startup = (struct FileSysStartupMsg *)
- BADDR(devnode->dn_Startup);
-
- if (dev) {
- dev->devname = ((char *)BADDR(startup->fssm_Device))+1;
- dev->isfloppy = (!strcmp(TD_NAME, dev->devname));
- dev->unit = startup->fssm_Unit;
- }
-
- if (startup->fssm_Environ < 20)
- goto notfound;
- /* Another GOTO! The world will end in 5 seconds... */
-
- dosenvec = (struct DosEnvec *)BADDR(startup->fssm_Environ);
-
- if (dev) {
- dev->isffs = dosenvec->de_DosType == 0x444F5301;
- /*
- * Since dosenvec->de_DosType does NOT equal
- * 0x444F5300 for standard OFS AmigaDOS disks,
- * I can't check it to see if the filing system
- * is "known". Hence, for now, just assume its
- * always known (since it can currently only be
- * OFS or FFS, and I can't think of any other way
- * of checking).
- */
- dev->isknown = 1;
- dev->blocksize = dosenvec->de_SizeBlock << 2;
- dev->blockspertrack = dosenvec->de_BlocksPerTrack;
- dev->surfaces = dosenvec->de_Surfaces;
- dev->lowcyl = dosenvec->de_LowCyl;
- dev->numcyl = (dosenvec->de_HighCyl -
- dosenvec->de_LowCyl) + 1;
- dev->numblocks = dev->blockspertrack * dev->surfaces
- * dev->numcyl;
- dev->reserved = dosenvec->de_Reserved;
- }
- Permit();
- return (TRUE);
- }
- }
- devnode = (struct DeviceNode *)BADDR(devnode->dn_Next);
- }
- notfound:
- Permit();
- return (FALSE);
- }
-
- /*
- * help()
- * ------
- * Prints out a help message about trackfile
- */
- void help(void)
- {
- print3(
- "Trackfile (C) Copyright Eddy Carroll, January 1990. Freely distributable.\n",
- "Creates an AmigaDos file which reserves specified tracks on a disk.\n\n",
- "Usage: tfile <pathname> <start> <end>\n\n"); print3(
- " <pathname> The full AmigaDOS path of the dummy file that will be \
- created\n",
- " to hold the reserved tracks, to stop AmigaDOS using them.\n\n",
- " <start> The starting track to be reserved on the disk.\n\n" ); print(
- " <end> The ending track to be reserved on the disk.\n\n" );
- }
-
-
- /*
- * opendev()
- * ---------
- * Opens the disk device, allocates stdreqs etc. Two buffers are
- * also allocated, one for reading a single block and one for
- * writing a single block.
- */
- void opendev(void)
- {
- ULONG memflags = MEMF_PUBLIC;
-
- if (diskdev->isfloppy)
- memflags |= MEMF_CHIP;
-
- reqport = (MSGPORT *)CreatePort(0,0);
- if (!reqport) {
- print("Couldn't allocate message port\n");
- cleanup(10);
- }
-
- readbuf = AllocMem(diskdev->blocksize, memflags);
- if (!readbuf) {
- print("Couldn't allocate memory for read buffer\n");
- cleanup(10);
- }
-
- writebuf = AllocMem(diskdev->blocksize, memflags);
- if (!writebuf) {
- print("Couldn't allocate memory for write buffer\n");
- cleanup(10);
- }
-
- req = CreateStdIO(reqport);
- if (!req) {
- print("Couldn't allocate IO request - memory is low!\n");
- cleanup(10);
- }
-
- if (OpenDevice(diskdev->devname, diskdev->unit, (IOREQ *)req, 0L)) {
- print3("Can't open device ", diskdev->devname, "\n");
- cleanup(10);
- }
- devopen = TRUE;
- }
-
- /*
- * readblock() & writeblock()
- * ----------- ------------
- *
- * These two functions read or write a block from the disk.
- * See the definition of transferblocks() below for more information.
- */
- #define BLOCK_READ 0
- #define BLOCK_WRITE 1
-
- #define readblock(buffer, s) transferblocks(buffer, s, 1, BLOCK_READ)
- #define writeblock(buffer, s) transferblocks(buffer, s, 1, BLOCK_WRITE)
-
- /*
- * transferblocks()
- * ----------------
- * Transfers n blocks to/from the disk into the buffer indicated,
- * starting at block s. Note that if you are using a floppy drive, the
- * buffer MUST be allocated in CHIP ram! You can ensure this by
- * including MEMF_CHIP in the flags to AllocMem() if diskdev->isfloppy
- * is true. Zero is returned if an error occurred, else non-zero.
- * Up to three retries are done before failure is accepted.
- *
- * The direction of transfer is BLOCK_READ to read blocks in, or
- * BLOCK_WRITE to write blocks out.
- */
- int transferblocks(void *buffer, int s, int n, int direction)
- {
- int retry, parstart;
-
- /*
- * Because AmigaDOS works with partitions, Block 0 of an AmigaDOS
- * device may in fact be block 12345 of an exec device, depending
- * where the partition starts. Hence, before trying to access an
- * Amiga-DOS numbered block, we need to add in the block at which
- * the current partition starts.
- */
- parstart = diskdev->lowcyl * diskdev->blockspertrack * diskdev->surfaces;
-
- /*
- * Now read in blocks from disk
- */
- for (retry = 0; retry < 3; retry++) {
- if (direction == BLOCK_READ)
- req->io_Command = CMD_READ;
- else
- req->io_Command = CMD_WRITE;
- req->io_Length = diskdev->blocksize * n;
- req->io_Offset = diskdev->blocksize * (s + parstart);
- req->io_Data = buffer;
- if (!DoIO((IOREQ *)req))
- break; /* Succeeded, so break out of loop */
- }
- if (retry == 3)
- return (0);
- else
- return (1);
- }
-
- /*
- * SendPacket()
- * ------------
- * ``Sort of'' simulates the ARP SendPacket() routine which sends
- * a packet to AmigaDos, and gets a reply if appropriate. What is
- * passed in is the action to be executed (one of the ACTION_xxx
- * definitions in dosextens.h), a pointer to a longword array of 7
- * arguments to be passed to the device, and the msgport of the device
- * as returned by DeviceProc("DF0:") for example. If result is non-NULL
- * then it should be a pointer to a two element array of ULONGs, and it
- * fills in the 0th element with the primary result, and the the
- * 1st element with the secondary result.
- */
- int SendPacket(ULONG action, void *args, MSGPORT *devport, ULONG *result)
- {
- PROC *proc = (PROC *)FindTask(NULL);
- STDPKT *packet;
-
- packet = (STDPKT *)AllocMem(sizeof(STDPKT), MEMF_CLEAR | MEMF_PUBLIC);
- if (!packet)
- return (FALSE);
- packet->sp_Msg.mn_Node.ln_Name = (char *)&packet->sp_Pkt;
- packet->sp_Pkt.dp_Link = &packet->sp_Msg;
- packet->sp_Pkt.dp_Port = &proc->pr_MsgPort;
- packet->sp_Pkt.dp_Type = action;
- memcpy(&packet->sp_Pkt.dp_Arg1, args, sizeof(ULONG) * 7);
-
- /*
- * Okay, we've done the necessary magic to create an AmigaDos
- * packet lookalike (thanks to Matt Dillon in Transactor V1.1).
- * Now we send the message to the Dos process, and get the reply.
- * Then our message will be filled in with the response from the
- * Dos process.
- */
- PutMsg(devport, (struct Message *)packet);
- WaitPort(&proc->pr_MsgPort);
- GetMsg(&proc->pr_MsgPort);
- if (result) {
- result[0] = packet->sp_Pkt.dp_Res1;
- result[1] = packet->sp_Pkt.dp_Res2;
- }
- FreeMem(packet, sizeof(STDPKT));
- return (TRUE);
- }
-
-
- /*
- * inhibit()
- * ---------
- * This function inhibits (if mode is TRUE) or uninhibits (if mode is
- * FALSE) the specified device.
- */
- void inhibit(MSGPORT *devport, int mode)
- {
- ULONG pktargs[7];
- int i;
-
- pktargs[0] = mode; /* Select inhibit or opposite */
- for (i = 1; i < 7; i++) /* Clear other arguments */
- pktargs[i] = 0;
-
- if (!SendPacket(ACTION_INHIBIT, pktargs, devport, NULL)) {
- print("Couldn't send inhibit packet to device\n");
- cleanup(10);
- }
- }
-
-
- /*
- * flushdisk()
- * -----------
- * This function flushes the specified DOS device, ensuring that all
- * dirty buffers are written to disk and the bitmap is up to date.
- */
- void flushdisk(MSGPORT *devport)
- {
- ULONG pktargs[7];
- int i;
-
- for (i = 0; i < 7; i++) /* Clear arguments */
- pktargs[i] = 0;
-
- if (!SendPacket(ACTION_FLUSH, pktargs, devport, NULL)) {
- print("Couldn't send flush packet to device\n");
- cleanup(10);
- }
- }
-
- /*
- * fixchecksum()
- * -------------
- * Calculates the checksum for the specified block, and stores it
- * in the indicated place, which will usually be a pointer into the
- * block itself. The block is assumed to be 512 bytes long.
- */
- void fixchecksum(void *block, ULONG *checksum)
- {
- ULONG *blk = block, *start, *end;
- ULONG sum = 0;
-
- end = blk + 128;
- *checksum = 0; /* Clear checksum so it won't affect count */
-
- for (start = blk; start < end; start++)
- sum += *start;
-
- *checksum = -sum; /* Real checksum is complement of total */
- }
-
- /*
- * readrootblock()
- * ---------------
- * This function simply reads in the root block of the disk into
- * the global 'root' structure for the rest of the program to access.
- */
- void readrootblock(void)
- {
- ULONG rootblocknum = diskdev->numblocks / 2;
- ULONG memflags = MEMF_PUBLIC;
-
- if (diskdev->isfloppy)
- memflags |= MEMF_CHIP;
-
- rootsize = 512;
- rootblock = AllocMem(rootsize, memflags);
- if (!rootblock) {
- print("Out of memory allocating space for root block\n");
- cleanup(10);
- }
- if (!readblock(rootblock, rootblocknum)) {
- print("Error reading root block from disk\n");
- cleanup(10);
- }
- }
-
-
- #ifdef DEBUG
- /*
- * writerootblock()
- * ----------------
- * This function writes the rootblock back to disk.
- * Temporarily, it zaps the "validated" flag to force a validation
- * to occur.
- */
- void writerootblock(void)
- {
- ULONG rootblocknum = diskdev->numblocks / 2;
-
- rootblock->BitmapFlag = 0;
- fixchecksum(rootblock, &rootblock->Checksum);
- writeblock(rootblock, rootblocknum);
- }
-
- #endif
-
-
- /*
- * readbitmap()
- * ------------
- *
- * This function creates a memory copy of the disks's bitmap, by
- * reading in all the disk's bitmap blocks. Two arrays are created;
- * The first holds the bitmap data itself, the second is a longword
- * array holding the block numbers that the bitmap is stored on, for
- * use when it is being written out again.
- *
- * If an error occurs, the function prints a message and exits to dos.
- * It is assumed that the root block has been read in to 'root' before
- * calling this function.
- */
- void readbitmap(void)
- {
- int i, end;
- ULONG nextblock;
- ULONG *block = readbuf;
-
- /*
- * First let's calculate the size of each array. The size of the
- * bitmap array is simply the number of blocks on the disk divided
- * by 8 (since a single byte can represent 8 blocks). The size of
- * the array to hold the locations of the bitmap blocks is the
- * number of blocks divided by 4064, since each bitmap block
- * can represent 4064 disk blocks (with 32 bits left over for
- * the block checksum).
- */
-
- /*
- * To calculate the number of DOS-usable blocks on the disk, we need
- * to subtract the number of blocks reserved at the start of the
- * partition. In addition, we add on 4063 so that the result after
- * division will be rounded up to the next integral block number.
- */
- numbitmapblocks = (diskdev->numblocks + 4063 - diskdev->reserved) / 4064;
- bitmapsize = numbitmapblocks * 508; /* 4 bytes used for checksum */
- bitmapblocksize = numbitmapblocks * 4;
-
- /*
- * Now, allocate the arrays
- */
- bitmap = AllocMem(bitmapsize, 0L);
- if (!bitmap) {
- print("Can't allocate memory to store disk bitmap.\n");
- cleanup(10);
- }
- bitmapblocks = AllocMem(bitmapblocksize, 0L);
- if (!bitmapblocks) {
- print("Can't allocate memory to store disk bitmap sector numbers.\n");
- cleanup(10);
- }
-
- /*
- * Now, read in all the sector numbers from the root block
- */
- end = MIN(numbitmapblocks, 25);
- for (i = 0; i < end; i++)
- bitmapblocks[i] = rootblock->BitmapKeys[i];
-
- /*
- * If we are using a large disk partition (larger than 52 Megs or so)
- * we also need to read in the bitmap extension block(s). Each
- * extension block contains 127 sector numbers.
- *
- * Note: Since I am unsure of the extension bitmap format used,
- * this code is being commented out for now, and a check has been
- * included in main() to ensure no disk big enough to have an
- * bitmap extension is allowed to get here; when I find out the
- * format, it will be trivial to add support for it here, since the
- * rest of the program just deals with an array of bitmap sector
- * numbers (and the bitmap array itself of course).
- *
- * For the code, I'm assuming the bitmap is stored back to front
- * (i.e. first sector last), based on Betty Clay's article in
- * Transactor. I want to verify this first though before letting
- * it loose on the unsuspecting public (after all, a bug that screws
- * up a 50 Mb disk is not going to go down well with people who
- * have 50 Mb disks... :-)
- */
-
- nextblock = rootblock->BitmapExtend;
-
- #ifdef FOUND_OUT_HOW_THE_BITMAP_IS_STORED
-
- while (i < numbitmapblocks) {
- int p = 127;
-
- if (!readblock(block, nextblock)) {
- print("Error reading bitmap extension block from disk\n");
- cleanup(10);
- }
- nextblock = block[0];
- end = MIN(i + 127, numbitmapblocks);
- while (i < end)
- bitmapblocks[i++] = blocks[p--];
- }
-
- #endif
-
- /*
- * Now I know what sectors the bitmap itself is stored on, so
- * I can read it in to memory.
- */
- for (i = 0; i < numbitmapblocks; i++) {
- if (!readblock(block, bitmapblocks[i])) {
- print("Error reading in bitmap from disk\n");
- cleanup(10);
- }
- /*
- * Remember, bitmap is pointer to ULONG so we use longword
- * offsets when copying the bitmap data into the bitmap array.
- */
- memcpy(bitmap + (127 * i), block + 1, 508);
- }
- }
-
- /*
- * writebitmap()
- * -------------
- * Writes the disk bitmap back to disk, storing it on the sectors
- * it was read in from earlier.
- */
- void writebitmap(void)
- {
- ULONG *diskblock = (ULONG *)writebuf;
- int i;
-
- for (i = 0; i < numbitmapblocks; i++) {
- /*
- * For each bitmap block, copy the 127 longwords into write
- * buffer, correct checksum, then write to disk.
- */
- memcpy(diskblock + 1, bitmap + (i * 127), 508);
- fixchecksum(diskblock, &diskblock[0]);
- if (!writeblock(diskblock, bitmapblocks[i])) {
- print(
- "Error writing updated bitmap to disk! Copy important files to a new disk!\n");
- cleanup(10);
- }
- }
- }
-
- #ifdef DEBUG
- /*
- * dumpbitmap()
- * ------------
- * A quick hack function to display the bitmap on screen, to allow
- * visual confirmation that it was read in correctly, altered
- * properly etc.
- */
- void dumpbitmap(void)
- {
- int t, s, c, blocknum, i;
- static char buf[300];
-
- for (c = 0; c < diskdev->numcyl; c++) {
- for (t = 0; t < diskdev->surfaces; t++) {
-
- blocknum = (((c * diskdev->surfaces) + t)
- * diskdev->blockspertrack);
- chkabort();
- print3(numtostr(c),",",numtostr(t));
- print3(": ",numtostr(blocknum),"; ");
- i = 0;
- for (s = 0; s < diskdev->blockspertrack; s++) {
- blocknum = (((c * diskdev->surfaces) + t)
- * diskdev->blockspertrack) + s;
- if (blocknum < diskdev->reserved ||
- blocknum >= diskdev->numblocks)
- buf[i++] = 'O'; /* Block reserved */
- else {
- blocknum = blocknum - diskdev->reserved;
- if (bitmap[blocknum >> 5] & (1 << (blocknum & 31)))
- buf[i++] = '-'; /* Block unused */
- else
- buf[i++] = 'O'; /* Block in use */
- }
- }
- buf[i] = '\0';
- print2(buf, "\n");
- }
- }
- }
- #endif
-
- /*
- * filltracks()
- * ------------
- * Tries to mark the specified cylinders as used in the memory copy
- * of the disk bitmap. 1 is returned if successful, 0 if any of the
- * blocks in the cylinders were already in use.
- */
- int filltracks(int lowcyl, int highcyl)
- {
- long startblock, endblock; /* Adjusted block numbers */
- long startblockindex, endblockindex; /* Indexes into bitmap array */
- long startoffset, endoffset; /* Bit offsets into bitmap word */
- long lastblock; /* Last bitmap block on disk */
- int i, warn = 0;
-
- lastblock = diskdev->numblocks - diskdev->reserved;
-
- startblock = lowcyl * diskdev->surfaces * diskdev->blockspertrack
- - diskdev->reserved;
- if (startblock < 0) {
- warn = 1;
- startblock = 0;
- }
- if (startblock >= lastblock) {
- warn = 1;
- startblock = lastblock;
- }
- startblockindex = startblock >> 5;
- startoffset = startblock & 31;
-
- endblock = (highcyl + 1) * diskdev->surfaces * diskdev->blockspertrack
- - diskdev->reserved;
- if (endblock < 0) {
- warn = 1;
- endblock = 0;
- }
- if (endblock > lastblock) {
- warn = 1;
- endblock = lastblock;
- }
- endblockindex = endblock >> 5;
- endoffset = endblock & 31;
-
- if (warn)
- print("(Warning: Track range includes reserved portion of disk.)\n");
-
- if (startblockindex == endblockindex) {
- /*
- * Start and stop in same bitmap word, so set the bits manually
- */
- for (i = startoffset; i < endoffset; i++) {
- if ((bitmap[startblockindex] & (1 << i)) == 0)
- return (0); /* Block already in use */
- else
- bitmap[startblockindex] &= ~(1 << i); /* Clear bit in bitmap */
- }
- return (1);
- }
-
- /*
- * Allocate first few blocks a bit at a time up to end of longword
- */
- for (i = startoffset; i < 32; i++) {
- if ((bitmap[startblockindex] & (1 << i)) == 0)
- return (0); /* Block already in use */
- else
- bitmap[startblockindex] &= ~(1 << i); /* Clear bit in bitmap */
- }
-
- /*
- * Now allocate inbetween blocks a longword at a time for speed
- */
- for (i = startblockindex + 1; i < endblockindex; i++) {
- if (bitmap[i] != 0xffffffff)
- return (0); /* Block already in use */
- else
- bitmap[i] = 0; /* Set all blocks used */
- }
-
- /*
- * Finally, allocate last few blocks a bit at a time
- */
- for (i = 0; i < endoffset; i++) {
- if ((bitmap[endblockindex] & (1 << i)) == 0)
- return (0); /* Block already in use */
- else
- bitmap[endblockindex] &= ~(1 << i); /* Clear bit in bitmap */
- }
- return (1);
- }
-
- /*
- * allocblock()
- * ------------
- * Tries to allocate a block as close to block `key' as possible,
- * from the remaining free blocks in the disk bitmap. The allocation
- * algorithm is as follows:
- *
- * - Find the nearest free block before the key
- * - Find the nearest free block after the key
- * - Allocate whichever one is closest
- *
- * If the allocation was successful, the number of the new block is
- * stored in newkey.
- */
- int allocblock(ULONG key, ULONG *newkey)
- {
- ULONG curblock = key - diskdev->reserved;
- ULONG endblock = diskdev->numblocks - diskdev->reserved;
- ULONG endindex = endblock >> 5;
- ULONG useblock;
- long i, j, tp; /* Must be signed */
- long curindex = curblock >> 5;
- long curoffset = curblock & 31;
- int backblock = -1, forblock = -1;
-
- /*
- * Find nearest block before current key. Remember that in the
- * bitmap, a `1' means the block is free, a `0' means its allocated.
- *
- * First of all, search back within current bitmap word
- */
- tp = bitmap[curindex];
- for (i = curoffset; i >= 0; i--) {
- if (tp & (1 << i)) {
- backblock = (curindex << 5) + i;
- break;
- }
- }
-
- if (backblock < 0) {
- /*
- * Didn't find room in initial word, so carry on search
- */
- for (i = curindex - 1; i >= 0; i--) {
- if (bitmap[i] != 0) {
- tp = bitmap[i];
- /*
- * Found free block word; now find what bit it is;
- * Note that because of the way we entered this
- * loop (with tp != 0), termination of the next
- * loop is guaranteed.
- */
- for (j = 31; (tp & (1 << j)) == 0; j--)
- ;
- backblock = (i << 5) + j;
- break;
- }
- }
- }
-
- /*
- * Now find nearest block after current key
- */
- tp = bitmap[curindex];
- for (i = curoffset; i < 32; i++) {
- if (tp & (1 << i)) {
- forblock = (curindex << 5) + i;
- break;
- }
- }
-
- if (forblock < 0) {
- /*
- * Didn't find room in initial word, so carry on search
- */
- for (i = curindex + 1; i <= endindex; i--) {
- if (bitmap[i] != 0) {
- tp = bitmap[i];
- /*
- * Found free room; now find what bit it is;
- * Note that because of the way we entered this
- * loop (with tp != 0), termination of the next
- * loop is guaranteed.
- */
- for (j = 0; (tp & (1 << j)) == 0; j++)
- ;
- forblock = (i << 5) + j;
- break;
- }
- }
- }
-
- /*
- * Now, forblock and backblock hold block numbers which are free
- * in the bitmap (or -1 if none was found). We just have to
- * work out which one to use.
- */
- if (forblock < 0) {
- if (backblock < 0)
- return (0);
- else
- useblock = backblock;
- } else {
- if (backblock < 0)
- useblock = forblock;
- else {
- if ((key - backblock) < (forblock - key))
- useblock = backblock;
- else
- useblock = forblock;
- }
- }
-
- /*
- * At this stage, useblock is the block number to allocate and
- * return.
- */
- bitmap[useblock >> 5] &= ~(1 << (useblock & 31));
- *newkey = useblock + diskdev->reserved;
- /*
- * Finally, a brief sanity check to ensure the number is in range
- * It SHOULD be but it doesn't do any harm to check, in case we
- * ran off the end of the bitmap or something...
- */
- if (*newkey < diskdev->numblocks)
- return (1);
- else
- return (0);
- }
-
-
- /*
- * createfileheaders()
- * -------------------
- * Allocates an array of file headers and extension blocks, and
- * fills them in with the appropriate values to make AmigaDOS think
- * a file exists on the tracks the user indictated. The key is
- * the block number of the file header which is to be modified to
- * hold the dummy file.
- *
- * As well as allocating the blocks on the tracks to be reserved,
- * an additional `frontend' data block is stuck at the front of the
- * file containing a brief message. This stops DOS from getting
- * confused if the user tries to access the file. Under the FFS it
- * isn't needed, but under the OFS, a series crash results. To stop
- * the code getting overly complicated, the FFS gets it too.
- *
- * After the headers have been initialised, they are written back to
- * the disk and hey presto, a new file is born :-)
- */
- void createfileheaders(int key, int lowcyl, int highcyl)
- {
- static char msgbuf[488];
- ULONG lastblock, startblock, endblock, numblocks, filesize;
- ULONG curblock;
- ULONG memflags = MEMF_PUBLIC | MEMF_CLEAR;
- int i, j, numheaders;
-
- lastblock = diskdev->numblocks;
-
- startblock = lowcyl * diskdev->surfaces * diskdev->blockspertrack;
- if (startblock < diskdev->reserved)
- startblock = diskdev->reserved;
-
- endblock = (highcyl + 1) * diskdev->surfaces * diskdev->blockspertrack;
- if (endblock > lastblock)
- endblock = lastblock;
-
- numblocks = 1 + endblock - startblock; /* 1 extra for front data block */
-
- /*
- * Now, we know how many blocks the file will have (we've been
- * careful not to count blocks which are reserved at the start
- * or end of the partition). Next, let's calculate how many
- * bytes our pretend file will have. This depends on whether
- * the filing system is OFS or FFS.
- */
- if (diskdev->isffs)
- filesize = numblocks * 512;
- else
- filesize = numblocks * 488;
-
- /*
- * Now allocate the file header/extensions to hold the file.
- * Each header/extension holds 72 block keys.
- */
- numheaders = (numblocks + 71) / 72;
- headersize = numheaders * 512;
-
- if (diskdev->isfloppy)
- memflags |= MEMF_CHIP;
-
- headers = AllocMem(headersize, memflags);
- if (!headers) {
- print("Error allocating memory for file header/extension blocks\n");
- cleanup(10);
- }
- /*
- * Read in file header block, for file to be modified.
- */
- if (!readblock(headers, key)) {
- print("Error reading file header block from disk\n");
- cleanup(10);
- }
- /*
- * Now fill in the details for all the file extension blocks.
- */
-
- curblock = startblock - 1; /* Adjust to allow for front data block */
-
- for (i = 0; i < numheaders; i++) {
- int end = MIN(72, endblock - curblock);
-
- for (j = 0; j < end; j++)
- headers[i].DataBlocks[71-j] = curblock++;
- }
-
- for (i = 1; i < numheaders; i++) {
-
- headers[i].Type = Type_List;
- headers[i].SecondaryType = SecType_File;
- if (!allocblock(headers[i-1].OwnKey, &headers[i].OwnKey)) {
- print("Not enough room on disk to store dummy file.\n");
- cleanup(10);
- }
- headers[i-1].Extension = headers[i].OwnKey;
- headers[i].HighSeq = 72;
- headers[i].DataSize = 72;
- headers[i].Parent = key;
- }
- headers[numheaders-1].Extension = 0;
- headers[numheaders-1].HighSeq = numblocks % 72;
- headers[numheaders-1].DataSize = numblocks % 72;
-
- headers[0].FileSize = filesize;
- headers[0].HighSeq = numblocks;
-
- /*
- * Now, allocate and save the dummy data block containing the
- * brief message. Under the FFS, users can actually access the
- * raw track data by seeking to (offset + 512), where offset is
- * the desired byte offset from the first reserved cylinder.
- */
- datasize = 512;
- datablock = AllocMem(datasize, memflags);
- if (!datablock) {
- print("Out of memory allocating temporary disk data block.\n");
- cleanup(10);
- }
- if (!allocblock(key, &datablocknum)) {
- print("Not enough room on disk to store dummy file.\n");
- cleanup(10);
- }
- /*
- * Now generate message containing track data.
- */
- strcpy(msgbuf, FileMessage);
- if (lowcyl == highcyl) {
- strcat(msgbuf, "This file contains disk track ");
- strcat(msgbuf, numtostr(lowcyl));
- } else {
- strcat(msgbuf, "This file contains disk tracks ");
- strcat(msgbuf, numtostr(lowcyl));
- strcat(msgbuf, " to ");
- strcat(msgbuf, numtostr(highcyl));
- }
- strcat(msgbuf, "\n\n");
-
- if (diskdev->isffs) {
- /*
- * For FFS, just put raw data into block.
- */
- strcpy((char *)datablock, msgbuf);
- } else {
- /*
- * For OFS, fill in appropriate header details
- */
- datablock->Header = key;
- datablock->Type = Type_Data;
- datablock->SeqNum = 1;
- datablock->NextData = 0;
- datablock->DataSize = strlen(msgbuf);
- strcpy((char *)datablock->Data, msgbuf);
-
- fixchecksum(datablock, &datablock->Checksum);
- }
-
- if (!writeblock(datablock, datablocknum)) {
- print("Error writing file data block to disk\n");
- cleanup(10);
- }
-
- /*
- * Now fix up datablock pointers in file header
- */
- headers[0].FirstBlock = datablocknum;
- headers[0].DataBlocks[71] = datablocknum;
-
- /*
- * All the data blocks have been allocated correctly; now
- * fix up the data checksums for each block. When the checksum
- * is correct, all the longwords in the block will add up to zero
- * (no carry when overflow occurs).
- */
- for (i = 0; i < numheaders; i++)
- fixchecksum(&headers[i], &headers[i].Checksum);
-
- /*
- * Finally, write all the file blocks back to disk. Note that
- * they are written back to disk in reverse order. This way, the
- * file header itself is the last thing to get written, so if an
- * error occurs before hand, it won't be left in an inconsistent
- * state.
- */
- chkabort(); /* Give user a final chance to abort */
- for (i = numheaders - 1; i >= 0; i--) {
- if (!writeblock(&headers[i], headers[i].OwnKey)) {
- print("Error writing file headers to disk\n");
- cleanup(10);
- }
- }
- }
-
-
- /*
- * mainline()
- * ----------
- */
- void main(argc,argv)
- int argc;
- char **argv;
- {
- unsigned int start, end; /* Cylinder numbers */
- char *p;
-
- #define NONUM(x) (!isdigit(argv[x][0]))
-
- if (argc != 4 || NONUM(2) || NONUM(3)) {
- help();
- cleanup(10);
- }
-
- /*
- * Strip off trailing dir and filenames to get device name
- */
- pathname = argv[1];
- strcpy(devname, pathname);
-
- for (p = devname; *p && *p != ':'; p++)
- ;
- if (*p != ':') {
- print("The pathname must include both a device and a filename.\n");
- cleanup(10);
- }
- p++; /* Skip over colon at end of device name */
- *p = '\0';
-
- if (strlen(pathname) <= strlen(devname)) {
- print("The pathname must include both a device and a filename.\n");
- cleanup(10);
- }
- start = atoi(argv[2]);
- end = atoi(argv[3]);
-
- if (!GetVolume(devname, diskdev)) {
- print2(devname, " is not a valid disk device\n");
- cleanup(10);
- }
-
- if (start > end) {
- print("Start track is greater than end track.\n");
- cleanup(10);
- }
-
- if (end >= diskdev->numcyl) {
- print3("Maximum end track on ", devname, " is ");
- print2(numtostr(diskdev->numcyl - 1), ".\n");
- cleanup(10);
- }
-
- if (!diskdev->isknown) {
- print(
- "Sorry, only Old Filing System and Fast Filing System are supported.\n");
- cleanup(10);
- }
-
- if (diskdev->blocksize != 512) {
- print(
- "Sorry, only devices with 512 byte blocks can be handled at present.\n");
- cleanup(10);
- }
-
- if (diskdev->numblocks > (25 * 4064)) {
- print("Sorry, this version doesn't support drives > 50 Mb\n");
- cleanup(10);
- }
-
- diskport = (MSGPORT *)DeviceProc(devname);
- if (!diskport) {
- print3("Can't locate process for device ", devname, "\n");
- cleanup(10);
- }
-
- /*
- * Everything seems in order, so lets try and create the dummy file.
- * After creating it, we flush the disk buffers etc. to ensure that
- * the disk bitmap is current.
- */
- filehandle = Open(pathname, MODE_NEWFILE);
- if (!filehandle) {
- print3("Couldn't open file ", pathname, ".\n");
- cleanup(10);
- }
- Close(filehandle); filehandle = NULL;
- lock = Lock(pathname, ACCESS_READ);
- if (!lock) {
- print3("Strangely, file ", pathname, " can no longer be accessed.\n");
- cleanup(314); /* pi -- let's be weird */
- }
- filekey = ((struct FileLock *)BTOC(lock))->fl_Key;
- flushdisk(diskport);
-
- /*
- * Assuming everthing is still okay, the next step is to read in
- * the root block and do some checks to make sure we can do the
- * allocation.
- */
- opendev();
- inhibit(diskport, TRUE);
- inhibited = TRUE;
- readrootblock();
- if (rootblock->BitmapFlag != -1) {
- print3("tfile: Bitmap for ", devname, " is not up to date.\n");
- cleanup(10);
- }
-
- /*
- * Read in bitmap, and mark all the blocks on the desired tracks
- * as in-use. If any of these blocks are already in use, then
- * abort with an error.
- */
- readbitmap();
- if (!filltracks(start, end)) {
- print3("Tracks ",numtostr(start)," to ");
- print2(numtostr(end)," contain AmigaDOS data.\n");
- cleanup(10);
- }
-
- /*
- * Now allocate file header blocks to store the AmigaDOS pointers
- * to each block in the reserved tracks in. The memory copy of
- * the bitmap is modified to reflect these additional blocks.
- * Then the new blocks are written back to disk, and the
- * file header of the existing file is updated to reflect the
- * additional data blocks.
- */
- createfileheaders(filekey,start,end);
-
- /*
- * Everything is now complete, so all that remains to be done
- * is to write back the new bitmap, update the root block and
- * exit.
- */
- writebitmap();
- cleanup(0);
- }
-