char *dev;
int clustersize;
uchar *fat; /* the fat */
int fatbits;
int fatsecs;
int fatlast; /* last cluster allocated */
int clusters;
int fatsecs;
vlong volsecs;
uchar *root; /* first block of root */
int rootsecs;
int rootfiles;
int rootnext;
int nresrv = 1;
int chatty;
vlong length;
Type *t;
int fflag;
int hflag;
int xflag;
char *file;
char *pbs;
char *type;
char *bootfile;
int dos;
enum
{
Sof = 1, /* start of file */
Eof = 2, /* end of file */
};
/*
* Look for a partition table on sector 1, as would be the
* case if we were erroneously formatting 9fat without -r 2.
* If it's there and nresrv is not big enough, complain and exit.
* I've blown away my partition table too many times.
*/
void
sanitycheck(Disk *disk)
{
char buf[512];
int bad;
if(xflag)
return;
bad = 0;
if(dos && nresrv < 2 && seek(disk->fd, disk->secsize, 0) == disk->secsize
&& read(disk->fd, buf, sizeof(buf)) >= 5 && strncmp(buf, "part ", 5) == 0) {
fprint(2,
"there's a plan9 partition on the disk\n"
"and you didn't specify -r 2 (or greater).\n"
"either specify -r 2 or -x to disable this check.\n");
bad = 1;
}
if(disk->type == Tsd && disk->offset == 0LL) {
fprint(2,
"you're attempting to format your disk (/dev/sdXX/data)\n"
"rather than a partition like /dev/sdXX/9fat;\n"
"this is likely a mistake. specify -x to disable this check.\n");
bad = 1;
}
if(bad)
exits("failed disk sanity check");
}
/*
* Return the BIOS drive number for the disk.
* 0x80 is the first fixed disk, 0x81 the next, etc.
* We map sdC0=0x80, sdC1=0x81, sdD0=0x82, sdD1=0x83
*/
int
getdriveno(Disk *disk)
{
char buf[64], *p;
if(disk->type != Tsd)
return 0x80; /* first hard disk */
/*
* The name is of the format #SsdC0/foo
* or /dev/sdC0/foo.
* So that we can just look for /sdC0, turn
* #SsdC0/foo into #/sdC0/foo.
*/
if(buf[0] == '#' && buf[1] == 'S')
buf[1] = '/';
long
writen(int fd, void *buf, long n)
{
long m, tot;
/* write 8k at a time, to be nice to the disk subsystem */
for(tot=0; tot<n; tot+=m){
m = n - tot;
if(m > 8192)
m = 8192;
if(write(fd, (uchar*)buf+tot, m) != m)
break;
}
return tot;
}
int
defcluster(vlong n)
{
int i;
i = n / 32768;
if(i <= 1)
return 1;
if(i >= 128)
return 128;
i--;
i |= i >> 1;
i |= i >> 2;
i |= i >> 4;
return i+1;
}
void
dosfs(int dofat, int dopbs, Disk *disk, char *label, int argc, char *argv[], int commit)
{
char r[16];
Dosboot *b;
uchar *buf, *pbsbuf, *p;
Dir *d;
int i, data, newclusters, npbs, n, sysfd;
ulong x;
vlong length, secsize;
if(dofat == 0 && dopbs == 0)
return;
for(t = floppytype; t < &floppytype[NTYPES]; t++)
if(strcmp(type, t->name) == 0)
break;
if(t == &floppytype[NTYPES])
fatal("unknown floppy type %s", type);
/*
* the number of fat bits depends on how much disk is left
* over after you subtract out the space taken up by the fat tables.
* try both. what a crock.
*/
fatbits = 12;
Tryagain:
if(fatbits == 32)
nresrv++; /* for FatInfo */
volsecs = length/secsize;
/*
* here's a crock inside a crock. even having fixed fatbits,
* the number of fat sectors depends on the number of clusters,
* but of course we don't know yet. maybe iterating will get us there.
* or maybe it will cycle.
*/
clusters = 0;
for(i=0;; i++){
fatsecs = (fatbits*clusters + 8*secsize - 1)/(8*secsize);
rootsecs = volsecs/200;
rootfiles = rootsecs * (secsize/DOSDIRSIZE);
if(rootfiles > 512){
rootfiles = 512;
rootsecs = rootfiles/(secsize/DOSDIRSIZE);
}
if(fatbits == 32){
rootsecs -= (rootsecs % clustersize);
if(rootsecs <= 0)
rootsecs = clustersize;
rootfiles = rootsecs * (secsize/DOSDIRSIZE);
}
data = nresrv + 2*fatsecs + (rootfiles*DOSDIRSIZE + secsize-1)/secsize;
newclusters = 2 + (volsecs - data)/clustersize;
if(newclusters == clusters)
break;
clusters = newclusters;
if(i > 10)
fatal("can't decide how many clusters to use (%d? %d?)",
clusters, newclusters);
if(chatty) print("clusters %d\n", clusters);
}
/*
* allocate an in memory root
*/
root = malloc(rootsecs*secsize);
if(root == 0)
fatal("out of memory");
memset(root, 0, rootsecs*secsize);
if(seek(disk->wfd, rootsecs*secsize, 1) < 0) /* rootsecs */
fatal("seek to files: %r");
if(chatty) print("files @%lluX\n", seek(disk->wfd, 0LL, 1));
/*
* Now positioned at the Files Area.
* If we have any arguments, process
* them and write out.
*/
for(p = root; argc > 0; argc--, argv++, p += DOSDIRSIZE){
if(p >= (root+(rootsecs*secsize)))
fatal("too many files in root");
/*
* Open the file and get its length.
*/
if((sysfd = open(*argv, OREAD)) < 0)
fatal("open %s: %r", *argv);
if((d = dirfstat(sysfd)) == nil)
fatal("stat %s: %r", *argv);
if(d->length > 0xFFFFFFFFU)
fatal("file %s too big\n", *argv, d->length);
if(commit)
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 += secsize*clustersize - 1;
length /= secsize*clustersize;
length *= secsize*clustersize;
if((buf = malloc(length)) == 0)
fatal("out of memory");
/*
* 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 /= secsize*clustersize;
x = clustalloc(Sof);
for(n = 0; n < length-1; n++)
clustalloc(0);
clustalloc(Eof);
}
else
x = 0;
/*
* Add the filename to the root.
*/
fprint(2, "add %s at clust %lux\n", d->name, x);
p = addrname(p, d, *argv, x);
free(d);
}
/*
* write the fats and root
*/
if(commit) {
if(fatbits == 32){
Fatinfo *fi;
fi = malloc(secsize);
if(fi == nil)
fatal("out of memory");
if(flag == Eof)
return 0;
else{
++fatlast;
if(fatlast >= clusters)
sysfatal("data does not fit on disk (%d %d)", fatlast, clusters);
return fatlast;
}
}