testing disk generator

This commit is contained in:
Greg Gauthier 2023-07-06 19:23:21 +01:00
parent 9e412b248b
commit 852d3a1b67
20 changed files with 3276 additions and 0 deletions

BIN
FDISK/BOOTDISK2.atr Normal file

Binary file not shown.

BIN
FDISK/test.atr Normal file

Binary file not shown.

362
SRC/atr2unix-1.3.c Normal file
View File

@ -0,0 +1,362 @@
/************************************************************************/
/* atr2unix.c */
/* */
/* Preston Crow */
/* Public Domain */
/* */
/* Extract files from an Atari DOS or MyDOS .ATR file */
/* */
/* Version History */
/* 5 Jun 95 Version 1.0 Preston Crow <crow@cs.dartmouth.edu> */
/* Initial public release */
/* 20 Dec 95 Version 1.1 Chad Wagner <cmwagner@gate.net> */
/* Ported to MS-DOS machines */
/* 10 Feb 98 Version 1.2 Preston Crow <crow@cs.dartmouth.edu> */
/* Expanded 256-byte sector support */
/* 2 Jan 22 Version 1.3 Preston Crow */
/* Enhanced debugging */
/************************************************************************/
/************************************************************************/
/* Portability macros */
/* 1 Jun 95 crow@cs.dartmouth.edu (Preston Crow) */
/************************************************************************/
#if defined(__MSDOS) || defined(__MSDOS__) || defined(_MSDOS) || \
defined(_MSDOS_)
#define MSDOS /* icky, icky, icky! */
#endif
/************************************************************************/
/* Include files */
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#ifdef MSDOS
#include <dir.h>
#include <io.h>
#else
#include <unistd.h>
#endif
/************************************************************************/
/* Macros and Constants */
/************************************************************************/
#define ATRHEAD 16
#define USAGE "atr2unix [-dlmr-] atarifile.atr\n" \
" Flags:\n" \
"\t-l Convert filenames to lower case\n" \
"\t-m MyDOS format disk image\n" \
"\t-- Next argument is not a flag\n" \
"\t-d debugging\n" \
"\t-r={sector} Use non-standard root directory number\n" \
"\t-f Fake run; do not create any files\n"
#ifndef SEEK_SET
#define SEEK_SET 0 /* May be missing from stdio.h */
#endif
#define SEEK(n) (ddshortinit?SEEK1(n):SEEK2(n))
#define SEEK1(n) (ATRHEAD + ((n<4)?((n-1)*128):(3*128+(n-4)*secsize)))
#define SEEK2(n) (ATRHEAD + ((n-1)*secsize))
/************************************************************************/
/* Data types */
/************************************************************************/
struct atari_dirent {
unsigned char flag; /* set bits: 7->deleted 6->in use 5->locked 0->write open */
unsigned char countlo; /* Number of sectors in file */
unsigned char counthi;
unsigned char startlo; /* First sector in file */
unsigned char starthi;
char namelo[8];
char namehi[3];
};
struct atr_head {
unsigned char h0; /* 0x96 */
unsigned char h1; /* 0x02 */
unsigned char seccountlo;
unsigned char seccounthi;
unsigned char secsizelo;
unsigned char secsizehi;
unsigned char hiseccountlo;
unsigned char hiseccounthi;
unsigned char unused[8];
};
/************************************************************************/
/* Function Prototypes */
/************************************************************************/
void read_dir(FILE *in,int sector);
void read_file(char *name,FILE *in,FILE *out,int sector,int count,int filenum);
/************************************************************************/
/* Global variables */
/************************************************************************/
int ddshortinit=0; /* True indicates double density with first 3 sectors 128 bytes */
int secsize,seccount;
int mydos=0;
int lowcase=0;
int debug=0;
int fake=0;
/************************************************************************/
/* main() */
/* Process command line */
/* Open input .ATR file */
/* Interpret .ATR header */
/************************************************************************/
int main(int argc,char *argv[])
{
FILE *in;
struct atr_head head;
int root=361;
--argc; ++argv; /* Skip program name */
/* Process flags */
while (argc) {
int done=0;
if (**argv=='-') {
++*argv;
while(**argv) {
switch(**argv) {
case 'm': /* MyDos disk */
mydos=1;
break;
case '-': /* Last option */
done=1;
break;
case 'l': /* strlwr names */
lowcase=1;
break;
case 'f': /* fake */
fake=1;
break;
case 'd': /* debugging */
debug=1;
break;
case 'r': /* root directory sector */
++*argv;
while ( **argv && !isdigit(**argv) ) ++*argv;
root=atoi(*argv);
while ( argv[0][1] ) ++*argv;
break;
default:
fprintf(stderr,USAGE);
exit(1);
}
++*argv;
}
--argc; ++argv;
}
else break;
if (done) break;
}
if (!argc) {
fprintf(stderr,USAGE);
exit(1);
}
in=fopen(*argv,"rb");
if (!in) {
fprintf(stderr,"Unable to open %s\n%s",*argv,USAGE);
exit(1);
}
--argc; ++argv;
if (argc) {
if (chdir(*argv)) {
fprintf(stderr,"Unable to change to directory: %s\n%s",*argv,USAGE);
exit(1);
}
}
fread(&head,sizeof(head),1,in);
if ( head.h0 != 0x96 || head.h1 != 0x02 )
{
if ( debug ) printf("File does not have ATR signature\n");
return 1;
}
secsize=head.secsizelo+256*head.secsizehi;
seccount=head.seccountlo+256*head.seccounthi;
if ( debug ) printf("ATR image: %d sectors, %d bytes each\n",seccount,secsize);
{
struct stat buf;
size_t expected;
fstat(fileno(in),&buf);
if (((buf.st_size-ATRHEAD)%256)==128) ddshortinit=1;
if (debug) {
if (ddshortinit && secsize==256) printf("DD, but first 3 sectors SD\n");
else if (secsize==256) printf("DD, including first 3 sectors\n");
}
expected = sizeof(head) + seccount * secsize - ((secsize - 128) * 3 * ddshortinit);
if ( (size_t)buf.st_size != expected ) {
if ( debug ) {
int seccount_real;
printf("File size wrong; expected %u bytes, observed %u bytes\n",(unsigned int)expected,(unsigned int)buf.st_size);
seccount_real = (buf.st_size - sizeof(head)) / secsize;
if ( ddshortinit )
{
if ( (size_t)buf.st_size <= sizeof(head) + 3 * 128 ) seccount_real = (buf.st_size - sizeof(head)) / 128;
else seccount_real = 3 + (buf.st_size - sizeof(head) - 3*128)/secsize;
}
printf("Sectors expected: %d, observed: %d\n",seccount,seccount_real);
}
}
}
read_dir(in,root);
return(0);
}
/************************************************************************/
/* display_entry() */
/* Display the contents of one directory entry for debugging */
/************************************************************************/
void display_entry(int i,struct atari_dirent *f)
{
struct atari_dirent empty;
memset(&empty,0,sizeof(empty));
if ( memcmp(&empty,f,sizeof(empty)) == 0 )
{
printf("%2d: [entry is all zeros]\n",i);
return;
}
unsigned count = f->countlo + 256 * f->counthi;
unsigned start = f->startlo + 256 * f->starthi;
printf("%2d: %4d %4d %c%c%c%c%c%c%c%c.%c%c%c\n",i,count,start,
f->namelo[0],f->namelo[1],f->namelo[2],f->namelo[3],f->namelo[4],f->namelo[5],f->namelo[6],f->namelo[7],
f->namehi[0],f->namehi[1],f->namehi[2]);
}
/************************************************************************/
/* read_dir() */
/* Read the entries in a directory */
/* Call read_file() for files, read_dir() for subdirectories */
/************************************************************************/
void read_dir(FILE *in,int sector)
{
int i,j,k;
struct atari_dirent f;
FILE *out;
char name[13];
if ( debug ) printf("Parsing directory sector %d\n",sector);
for(i=0;i<64;++i) {
fseek(in,(long)SEEK(sector)+i*sizeof(f)+(secsize-128)*(i/8),SEEK_SET);
fread(&f,sizeof(f),1,in);
if ( debug ) display_entry(i,&f);
if ( fake ) continue;
if (!f.flag) /* No more entries */
{
if ( debug ) printf("Directory entry %d: zero indicates end of entries\n",i);
return;
}
if (f.flag&128) /* Deleted file */
{
if ( debug ) printf("Directory entry %d: deleted flag\n",i);
continue;
}
for(j=0;j<8;++j) {
name[j]=f.namelo[j];
if (name[j]==' ') break;
}
name[j]='.';
++j;
for(k=0;k<3;++k,++j) {
name[j]=f.namehi[k];
if (name[j]==' ') break;
}
name[j]=0;
if (name[j-1]=='.') name[j-1]=0;
if(lowcase) for(j=0;name[j];++j) name[j]=tolower(name[j]);
if (f.flag ==0x47 ) { /* Seems to work */
printf("Warning: File %s has flag bit 1 set--file ignored\n",name);
continue;
}
if (mydos && f.flag&16) { /* Subdirectory */
if (debug) printf("subdir %s (sec %d);\n",name,f.startlo+256*f.starthi);
#ifdef MSDOS
mkdir(name);
#else
mkdir(name,0777);
#endif
chdir(name);
read_dir(in,f.startlo+256*f.starthi);
chdir("..");
}
else {
out=fopen(name,"wb");
if (!out) {
fprintf(stderr,"Unable to create file: %s\n",name);
exit(2);
}
if (debug) printf("readfile %s (sec %d,count %d,flags %x);\n",name,f.startlo+256*f.starthi,f.countlo+256*f.counthi,f.flag);
read_file(name,in,out,f.startlo+256*f.starthi,f.countlo+256*f.counthi,i);
if (f.flag&32) { /* Make locked files read-only */
#ifdef MSDOS
chmod(name,S_IREAD);
#else
mode_t um;
um=umask(022);
umask(um);
chmod(name,0444 & ~um);
#endif
}
}
}
}
/************************************************************************/
/* read_file() */
/* Trace through the sector chain. */
/* Complications: Are the file numbers or high bits on the sector */
/* number? */
/* What about the last block code for 256-byte sectors? */
/************************************************************************/
void read_file(char *name,FILE *in,FILE *out,int sector,int count,int filenum)
{
unsigned char buf[256];
buf[secsize-1]=0;
while(count) {
if (sector<1) {
fprintf(stderr,"Corrupted file (invalid sector %d): %s\n",sector,name);
return;
}
if (buf[secsize-1]&128 && secsize==128) {
fprintf(stderr,"Corrupted file (unexpected EOF): %s\n",name);
return;
}
if (fseek(in,(long)SEEK(sector),SEEK_SET)) {
fprintf(stderr,"Corrupted file (next sector %d): %s\n",sector,name);
return;
}
fread(buf,secsize,1,in);
fwrite(buf,buf[secsize-1],1,out);
if (mydos) {
sector=buf[secsize-2]+buf[secsize-3]*256;
}
else { /* DOS 2.0 */
sector=buf[secsize-2]+(3&buf[secsize-3])*256;
if (buf[secsize-3]>>2 != filenum) {
fprintf(stderr,"Corrupted file (167: file number mismatch): %s\n",name);
return;
}
}
--count;
}
if (!(buf[secsize-1]&128) && secsize==128 && sector) {
fprintf(stderr,"Corrupted file (expected EOF, code %d, next sector %d): %s\n",buf[secsize-1],sector,name);
return;
}
fclose(out);
}

