ref: 94443daf8e248e65afc8d3f17f26efea22748b51
dir: /utils/format/format.c/
#include <lib9.h>
/*
* floppy types (all MFM encoding)
*/
typedef struct Type Type;
struct Type
{
char *name;
int bytes; /* bytes/sector */
int sectors; /* sectors/track */
int heads; /* number of heads */
int tracks; /* tracks/disk */
int media; /* media descriptor byte */
int cluster; /* default cluster size */
};
Type floppytype[] =
{
{ "3½HD", 512, 18, 2, 80, 0xf0, 1, },
{ "3½DD", 512, 9, 2, 80, 0xf9, 2, },
{ "5¼HD", 512, 15, 2, 80, 0xf9, 1, },
{ "5¼DD", 512, 9, 2, 40, 0xfd, 2, },
};
#define NTYPES (sizeof(floppytype)/sizeof(Type))
typedef struct Dosboot Dosboot;
struct Dosboot{
uchar magic[3]; /* really an xx86 JMP instruction */
uchar version[8];
uchar sectsize[2];
uchar clustsize;
uchar nresrv[2];
uchar nfats;
uchar rootsize[2];
uchar volsize[2];
uchar mediadesc;
uchar fatsize[2];
uchar trksize[2];
uchar nheads[2];
uchar nhidden[4];
uchar bigvolsize[4];
uchar driveno;
uchar reserved0;
uchar bootsig;
uchar volid[4];
uchar label[11];
uchar type[8];
};
#define PUTSHORT(p, v) { (p)[1] = (v)>>8; (p)[0] = (v); }
#define PUTLONG(p, v) { PUTSHORT((p), (v)); PUTSHORT((p)+2, (v)>>16); }
typedef struct Dosdir Dosdir;
struct Dosdir
{
uchar name[8];
uchar ext[3];
uchar attr;
uchar reserved[10];
uchar time[2];
uchar date[2];
uchar start[2];
uchar length[4];
};
#define DRONLY 0x01
#define DHIDDEN 0x02
#define DSYSTEM 0x04
#define DVLABEL 0x08
#define DDIR 0x10
#define DARCH 0x20
/*
* the boot program for the boot sector.
*/
uchar bootprog[512];
uchar bootprog1[16] =
{
0xEB, 0x3C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
uchar bootprog2[128] =
{
0xFA, 0xFC, 0x8C, 0xC8, 0x8E, 0xD8, 0x8E, 0xD0,
0xBC, 0x00, 0x7C, 0xBE, 0x77, 0x7C, 0xE8, 0x19,
0x00, 0x33, 0xC0, 0xCD, 0x16, 0xBB, 0x40, 0x00,
0x8E, 0xC3, 0xBB, 0x72, 0x00, 0xB8, 0x34, 0x12,
0x26, 0x89, 0x07, 0xEA, 0x00, 0x00, 0xFF, 0xFF,
0xEB, 0xD6, 0xAC, 0x0A, 0xC0, 0x74, 0x09, 0xB4,
0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2,
0xC3, 'N', 'o', 't', ' ', 'a', ' ', 'b',
'o', 'o', 't', 'a', 'b', 'l', 'e', ' ',
'd', 'i', 's', 'c', ' ', 'o', 'r', ' ',
'd', 'i', 's', 'c', ' ', 'e', 'r', 'r',
'o', 'r', '\r', '\n', 'P', 'r', 'e', 's',
's', ' ', 'a', 'l', 'm', 'o', 's', 't',
' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y',
' ', 't', 'o', ' ', 'r', 'e', 'b', 'o',
'o', 't', '.', '.', '.', 0x00, 0x00, 0x00,
};
uchar bootprog3[16] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA,
};
static void
mkbootprog(void)
{
int i;
for (i = 0; i < 512; i++)
bootprog[i] = 0;
for (i = 0; i < 16; i++)
bootprog[i+0x000] = bootprog1[i];
for (i = 0; i < 128; i++)
bootprog[i+0x03E] = bootprog2[i];
for (i = 0; i < 16; i++)
bootprog[i+0x1F0] = bootprog3[i];
}
char *dev;
int clustersize;
uchar *fat; /* the fat */
int fatbits;
int fatsecs;
int fatlast; /* last cluster allocated */
int clusters;
int fatsecs;
int volsecs;
uchar *root; /* first block of root */
int rootsecs;
int rootfiles;
int rootnext;
Type *t;
int fflag;
char file[64]; /* output file name */
char *bootfile;
char *type;
enum
{
Sof = 1, /* start of file */
Eof = 2, /* end of file */
};
void dosfs(int, char*, int, char*[]);
ulong clustalloc(int);
void addrname(uchar*, Dir*, ulong, char *);
int initfflag(void);
Tm *getlocaltime(void);
int openfloppy(char *);
void
usage(void)
{
fprint(2, "usage: format [-b bfile] [-c csize] [-df] [-l label] [-t type] file [args ...]\n");
exits("usage");
}
void
fatal(char *fmt, ...)
{
char err[128];
va_list arg;
va_start(arg, fmt);
vseprint(err, err+sizeof(err), fmt, arg);
va_end(arg);
fprint(2, "format: %s\n", err);
if(fflag && file[0])
remove(file);
exits(err);
}
void
main(int argc, char **argv)
{
int n, dos;
int cfd;
char buf[512];
char label[11];
char *a;
fflag = initfflag();
mkbootprog();
dos = 0;
type = 0;
clustersize = 0;
memmove(label, "CYLINDRICAL", sizeof(label));
ARGBEGIN {
case 'b':
bootfile = ARGF();
break;
case 'd':
dos = 1;
break;
case 'c':
clustersize = atoi(ARGF());
break;
case 'f':
fflag = 1;
break;
case 'l':
a = ARGF();
n = strlen(a);
if(n > sizeof(label))
n = sizeof(label);
memmove(label, a, n);
while(n < sizeof(label))
label[n++] = ' ';
break;
case 't':
type = ARGF();
break;
default:
usage();
} ARGEND
if(argc < 1)
usage();
dev = argv[0];
cfd = -1;
if(fflag == 0){
n = strlen(argv[0]);
if(n > 4 && strcmp(argv[0]+n-4, "disk") == 0)
*(argv[0]+n-4) = 0;
else if(n > 3 && strcmp(argv[0]+n-3, "ctl") == 0)
*(argv[0]+n-3) = 0;
sprint(buf, "%sctl", dev);
cfd = open(buf, ORDWR);
if(cfd < 0)
fatal("opening %s: %r", buf);
print("Formatting floppy %s\n", dev);
if(type)
sprint(buf, "format %s", type);
else
strcpy(buf, "format");
if(write(cfd, buf, strlen(buf)) < 0)
fatal("formatting tracks: %r");
}
if(dos)
dosfs(cfd, label, argc-1, argv+1);
if(cfd >= 0)
close(cfd);
exits(0);
}
void
dosfs(int cfd, char *label, int argc, char *argv[])
{
char r[16];
Dosboot *b;
uchar *buf;
Dir *d;
int n, fd, sysfd;
ulong length, x;
uchar *p;
print("Initialising MS-DOS file system\n");
if(fflag){
sprint(file, "%s", dev);
if ((fd = openfloppy(dev)) < 0)
fatal("create %s: %r", file);
t = floppytype;
if(type){
for(t = floppytype; t < &floppytype[NTYPES]; t++)
if(strcmp(type, t->name) == 0)
break;
if(t == &floppytype[NTYPES])
fatal("unknown floppy type %s", type);
}
length = t->bytes*t->sectors*t->heads*t->tracks;
}
else{
sprint(file, "%sdisk", dev);
fd = open(file, ORDWR);
if(fd < 0)
fatal("open %s: %r", file);
d = dirfstat(fd);
if(d == nil)
fatal("stat %s: %r", file);
length = d->length;
free(d);
t = 0;
seek(cfd, 0, 0);
n = read(cfd, file, sizeof(file)-1);
if(n < 0)
fatal("reading floppy type");
else {
file[n] = 0;
for(t = floppytype; t < &floppytype[NTYPES]; t++)
if(strcmp(file, t->name) == 0)
break;
if(t == &floppytype[NTYPES])
fatal("unknown floppy type %s", file);
}
}
print("floppy type %s, %d tracks, %d heads, %d sectors/track, %d bytes/sec\n",
t->name, t->tracks, t->heads, t->sectors, t->bytes);
if(clustersize == 0)
clustersize = t->cluster;
clusters = length/(t->bytes*clustersize);
if(clusters < 4087)
fatbits = 12;
else
fatbits = 16;
volsecs = length/t->bytes;
fatsecs = (fatbits*clusters + 8*t->bytes - 1)/(8*t->bytes);
rootsecs = volsecs/200;
rootfiles = rootsecs * (t->bytes/sizeof(Dosdir));
buf = malloc(t->bytes);
if(buf == 0)
fatal("out of memory");
/*
* write bootstrap & parameter block
*/
if(bootfile){
if((sysfd = open(bootfile, OREAD)) < 0)
fatal("open %s: %r", bootfile);
if(read(sysfd, buf, t->bytes) < 0)
fatal("read %s: %r", bootfile);
close(sysfd);
}
else
memmove(buf, bootprog, sizeof(bootprog));
b = (Dosboot*)buf;
b->magic[0] = 0xEB;
b->magic[1] = 0x3C;
b->magic[2] = 0x90;
memmove(b->version, "Plan9.00", sizeof(b->version));
PUTSHORT(b->sectsize, t->bytes);
b->clustsize = clustersize;
PUTSHORT(b->nresrv, 1);
b->nfats = 2;
PUTSHORT(b->rootsize, rootfiles);
if(volsecs < (1<<16)){
PUTSHORT(b->volsize, volsecs);
}
PUTLONG(b->bigvolsize, volsecs);
b->mediadesc = t->media;
PUTSHORT(b->fatsize, fatsecs);
PUTSHORT(b->trksize, t->sectors);
PUTSHORT(b->nheads, t->heads);
PUTLONG(b->nhidden, 0);
b->driveno = 0;
b->bootsig = 0x29;
x = time(0);
PUTLONG(b->volid, x);
memmove(b->label, label, sizeof(b->label));
sprint(r, "FAT%d ", fatbits);
memmove(b->type, r, sizeof(b->type));
buf[t->bytes-2] = 0x55;
buf[t->bytes-1] = 0xAA;
if(seek(fd, 0, 0) < 0)
fatal("seek to boot sector: %r\n");
if(write(fd, buf, t->bytes) != t->bytes)
fatal("writing boot sector: %r");
free(buf);
/*
* allocate an in memory fat
*/
fat = malloc(fatsecs*t->bytes);
if(fat == 0)
fatal("out of memory");
memset(fat, 0, fatsecs*t->bytes);
fat[0] = t->media;
fat[1] = 0xff;
fat[2] = 0xff;
if(fatbits == 16)
fat[3] = 0xff;
fatlast = 1;
if (seek(fd, 2*fatsecs*t->bytes, 1) < 0)
fatal("seek to 2 fats: %r"); /* 2 fats */
/*
* allocate an in memory root
*/
root = malloc(rootsecs*t->bytes);
if(root == 0)
fatal("out of memory");
memset(root, 0, rootsecs*t->bytes);
if (seek(fd, rootsecs*t->bytes, 1) < 0)
fatal("seek to root: %r"); /* rootsecs */
/*
* Now positioned at the Files Area.
* If we have any arguments, process
* them and write out.
*/
for(p = root; argc > 0; argc--, argv++, p += sizeof(Dosdir)){
if(p >= (root+(rootsecs*t->bytes)))
fatal("too many files in root");
/*
* Open the file and get its length.
*/
if((sysfd = open(*argv, OREAD)) < 0)
fatal("open %s: %r", *argv);
d = dirfstat(sysfd);
if(d == nil)
fatal("stat %s: %r", *argv);
print("Adding file %s, length %lld\n", *argv, d->length);
length = d->length;
if(length){
/*
* Allocate a buffer to read the entire file into.
* This must be rounded up to a cluster boundary.
*
* Read the file and write it out to the Files Area.
*/
length += t->bytes*clustersize - 1;
length /= t->bytes*clustersize;
length *= t->bytes*clustersize;
if((buf = malloc(length)) == 0)
fatal("out of memory");
if(read(sysfd, buf, d->length) < 0)
fatal("read %s: %r", *argv);
memset(buf+d->length, 0, length-d->length);
/* if(write(fd, buf, length) < 0) */
if (write(fd, buf, length) != length)
fatal("write %s: %r", *argv);
free(buf);
close(sysfd);
/*
* Allocate the FAT clusters.
* We're assuming here that where we
* wrote the file is in sync with
* the cluster allocation.
* Save the starting cluster.
*/
length /= t->bytes*clustersize;
x = clustalloc(Sof);
for(n = 0; n < length-1; n++)
clustalloc(0);
clustalloc(Eof);
}
else
x = 0;
/*
* Add the filename to the root.
*/
addrname(p, d, x, *argv);
free(d);
}
/*
* write the fats and root
*/
if (seek(fd, t->bytes, 0) < 0)
fatal("seek to fat1: %r");
/* if(write(fd, fat, fatsecs*t->bytes) < 0) */
if (write(fd, fat, fatsecs*t->bytes) != fatsecs*t->bytes)
fatal("writing fat #1: %r");
/* if(write(fd, fat, fatsecs*t->bytes) < 0) */
if (write(fd, fat, fatsecs*t->bytes) != fatsecs*t->bytes)
fatal("writing fat #2: %r");
/* if(write(fd, root, rootsecs*t->bytes) < 0) */
if (write(fd, root, rootsecs*t->bytes) != rootsecs*t->bytes)
fatal("writing root: %r");
if(fflag){
if (seek(fd, t->bytes*t->sectors*t->heads*t->tracks-1, 0) < 0)
/* fatal("seek to 9: %r") */ {}
if (write(fd, "9", 1) != 1)
/* fatal("writing 9: %r") */ {}
}
}
/*
* allocate a cluster
*/
ulong
clustalloc(int flag)
{
ulong o, x;
if(flag != Sof){
x = (flag == Eof) ? 0xffff : (fatlast+1);
if(fatbits == 12){
x &= 0xfff;
o = (3*fatlast)/2;
if(fatlast & 1){
fat[o] = (fat[o]&0x0f) | (x<<4);
fat[o+1] = (x>>4);
} else {
fat[o] = x;
fat[o+1] = (fat[o+1]&0xf0) | ((x>>8) & 0x0F);
}
} else {
o = 2*fatlast;
fat[o] = x;
fat[o+1] = x>>8;
}
}
if(flag == Eof)
return 0;
else
return ++fatlast;
}
void
putname(char *p, Dosdir *d)
{
int i;
char *q;
q = strrchr(p, '/');
if (q)
p = q+1;
q = strrchr(p, '\\');
if (q)
p = q+1;
memset(d->name, ' ', sizeof d->name+sizeof d->ext);
for(i = 0; i< sizeof(d->name); i++){
if(*p == 0 || *p == '.')
break;
d->name[i] = toupper(*p++);
}
p = strrchr(p, '.');
if(p){
for(i = 0; i < sizeof d->ext; i++){
if(*++p == 0)
break;
d->ext[i] = toupper(*p);
}
}
}
void
puttime(Dosdir *d)
{
Tm *t = getlocaltime();
ushort x;
x = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
d->time[0] = x;
d->time[1] = x>>8;
x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
d->date[0] = x;
d->date[1] = x>>8;
}
void
addrname(uchar *entry, Dir *dir, ulong start, char *nm)
{
Dosdir *d;
d = (Dosdir*)entry;
/* putname(dir->name, d); */
putname(nm, d);
d->attr = DRONLY;
puttime(d);
d->start[0] = start;
d->start[1] = start>>8;
d->length[0] = dir->length;
d->length[1] = dir->length>>8;
d->length[2] = dir->length>>16;
d->length[3] = dir->length>>24;
}