Commit 1a53aac2 authored by ASCP's avatar ASCP 💬

Initial commit

parents
File added
File added
File added
Programming Documentation For
QUARTERBACK
OVERVIEW
Quarterback is a hard disk backup program, designed to copy AmigaDOS
files to and from floppy disks quickly and easily. It can backup
files from or restore files to any standard AmigaDOS file-structured
device. It can use any standard AmigaDOS device to hold the files,
but was designed primarily to use floppy disks as the backup medium.
However, it can also backup to another hard disk partition, or to
some other AmigaDOS device such as cartridge drives or tape drives
provided the device us really AmigaDOS-compatible (random access).
German, Swedish, and Norwegian versions of Quarterback exist in
addition to the standard English version.
DESIGN PHILOSOPHY
The Quarterback design has been optimized for speed of floppy disk
operations, but uses standard device drivers. In reading and
writing files from the hard disk, it accesses files via AmigaDOS.
In this sense it is compatible with all standard hard disk devices.
If a hard disk can work with the Amiga via AmigaDOS, Quarterback can
back it up. Likewise, if the backup medium device driver uses the
standard AmigaDOS disk driver interface (poorly defined, unfor-
tunately) then Quarterback can utilize the driver.
The design of the program has evolved over the years to make it
easier to use. For example, it now displays the volumes available
to backup or restore by volume name, so that the user need only
click on the name of the volume he wishes to backup.
Quarterback utilizes two floppy drives (if available) to optimize
backup/restore speed by switching to an alternate drive while the
operator is changing the diskette in the drive just completed. Disk
change detection is handled through Intuition.
MODULE DESCRIPTION
Quarterback consists of 13 source modules and 4 include files.
The include files are maintained in a subdirectory named i.
MACROS.ASM contains common assembly language macros defining a
pseudo high-level language. EQUATES.ASM includes common equates
from the include files provided by Commodore. BOXES.ASM contains
equates for defining the coordinates of text messages and boxes for
various Quarterback displays. IO.I contains equates and offsets
used by DISK.ASM.
QB.ASM contains initialization and exit code, main event loop
processing, and code for command file inperpretation.
FILES.ASM contains code to open, read, and write AmigaDOS files on
the hard disk drive.
MAIN.ASM contains the primary backup and restore code, including
status messages, error requesters, catalog processing, etc.
REPORT.ASM contains code to generate the backup/restoration
report.
DEVICE.ASM generates the list of volumes available to backup or
restore, and determines the availability and capacity of the backup
device(s).
DISK.ASM handles the actual backup device reads and writes via
direct calls to the device driver.
GADGETS.ASM contains data tables defining all gadgets of the
program.
MENUS.ASM contains tables defining the menu bar items.
PGU.ASM contains a patch to the DISK.RESOURCE code to correct for
problems caused by a bug in older versions of Trackdisk.device.
FUN.ASM contains text string manipulation code and error requester
subroutines.
BEEP.ASM sounds an audible beep via the audio hardware.
MESSAGES.ASM contains all language-dependent text messages.
VERSION.ASM contains title bar and initial greeting text, including
the current version text.
BUILDING INSTRUCTIONS
Source modules are assembled using the CAPE assembler and linked
using BLINK. Demo and evaluation versions are linked using special
versions of VERSION.ASM and MAIN.ASM.
TRICKS, TRAPS, AND GOTCHAS
Older versions of Quarterback used a software interrupt vector via
Trackdisk.device to detect disk changes. This unfortunately caused
Quarterback to be dependent upon the version of Trackdisk.device in
use on the Amiga.
The current version (V4.3) now utilizes Intuition calls to detect
disk changes. The Intuition approach guarantees future compati-
bility with new versions of Workbench.
SUPPORT ISSUES
Quarterback does not store files on a backup disk in standard
AmigaDOS format. It uses its own custom format, avoiding the
overhead and wasted space of the AmigaDOS directory structure and
file headers. This means that AmigaDOS cannot be used to retrieve
files from Quarterback disks; only Quarterback can do this.
Quarterback stores a catalog of files on the first disk of the
backup set. However, since this catalog is required to find and
restore files on the entire set of backup disks, and because of the
danger of being unable to restore any files from any disks of the
set if the catalog cannot be read from the first, Quarterback stores
a second copy of the catalog on the last disk of the backup set.
Quarterback automatically asks the operator for the first disk when
starting to restore files. If the catalog cannot be read from the
first disk, Quarterback asks for the last disk so that the
"alternate" catalog can be retrieved. If neither catalog can be
found or read completely, Quarterback cannot restore files from any
disk.
In order to prevent accidental writing on a disk which might contain
valuable data, Quarterback requires that a disk change take place
before any files are written to the backup device. Some new users
are initially confused by this, thinking that something is wrong
with the program. Although this is clearly defined in the
documentation, invariably a few new users will call and report a
"bug".
Quarterback uses AmigaDOS calls to access files on the hard disk.
While this ensures hardware compatibility with any Amiga hard disk
drive, it makes Quarterback vulnerable to AmigaDOS problems,
including crashes caused by corrupted directory or file header
blocks on the volume. From the user's point of view it appears that
Quarterback has crashed, when in fact the problem MAY be an AmigaDOS
crash or even a device driver crash. Sometimes it can be very
difficult to convince an irate customer of this possibility or to
uncover the real cause ofthe problem. However, Quarterback is a
mature and stable product, such that undocumented problems are
unlikely to appear.
COMMENTS
Quarterback needs two additional features to remain fully
competitive in the Amiga marketplace: data compression and streaming
tape support.
File added
File added
#include <exec/types.h>
#include <exec/io.h>
#include <devices/trackdisk.h>
#include <libraries/dosextens.h>
#include <exec/memory.h>
#include <ctype.h>
#include <stdio.h>
#include <intuition/intuition.h>
extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStd();
extern struct FileHandle *Open();
extern struct Process *FindTask();
extern void *AllocMem();
struct MsgPort *diskport1 = 0;
struct IOStdReq *diskreq1 = 0;
struct Process *Me;
struct IntuitionBase *IntuitionBase;
LONG size = 0;
UBYTE *buff1;
UBYTE disk=1;
SHORT err;
#define MAX 5632 /* 512*11 End of Buffer */
void main( argc, argv )
int argc;
char *argv[];
{
LONG drv;
drv = atoi(argv[1]);
if(drv < 0 || drv > 3)
{ printf("Drive must be between 0 and 3\n"); exit(0); }
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
if(IntuitionBase==NULL) { printf("no Intuition\n"); exit(0); }
diskport1 = (struct MsgPort *)CreatePort(0,0);
if(diskport1==0) { printf("no diskport\n"); exit(0); }
diskreq1 = (struct IOStdReq *)CreateStdIO(diskport1);
if(diskreq1==0) { printf("no diskreq\n"); goto out3; }
buff1 = (UBYTE *)AllocMem(512*11, MEMF_CHIP|MEMF_CLEAR);
if( !buff1 ) { printf("Can't allocate buffer 1\n"); goto out2; }
if((err = OpenDevice(TD_NAME, drv, diskreq1, 0)) != 0)
{ printf("no Drive %d %d\n",drv,err); goto out1; }
Me = FindTask(0);
ReadTrk();
if(err)
printf("\nRead failed\n\n");
else
{
DoDir( argv[2], 0 );
if(err)
printf("Read failed.\n\n");
else
printf("Read successful.\n\n");
}
MotorOff();
CloseDevice(diskreq1);
out1:
FreeMem(buff1,512*11);
out2:
DeleteStdIO(diskreq1);
out3:
DeletePort(diskport1);
} /* End of main */
DoDir( name, depth )
UBYTE *name;
ULONG depth;
{
struct FileInfoBlock *fib;
ULONG flock, lock, oldlock, x, i, terr;
UBYTE fname[35];
UBYTE tmp;
fib = (struct FileInfoBlock *)
AllocMem( sizeof( struct FileInfoBlock ),MEMF_PUBLIC|MEMF_CLEAR );
if(!fib)
{ printf("\nCan't allocate memory.\n\n"); err=1; return(0); }
else
{
lock = Lock( name, ACCESS_READ );
if(!lock)
{
err=1;
printf("\nCan't find %s Directory.\n\n",name);
FreeMem( fib, sizeof( struct FileInfoBlock ) );
return(0);
}
else
{
oldlock = CurrentDir( lock );
while ( *(buff1+size) != 0xFF )
{
for( x=0; x<depth; x++) printf("\t");
i=0;
for(;;)
{
tmp = *(buff1+size);
if( tmp == 0xFF ) break;
if( tmp == 0xFE ) break;
fname[i++] = *(buff1+size++);
if(i>30)
{ printf("\nDisk data corrupt\n\n"); err=1; break; }
if(size >= MAX) ReadTrk();
if(err) break;
}
fname[i] = 0; /* pad name */
size++;
if(size >= MAX) ReadTrk();
if(err) break;
switch(tmp)
{
case 0xFE:
printf("%s ",fname);
Dump(fname);
if(!err)
printf("...copied\n");
break;
case 0xFF:
printf("%s (dir)",fname);
flock = CreateDir(fname);
if(!flock)
{
terr = IoErr();
if(terr == 203 || terr == 216 || terr == 202)
{
UnLock(flock);
printf(" [exists]\n");
DoDir( fname, depth+1 );
}
else
{
err=1;
printf("\nError %d creating Directory.\n",terr);
}
}
else
{
UnLock(flock);
printf(" [created]\n");
DoDir( fname, depth+1 );
}
break;
default:
err=1;
printf("\nDisk data corrupt\n\n");
}
if(err) break;
}
lock = CurrentDir( oldlock );
UnLock( lock );
}
FreeMem( fib, sizeof( struct FileInfoBlock ) );
}
if(!err)
{
size++;
if(size >= MAX) ReadTrk();
}
return(0);
}
Dump(fname)
UBYTE *fname;
{
SHORT i;
SHORT s;
ULONG tot, fsize=0;
struct FileHandle *src;
for(i=0; i<4; i++) /* Get file size */
{
fsize = fsize * 0x100 + *(buff1+size++);
if(size >= MAX) ReadTrk();
if(err) return(0);
}
if((src = Open(fname, MODE_NEWFILE)) == NULL)
{ printf("\nCan't open file %s\n",fname); err=1; return(0); }
while(fsize)
{
if(fsize > (MAX-size))
{ tot = MAX-size; fsize -= tot; }
else
{ tot = fsize; fsize -= tot; }
s = Write(src, buff1+size, tot);
if(s == -1)
{
printf("\nError %d while writing %s\n\n",IoErr(),fname);
err=1;
Close(src);
return(0);
}
size += s;
if(size >= MAX) ReadTrk();
if(err) break;
}
Close(src);
return(0);
}
ReadTrk()
{
static SHORT Trak = 0;
again:
size = (Trak == 0) ? 5 : 0;
if(Trak==0)
{
while(TRUE)