476
SRC/dcmtoatr-1.4.c Normal file
View File

@ -0,0 +1,476 @@
/*
** dcmtoatr.c -- written by Chad Wagner
**
** I just wanted to throw in some personal comments, I wanted to thank
** Preston Crow, for his work on portability issues, as well as some of
** the ideas he put into this program, Bob Puff, for his hard work on
** The Disk Communicator, an excellent means for transferring disk images,
** and I feel it is the de facto standard, and should remain as such, and
** Jason Duerstock, for writing DCMTODSK and his documents on the DCM
** format, which did help me resolve some of the things I wasn't aware of.
** I am sure there is a few others. Unfortunately I only got one response
** from Bob Puff, he was attempting to help, but I believe he is very busy
** person, and just didn't have the time.
**
** Revision History:
** 31 May 95 cmwagner@gate.net
** 1 Jun 95 cmwagner@gate.net
** added in some portability macros from dcm.c
** added in read_atari16() function from dcm.c
** wrote write_atari16() function
** did a general clean-up of the code
** 1 Jun 95 crow@cs.dartmouth.edu
** did a clean-up of the code, hopefully resolving any
** portability issues
** 2 Jun 95 cmwagner@gate.net and crow@cs.dartmouth.edu
** Allow for multi-file DCM files, after they've been
** combined into a single file
** 5 Jun 95 cmwagner@gate.net
** Fixed decoding routines to handle double density diskettes
** 26 Jun 95 cmwagner@gate.net
** Added in support for creating DCMTOXFD, default compile is
** for DCMTOATR
** 3 Sep 95 cmwagner@gate.net
** Added in -x switch, which creates an XFD image, instead of the
** default ATR image.
** added in soffset() routine, changed around the SOFFSET define,
** so that xfd images could be created, without compiling a
** different version.
** 26 Jun 95 modification is no longer relevant because of this
** modification.
** wrote some more comments, about what certain functions are doing,
** when they were created, and who wrote them.
** 28 Sep 95 lovegrov@student.umass.edu
** Fixed bug in soffset() function, apparently sector 4 would return
** an offset of 16 for ATR images or 0 for XFD images, which is not
** correct.
*/
/* Include files */
#include <stdio.h>
#include <string.h>
/* prototypes */
void decode_C1(void);
void decode_C3(void);
void decode_C4(void);
void decode_C6(void);
void decode_C7(void);
void decode_FA(void);
int read_atari16(FILE *);
void write_atari16(FILE *,int);
int read_offset(FILE *);
void read_sector(FILE *);
void write_sector(FILE *);
long soffset(void);
/*
** Portability macros
** 1 Jun 95 crow@cs.dartmouth.edu (Preston Crow)
*/
#if defined(__MSDOS) || defined(__MSDOS__) || defined(_MSDOS) || defined(_MSDOS_)
#define MSDOS /* icky, icky, icky! */
#endif
#ifndef SEEK_SET
#define SEEK_SET 0 /* May be missing from stdio.h */
#endif
/* version of this program, as seen in usage message */
#define VERSION "1.4"
/* Global variables */
FILE *fin,*fout;
unsigned int secsize;
unsigned short cursec=0,maxsec=0;
unsigned char createdisk=0,working=0,last=0,density,buf[256],atr=16;
int doprint=1; /* True for diagnostic output */
/*
** main()
*/
int main(int argc,char **argv)
{
unsigned char archivetype; /* Block type for first block */
unsigned char blocktype; /* Current block type */
unsigned char tmp; /* Temporary for read without clobber on eof */
unsigned char imgin[256],imgout[256]; /* file names */
unsigned char done=0; /* completion flag */
char *self; /* program name from argv[0] */
#ifdef MSDOS
if ((self = strrchr(argv[0],'\\')) == NULL)
#else
if ((self = strrchr(argv[0],'/')) == NULL)
#endif
{
self = argv[0];
}
else
self++; /* Skip the slash */
--argc;++argv; /* Don't look at the filename anymore */
/* Process switches */
if (argc) while (*argv[0]=='-') {
int nomore=0;
++argv[0]; /* skip the '-' */
while(*argv[0]) {
switch(*argv[0]) {
case '-':
nomore=1;
break;
case 'q':
case 'Q':
doprint = !doprint;
break;
case 'x':
case 'X':
atr = 16 - atr;
break;
default:
fprintf(stderr,"Unsupported switch: %c\n",*argv[0]);
fprintf(stderr,"%s "VERSION" by cmwagner@gate.net\n",self);
fprintf(stderr,"%s [-qx] input[.dcm] [output[.atr]]\n",self);
exit(1);
}
++argv[0]; /* We've processed this flag */
}
--argc;++argv; /* Done processing these flags */
if(nomore) break; /* Filename may begin with '-' */
}
if (argc<1 || argc>2) {
fprintf(stderr,"%s "VERSION" by cmwagner@gate.net\n",self);
fprintf(stderr,"%s [-qx] input[.dcm] [output[.atr]]\n",self);
exit(1);
}
strcpy(imgin,argv[0]);
if (strrchr(imgin,'.') == NULL)
strcat(imgin,".dcm");
if (argc==2)
strcpy(imgout,argv[1]);
else {
char *p;
strcpy(imgout,imgin);
if ((p = strrchr(imgout,'.')) != NULL)
*p = 0;
}
if (strrchr(imgout,'.') == NULL)
if (atr) {
strcat(imgout,".atr");
} else {
strcat(imgout,".xfd");
}
if ((fin = fopen(imgin,"rb")) == NULL) {
fprintf(stderr,"I couldn't open \"%s\" for reading.\n",imgin);
exit(1);
}
archivetype = blocktype = fgetc(fin);
switch(blocktype) {
case 0xF9:
case 0xFA:
break;
default:
fprintf(stderr,"0x%02X is an unknown header block.\n",blocktype);
exit(1);
}
if ((fout = fopen(imgout,"rb")) != NULL) {
fprintf(stderr,"I can't use \"%s\" for output, it already exists.\n",imgout);
exit(1);
} else {
fout = fopen(imgout,"wb");
}
rewind(fin);
do {
if(doprint) printf("\rCurrent sector: %4u",cursec);
#ifdef MSDOS
if (kbhit()) {
if (getch() == 27) {
fprintf(stderr,"\nProcessing terminated by user.\n");
exit(1);
}
}
#endif
if (feof(fin)) {
fflush(stdout); /* Possible buffered I/O confusion fix */
if ((!last) && (blocktype == 0x45) && (archivetype == 0xF9)) {
fprintf(stderr,"\nMulti-part archive error.\n");
fprintf(stderr,"To process these files, you must first combine the files into a single file.\n");
#ifdef MSDOS
fprintf(stderr,"\tCOPY /B file1.dcm+file2.dcm+file3.dcm newfile.dcm\n");
#else
fprintf(stderr,"\tcat file1.dcm file2.dcm file3.dcm > newfile.dcm\n");
#endif
}
else {
fprintf(stderr,"\nEOF before end block.\n");
}
exit(1);
}
tmp = fgetc(fin); /* blocktype is needed on EOF error--don't corrupt it */
if (feof(fin)) continue; /* Will abort on the check at the top of the loop */
blocktype = tmp;
switch(blocktype) {
case 0xF9:
case 0xFA:
/* New block */
decode_FA();
break;
case 0x45:
/* End block */
working=0;
if (last) {
if (doprint) printf("\r%s has been successfully decompressed.\n",imgout);
fclose(fin);
fclose(fout);
done=1; /* Normal exit */
}
break;
case 0x41:
case 0xC1:
decode_C1();
break;
case 0x43:
case 0xC3:
decode_C3();
break;
case 0x44:
case 0xC4:
decode_C4();
break;
case 0x46:
case 0xC6:
decode_C6();
break;
case 0x47:
case 0xC7:
decode_C7();
break;
default:
fprintf(stderr,"\n0x%02X is an unknown block type. File may be "
"corrupt.\n",blocktype);
exit(1);
} /* end case */
if ((blocktype != 0x45) && (blocktype != 0xFA) &&
(blocktype != 0xF9)) {
if (!(blocktype & 0x80)) {
cursec=read_atari16(fin);
fseek(fout,soffset(),SEEK_SET);
} else {
cursec++;
}
}
} while(!done); /* end do */
return(0); /* Should never be executed */
}
void decode_C1(void)
{
int secoff,tmpoff,c;
tmpoff=read_offset(fin);
c=fgetc(fin);
for (secoff=0; secoff<secsize; secoff++) {
buf[secoff]=c;
}
c=tmpoff;
for (secoff=0; secoff<tmpoff; secoff++) {
c--;
buf[c]=fgetc(fin);
}
write_sector(fout);
}
void decode_C3(void)
{
int secoff,tmpoff,c;
secoff=0;
do {
if (secoff)
tmpoff=read_offset(fin);
else
tmpoff=fgetc(fin);
for (; secoff<tmpoff; secoff++) {
buf[secoff]=fgetc(fin);
}
if (secoff == secsize)
break;
tmpoff=read_offset(fin);
c=fgetc(fin);
for (; secoff<tmpoff; secoff++) {
buf[secoff] = c;
}
} while(secoff < secsize);
write_sector(fout);
}
void decode_C4(void)
{
int secoff,tmpoff;
tmpoff=read_offset(fin);
for (secoff=tmpoff; secoff<secsize; secoff++) {
buf[secoff]=fgetc(fin);
}
write_sector(fout);
}
void decode_C6(void)
{
write_sector(fout);
}
void decode_C7(void)
{
read_sector(fin);
write_sector(fout);
}
void decode_FA(void)
{
unsigned char c;
if (working) {
fprintf(stderr,"\nTrying to start section but last section never had "
"an end section block.\n");
exit(1);
}
c=fgetc(fin);
density=((c & 0x70) >> 4);
last=((c & 0x80) >> 7);
switch(density) {
case 0:
maxsec=720;
secsize=128;
break;
case 2:
maxsec=720;
secsize=256;
break;
case 4:
maxsec=1040;
secsize=128;
break;
default:
fprintf(stderr,"\nDensity type is unknown, density type=%u\n",density);
exit(1);
}
if (createdisk == 0) {
createdisk = 1;
if (atr) {
/* write out atr header */
/* special code, 0x0296 */
write_atari16(fout,0x296);
/* image size (low) */
write_atari16(fout,(short)(((long)maxsec * secsize) >> 4));
/* sector size */
write_atari16(fout,secsize);
/* image size (high) */
write_atari16(fout,(short)(((long)maxsec * secsize) >> 20));
/* 8 bytes unused */
write_atari16(fout,0);
write_atari16(fout,0);
write_atari16(fout,0);
write_atari16(fout,0);
}
memset(buf,0,256);
for (cursec=0; cursec<maxsec; cursec++) {
fwrite(buf,secsize,1,fout);
}
}
cursec=read_atari16(fin);
fseek(fout,soffset(),SEEK_SET);
working=1;
}
/*
** read_atari16()
** Read a 16-bit integer with Atari byte-ordering.
** 1 Jun 95 crow@cs.dartmouth.edu (Preston Crow)
*/
int read_atari16(FILE *fin)
{
int ch_low,ch_high; /* fgetc() is type int, not char */
ch_low = fgetc(fin);
ch_high = fgetc(fin);
return(ch_low + 256*ch_high);
}
/*
** write_atari16()
** Write a 16-bit integer with Atari byte-ordering
** 1 Jun 95 cmwagner@gate.net (Chad Wagner)
*/
void write_atari16(FILE *fout,int n)
{
unsigned char ch_low,ch_high;
ch_low = (unsigned char)(n&0xff);
ch_high = (unsigned char)(n/256);
fputc(ch_low,fout);
fputc(ch_high,fout);
}
/*
** read_offset()
** Simple routine that 'reads' the offset from an RLE encoded block, if the
** offset is 0, then it returns it as 256.
** 5 Jun 95 cmwagner@gate.net (Chad Wagner)
*/
int read_offset(FILE *fin)
{
int ch; /* fgetc() is type int, not char */
ch = fgetc(fin);
if (ch == 0)
ch = 256;
return(ch);
}
/*
** read_sector()
** Simple routine that reads in a sector, based on it's location, and the
** sector size. Sectors 1-3, are 128 bytes, all other sectors are secsize.
** 5 Jun 95 cmwagner@gate.net (Chad Wagner)
*/
void read_sector(FILE *fin)
{
fread(buf,(cursec < 4 ? 128 : secsize),1,fin);
}
/*
** write_sector()
** Simple routine that writes in a sector, based on it's location, and the
** sector size. Sectors 1-3, are 128 bytes, all other sectors are secsize.
** 5 Jun 95 cmwagner@gate.net (Chad Wagner)
*/
void write_sector(FILE *fout)
{
fwrite(buf,(cursec < 4 ? 128 : secsize),1,fout);
}
/*
** soffset()
** calculates offsets within ATR or XFD images, for seeking.
** 28 Sep 95 lovegrov@student.umass.edu (Mike White)
*/
long soffset()
{
return (long)atr + (cursec < 4 ? ((long)cursec - 1) * 128 :
((long)cursec - 4) * secsize + 384);
}

1347
SRC/sio2linux-3.1.0.c Normal file

File diff suppressed because it is too large Load Diff

925
SRC/unix2atr-0.9.c Normal file
View File

@ -0,0 +1,925 @@
/************************************************************************/
/* unix2atr.c */
/* */
/* Preston Crow */
/* Public Domain */
/* */
/* Extract files from a Unix directory tree and create a MyDOS */
/* ATR-format disk image file. */
/* */
/* To-do for version 1.0: */
/* Eliminate any bugs */
/* Fix up the DOS 2.5 boot sectors. */
/* * Adjust for DOS.SYS if it is there for DOS2.0/2.5. */
/* */
/* To-do after 1.0: */
/* Support for DOS2.0D?? (256-byte sectors without MyDOS) */
/* * Is it any different from 2.0S? */
/* Support for SpartaDOS */
/* * This will probably have to be coded by someone else, */
/* as I'm not terribly interested in it. */
/* Support for more MyDOS versions */
/* * Simply a matter of detecting the version and writing */
/* out the right boot sectors. */
/* */
/* Version History */
/* */
/* 14 Mar 98 Version 0.9 Preston Crow <crow@cs.dartmouth.edu> */
/* */
/* Auto detect MyDOS version and use correct boot sectors. */
/* This needs to be updated for additional versions; */
/* currently only 4.50 and 4.53 are supported. */
/* */
/* Fixed segfault with directories with > 64 files. */
/* */
/* Fixed a bug in the writing of file data--it's right now */
/* */
/* Cleaned up the MyDOS boot sector data. It may still */
/* be sensitive to different versions of MyDOS. */
/* */
/* 24 Feb 98 Version 0.8 Preston Crow <crow@cs.dartmouth.edu> */
/* Add '-s' option to skip the first 720 sectors. */
/* This is useful to protect against corruption from */
/* files that do raw sector I/O, and to save room to write */
/* the DOS files. */
/* Even with this flag, DOS.SYS will be written at sector 4 */
/* */
/* VTOC is now generated for DOS2.5 enhanced density images. */
/* */
/* Boot sectors are correct for MyDOS and DOS2.0/2.5, */
/* except that they aren't adjusted to reflect the disk */
/* parameters or the existence of DOS.SYS. */
/* */
/* DOS.SYS, DUP.SYS, and AUTORUN.SYS will be the first */
/* files written if they are found. */
/* */
/* Directory sorting is case-insensitive if '-u' is */
/* specified, so the resulting image has a sorted directory. */
/* */
/* 21 Feb 98 Version 0.7 Preston Crow <crow@cs.dartmouth.edu> */
/* Bug fix: ATR "sector" count is now correct. */
/* (Why did they use such a strange formula?) */
/* Initial writing of boot sector and VTOC. */
/* */
/* Still no support for extended DOS 2.5 VTOC. */
/* */
/* Should include file numbers for non-MyDOS disks. */
/* */
/* 7 Feb 98 Version 0.6 Preston Crow <crow@cs.dartmouth.edu> */
/* Bug fixes */
/* */
/* 7 Jun 95 Version 0.5 Preston Crow <crow@cs.dartmouth.edu> */
/* Mostly works except: */
/* MyDos format is the only one that works. */
/* bitmaps aren't written to the image */
/* boot sectors aren't created */
/* */
/************************************************************************/
/************************************************************************/
/* Include files */
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <string.h>
#include <unistd.h>
/************************************************************************/
/* Macros and Constants */
/************************************************************************/
#define ATRHEAD 16
#define USAGE "unix2atr [-dumps] #sectors atarifile.atr [directory]\n Flags:\n\t-d Double density sectors\n\t-u Convert filenames to upper case\n\t-m MyDOS format disk image\n\t-s skip the first 720 sectors\n\t-p print debugging stuff\n"
/* SEEK: seek offset in the disk image file for a given sector number */
#define SEEK(n) (ATRHEAD + ((n<4)?((n-1)*128):(3*128+(n-4)*secsize)))
/************************************************************************/
/* Data types */
/************************************************************************/
struct atari_dirent {
unsigned char flag; /* set bits:
7->deleted
6->normal file
5->locked
4->MyDOS subdirectory
3->???
2->??? \ one for >720, one for >1024 ?
1->??? / all for MyDOS?
0->write open */
unsigned char countlo; /* Number of sectors in file */
unsigned char counthi;
unsigned char startlo; /* First sector in file */
unsigned char starthi;
char namelo[8];
char namehi[3];
};
struct atr_head {
unsigned char h0; /* 0x96 */
unsigned char h1; /* 0x02 */
unsigned char seccountlo;
unsigned char seccounthi;
unsigned char secsizelo;
unsigned char secsizehi;
unsigned char hiseccountlo;
unsigned char hiseccounthi;
unsigned char unused[8];
};
/************************************************************************/
/* Function Prototypes */
/************************************************************************/
void write_file(FILE *fin,int sector,int fileno); /* Write a file starting at the specified sector */
void write_dir(int sector); /* Write a directory */
void set_dos_version(char *fname); /* Determine which version of DOS.SYS it is */
int use_sector(void); /* Return a sector number that is free to use after marking it */
int use_8_sector(void); /* Get 8 sectors for a directory */
void write_boot(void); /* Write first 3 sectors */
void write_bitmaps(void); /* Write out the free bitmap */
int afnamecpy(char *an,const char *n);
/************************************************************************/
/* Global variables */
/************************************************************************/
int secsize;
int mydos=0;
int upcase=0;
int debug=0;
int seccount;
char bitmap[64*1024]; /* Free "bit" map */
int lastfree=4;
FILE *fout;
int rootdir; /* flag for sorting routine */
int dos=0; /* true if DOS.SYS is written */
int dosver=0; /* DOS.SYS version code */
/************************************************************************/
/* main() */
/* Process command line */
/* Open input .ATR file */
/* Interpret .ATR header */
/************************************************************************/
int main(int argc,char *argv[])
{
struct atr_head head;
int i;
unsigned char buf[256];
--argc; ++argv; /* Skip program name */
secsize=128;
/* Process flags */
while (argc) {
int done=0;
if (**argv=='-') {
++*argv;
while(**argv) {
switch(**argv) {
case 'd': /* DD */
secsize=256;
break;
case 'm': /* MyDos disk */
mydos=1;
break;
case '-': /* Last option */
done=1;
break;
case 'u': /* strupr names */
upcase=1;
break;
case 'p': /* debugging */
debug=1;
break;
case 's': /* skip early sectors */
lastfree=721;
break;
default:
fprintf(stderr,USAGE);
exit(1);
}
++*argv;
}
--argc; ++argv;
}
else break;
if (done) break;
}
if (argc<2) {
fprintf(stderr,USAGE);
exit(1);
}
/* Number of sectors */
seccount=atoi(*argv);
++argv;--argc;
if (seccount<368) {
fprintf(stderr,USAGE);
exit(1);
}
if ((seccount>1040||(seccount>720&&secsize==256))&&!mydos) {
fprintf(stderr,"Must use MyDos format if more than 1040 SD or 720 DD sectors\n");
exit(1);
}
/* Open output file */
fout=fopen(*argv,"wb");
if (!fout) {
fprintf(stderr,"Unable to open %s\n%s",*argv,USAGE);
exit(1);
}
--argc; ++argv;
/* Change directories? */
if (argc) {
if (chdir(*argv)) {
fprintf(stderr,"Unable to change to directory: %s\n%s",*argv,USAGE);
exit(1);
}
}
/* Initialize free sectors */
for(i=1;i<=seccount;++i) bitmap[i]=0;
for(i=seccount+1;i<64*1024;++i) bitmap[i]=1;
for(i=360;i<=368;++i) bitmap[i]=1;
for(i=0;i<=3;++i) bitmap[i]=1;
if (mydos) {
if (seccount>943+(secsize-128)*8) {
for(i=360-((seccount-943+(secsize*8-1))/(secsize*8));i<360;++i) bitmap[i]=1;
}
}
else {
for(i=1024;i<=seccount;++i) {
bitmap[i]=0; /* Don't use sectors 1024 or above */
}
}
if (!mydos) bitmap[720]=1;
/* Initialize ATR header */
head.h0=0x96;
head.h1=0x02;
head.secsizelo=secsize&0xff;
head.secsizehi=secsize/0x100;
{
unsigned long paragraphs;
paragraphs=(seccount-3)*(secsize/16) + 3*128/16;
head.seccountlo=paragraphs&0xff;
head.seccounthi=(paragraphs>>8)&0xff;
head.hiseccountlo=(paragraphs>>16)&0xff;
head.hiseccounthi=(paragraphs>>24)&0xff;
}
bzero(head.unused,sizeof(head.unused));
fwrite(&head,sizeof(head),1,fout);
/* Initialize sectors */
if (debug)printf("Creating %d %d-byte sectors (%d byte file)\n",seccount,secsize,SEEK(seccount)+secsize);
for(i=0;i<256;++i)buf[i]=0;
fseek(fout,SEEK(1),SEEK_SET);
for(i=1;i<=3;++i) fwrite(buf,128,1,fout);
for(i=4;i<=seccount;++i) fwrite(buf,secsize,1,fout);
write_dir(361);
write_boot();
write_bitmaps();
return(0);
}
/************************************************************************/
/* write_file() */
/* Write a file starting at the specified sector */
/************************************************************************/
void write_file(FILE *fin,int sector,int fileno)
{
unsigned char buf[256];
int i;
int sc=1;
unsigned char c;
c=fgetc(fin);
while (!feof(fin)) {
int nsec=0;
bzero(buf,secsize);
if (!mydos) buf[secsize-3]=(fileno<<2);
for(i=0;i<secsize-3;++i) {
buf[i]=c;
++buf[secsize-1];
c=fgetc(fin);
if (feof(fin)) break;
}
/* Write the sector */
if (!feof(fin)) {
nsec=use_sector();
++sc;
buf[secsize-2]=nsec%256;
buf[secsize-3]+=nsec/256; /* add to fileno */
}
fseek(fout,SEEK(sector),SEEK_SET);
fwrite(buf,secsize,1,fout);
if (nsec && buf[secsize-1]!=secsize-3) {
printf("Something is very wrong!\n");
printf("sector: %d\n",sector);
printf("nsec: %d\n",nsec);
printf("bytes: %d\n",buf[secsize-1]);
exit(1);
}
if (debug && 0) printf("\t\t\tsector %d -> %d\n",sector,nsec);
sector=nsec;
}
if (debug) printf("\t\tFile written, %d sectors\n",sc);
}
/************************************************************************/
/* mydirsort() */
/* */
/* Compare two directory entries for use in sorting. */
/* Essentially alphabetical ordering, except for special files that */
/* go first: DOS.SYS, DUP.SYS, and AUTORUN.SYS. */
/* */
/* Note that MyDOS 4.53 seems to use '*AR0' instead of 'AUTORUN.SYS' */
/* as the auto-loaded menu program. I don't know why. */
/************************************************************************/
int mydirsort(const struct dirent *const*a,const struct dirent *const*b)
{
char an[12],bn[12];
/* If the filename isn't valid for Atari, it's order doesn't matter */
if (!afnamecpy(an,(*a)->d_name)) return(0);
if (!afnamecpy(bn,(*b)->d_name)) return(0);
/* Place certain files first in the root directory */
if (rootdir) {
if (strcmp(an,"DOS SYS")==0) return(-1);
if (strcmp(bn,"DOS SYS")==0) return( 1);
if (strcmp(an,"DUP SYS")==0) return(-1);
if (strcmp(bn,"DUP SYS")==0) return( 1);
if (strcmp(an,"AUTORUN SYS")==0) return(-1);
if (strcmp(bn,"AUTORUN SYS")==0) return( 1);
if (strcmp(an,"AUTORUN AR0")==0) return(-1);
if (strcmp(bn,"AUTORUN AR0")==0) return( 1);
#if 1 /* force some reordering to make me happy */
if (strcmp(an,"FILES LST")==0) return(-1);
if (strcmp(bn,"FILES LST")==0) return( 1);
if (strcmp(an+2,bn+2)==0) return(strcmp(an,bn));
if (strcmp(an+2," ")==0) return( 1);
if (strcmp(bn+2," ")==0) return(-1);
#endif
}
/* Compare the converted filenames */
return(strcmp(an,bn));
}
/************************************************************************/
/* write_dir() */
/************************************************************************/
#define SENTRY(n) (secsize==128?n:(n/8)*8+n)
void write_dir(int sector)
{
struct direct **d;
int used;
int i;
int e;
int count;
int start;
char aname[12];
struct atari_dirent dir[128]; /* 64 + 64 DD wasted space */
int lastfreesave=0;
aname[11]=0;
for(i=0;i<8*256;++i) ((char *)dir)[i]=0;
rootdir=(sector==361);
i=scandir(".",&d,NULL,mydirsort);
used=0;
while (i) {
/* Process **d */
do {
struct stat sbuf;
int subdir;
/* Hidden files--ignore silently */
if ((*d)->d_name[0]=='.') break;
if (lastfreesave) {
lastfree=lastfreesave;
lastfreesave=0;
}
/* Convert name */
if (!afnamecpy(aname,(*d)->d_name)) {
printf("Warning: %s: Can't convert to Atari name\n",(*d)->d_name);
break;
}
/* If it's DOS.SYS, start at sector 4, even if we're reserving the first 720 sectors */
if (rootdir) {
if (strcmp(aname,"DOS SYS")==0) {
set_dos_version((*d)->d_name);
}
if (
strcmp(aname,"DOS SYS")==0 ||
strcmp(aname,"DUP SYS")==0 ||
strcmp(aname,"AUTORUN SYS")==0
) {
lastfreesave=lastfree;
lastfree=3;
}
}
/* Determine if it's a file or directory */
if (stat((*d)->d_name,&sbuf)) {
printf("Warning: %s: Can't stat file\n",(*d)->d_name);
break;
}
subdir=0;
if (!sbuf.st_mode&(S_IFDIR|S_IFREG)) {
printf("Warning: %s: Not a normal file or directory\n",(*d)->d_name);
break;
}
if (sbuf.st_mode&S_IFDIR) subdir=1;
if (subdir && !mydos) {
printf("Warning: %s/: Can't process subdirectory for standard Atari images\n",(*d)->d_name);
break;
}
/* Create the entry */
e=SENTRY(used);
if (used>63) {
printf("Warning: More than 64 files in this directory\n");
printf(" Additional files or subdirectories ignored\n");
return;
}
strcpy(dir[e].namelo,aname);
if (subdir) {
dir[e].flag=16;
count=8;
start=use_8_sector();
}
else {
dir[e].flag=0x46;
if (!sbuf.st_mode&0000200) dir[e].flag &=32; /* locked */
count=(sbuf.st_size+(secsize-3)-1)/(secsize-3);
start=use_sector();
}
dir[e].countlo=count&0xff;
dir[e].counthi=count/0x100;
dir[e].startlo=start&0xff;
dir[e].starthi=start/0x100;
/* Write the directory sector */
fseek(fout,SEEK(sector),SEEK_SET);
fwrite(dir,secsize,8,fout);
++used;
/* Write the file/subdir */
if (!subdir) {
FILE *fin;
fin=fopen((*d)->d_name,"rb");
if (!fin) {
printf("Warning: %s: Can't open file\n",(*d)->d_name);
break;
}
if (debug) printf("\tWriting file %s starting at sector %d\n",(*d)->d_name,start);
write_file(fin,start,used-1);
fclose(fin);
}
else {
if (debug) printf("\tWriting directory %s\n",(*d)->d_name);
if (chdir((*d)->d_name)) {
fprintf(stderr,"Unable to change to directory: %s\n",(*d)->d_name);
break;
}
write_dir(start);
chdir("..");
}
} while(0); /* for break */
free(*d);
++d;--i;
}
}
/************************************************************************/
/* set_dos_version() */
/* Read the first K of dos.sys and make an educated guess as to which */
/* version it is. */
/************************************************************************/
void set_dos_version(char *fname)
{
FILE *dosfile;
unsigned char buf[1024];
dosfile=fopen(fname,"rb");
if (!dosfile) return;
fread(buf,1,1024,dosfile);
fclose(dosfile);
if (buf[18]==0x08) dosver=450; /* MyDOS 4.50 */
if (buf[18]==0xFD) dosver=453; /* MyDOS 4.53/4 */
if (dosver==0) {
printf("Warning: Unable to determine DOS.SYS version\n");
}
dos=1;
}
/************************************************************************/
/* use_sector() */
/* Return a sector number that is free to use after marking it used. */
/************************************************************************/
int use_sector(void)
{
while (lastfree<=seccount&&bitmap[lastfree]) ++lastfree;
if (lastfree>seccount) {
fprintf(stderr,"Disk image full\n");
write_bitmaps();
exit(1);
}
bitmap[lastfree]=1;
return(lastfree);
}
/************************************************************************/
/* use_8_sector() */
/* Get 8 consecutive sectors for a directory */
/************************************************************************/
int use_8_sector(void)
{
int i=lastfree;
int j;
while ((bitmap[i+0]||bitmap[i+1]||bitmap[i+2]||bitmap[i+3]||
bitmap[i+4]||bitmap[i+5]||bitmap[i+6]||bitmap[i+7])
&& i+7<64*1024) ++i;
if (i+7<64*1024) {
for (j=0;j<8;++j) bitmap[i+j]=1;
return(i);
}
fprintf(stderr,"Disk image full--no room for directory\n");
write_bitmaps();
exit(1);
}
/************************************************************************/
/* write_boot() */
/* Write out the first 3 sectors */
/************************************************************************/
void write_boot(void)
{
/*
* Sectors 1 through 3
*
* Copied from a blank 720-sector DOS2.0S-formatted disk
* DOS2.5 generates the same data for 720- and 1040-sector disks.
*
* Writing DOS files may change some bytes, but I haven't checked
* to see which bytes change.
*/
char dos20init[128*3]={
0x00,0x03,0x00,0x07,0x40,0x15,0x4c,0x14,0x07,0x03,0x03,0x00,0x7c,0x1a,0x00,0x04,
0x00,0x7d,0xcb,0x07,0xac,0x0e,0x07,0xf0,0x36,0xad,0x12,0x07,0x85,0x43,0x8d,0x04,
0x03,0xad,0x13,0x07,0x85,0x44,0x8d,0x05,0x03,0xad,0x10,0x07,0xac,0x0f,0x07,0x18,
0xae,0x0e,0x07,0x20,0x6c,0x07,0x30,0x17,0xac,0x11,0x07,0xb1,0x43,0x29,0x03,0x48,
0xc8,0x11,0x43,0xf0,0x0e,0xb1,0x43,0xa8,0x20,0x57,0x07,0x68,0x4c,0x2f,0x07,0xa9,
0xc0,0xd0,0x01,0x68,0x0a,0xa8,0x60,0x18,0xa5,0x43,0x6d,0x11,0x07,0x8d,0x04,0x03,
0x85,0x43,0xa5,0x44,0x69,0x00,0x8d,0x05,0x03,0x85,0x44,0x60,0x8d,0x0b,0x03,0x8c,
0x0a,0x03,0xa9,0x52,0xa0,0x40,0x90,0x04,0xa9,0x57,0xa0,0x80,0x8d,0x02,0x03,0x8c,
0x03,0x03,0xa9,0x31,0xa0,0x0f,0x8d,0x00,0x03,0x8c,0x06,0x03,0xa9,0x03,0x8d,0xff,
0x12,0xa9,0x00,0xa0,0x80,0xca,0xf0,0x04,0xa9,0x01,0xa0,0x00,0x8d,0x09,0x03,0x8c,
0x08,0x03,0x20,0x59,0xe4,0x10,0x1d,0xce,0xff,0x12,0x30,0x18,0xa2,0x40,0xa9,0x52,
0xcd,0x02,0x03,0xf0,0x09,0xa9,0x21,0xcd,0x02,0x03,0xf0,0x02,0xa2,0x80,0x8e,0x03,
0x03,0x4c,0xa2,0x07,0xae,0x01,0x13,0xad,0x03,0x03,0x60,0xaa,0x08,0x14,0x0b,0xbe,
0x0a,0xcb,0x09,0x00,0x0b,0xa6,0x0b,0x07,0x85,0x44,0xad,0x0a,0x07,0x8d,0xd6,0x12,
0xad,0x0c,0x07,0x85,0x43,0xad,0x0d,0x07,0x85,0x44,0xad,0x0a,0x07,0x8d,0x0c,0x13,
0xa2,0x07,0x8e,0x0d,0x13,0x0e,0x0c,0x13,0xb0,0x0d,0xa9,0x00,0x9d,0x11,0x13,0x9d,
0x29,0x13,0x9d,0x31,0x13,0xf0,0x36,0xa0,0x05,0xa9,0x00,0x91,0x43,0xe8,0x8e,0x01,
0x03,0xa9,0x53,0x8d,0x02,0x03,0x20,0x53,0xe4,0xa0,0x02,0xad,0xea,0x02,0x29,0x20,
0xd0,0x01,0x88,0x98,0xae,0x0d,0x13,0x9d,0x11,0x13,0xa5,0x43,0x9d,0x29,0x13,0xa5,
0x44,0x9d,0x31,0x13,0x20,0x70,0x08,0x88,0xf0,0x03,0x20,0x70,0x08,0xca,0x10,0xb2,
0xac,0x09,0x07,0xa2,0x00,0xa9,0x00,0x88,0x10,0x01,0x98,0x9d,0x19,0x13,0x98,0x30,
0x0d,0xa5,0x43,0x9d,0x39,0x13,0xa5,0x44,0x9d,0x49,0x13,0x20,0x70,0x08,0xe8,0xe0,
0x10,0xd0,0xe2,0xa5,0x43,0x8d,0xe7,0x02,0xa5,0x44,0x8d,0xe8,0x02,0x4c,0x7e,0x08,
0x18,0xa5,0x43,0x69,0x80,0x85,0x43,0xa5,0x44,0x69,0x00,0x85,0x44,0x60,0xa0,0x7f
};
/*
* Sectors 1 through 3
*
* Rick D. <rldetlefsen@delphi.com> reported:
> MYDOS will store the same info in the boot sector as any other DOS. This is
> because the OS must use it to locate and load DOS into ram.
> Sector 1, byte offset 0-19 hold the useful info. b14=1=DOS;=0=No DOS,
> B15 & 16=sector to start of DOS, B18 & B19=DOS load address, B9= #file buffers,
> B10=drive bits, and B17=Disp to sector link(effectivly, disk density). The
> rest of the stuff is either in DOS(ramdisk config), or Mydos guese, i.e. >720
> sectors, or double sided.
*
*/
char mydosinit453[3*128]={
0x4d,0x03,0x00,0x07,0xe0,0x07,0x4c,0x14,0x07,0x03,0x09,0x01,0xe8,0x1b,0x02,0x04
,0x00,0xfd,0x0a,0x0b,0xac,0x12,0x07,0xad,0x13,0x07,0x20,0x58,0x07,0xad,0x10,0x07
,0xac,0x0f,0x07,0x18,0xae,0x0e,0x07,0xf0,0x1d,0x20,0x63,0x07,0x30,0x18,0xac,0x11
,0x07,0xb1,0x43,0x29,0xff,0x48,0xc8,0x11,0x43,0xf0,0x0e,0xb1,0x43,0x48,0x20,0x4d