944 lines · 20.7 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <ctype.h>#include <disk.h> /* *  disk types */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, }, { "3½QD",	512, 36, 2, 80, 0xf9, 2, },	/* invented */ { "5¼HD",	512, 15,  2, 80, 0xf9, 1, }, { "5¼DD",	512,  9,  2, 40, 0xfd, 2, }, { "hard",	512,  0,  0, 0, 0xf8, 4, },}; #define NTYPES (sizeof(floppytype)/sizeof(Type)) typedef struct Dosboot	Dosboot;struct Dosboot{	uchar	magic[3];	/* really an x86 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];	union{		struct{			uchar	driveno16;			uchar	reserved16;			uchar	bootsig;			uchar	volid[4];			uchar	label[11];			uchar	type[8];		};		struct{			uchar	fatsize32[4];			uchar	extflags[2];			uchar	extver[2];			uchar	rootclust[4];			uchar	fsinfo[2];			uchar	bootblk[2];			uchar	reserved32[12];			uchar	driveno32;		};	};};#define	PUTSHORT(p, v) { (p)[1] = (v)>>8; (p)[0] = (v); }#define	PUTLONG(p, v) { PUTSHORT((p), (v)); PUTSHORT((p)+2, (v)>>16); }#define	GETSHORT(p)	(((p)[1]<<8)|(p)[0])#define	GETLONG(p)	(((ulong)GETSHORT(p+2)<<16)|(ulong)GETSHORT(p)) typedef struct Fsinfo	Fsinfo;struct Fsinfo{	uchar	siga[4];		/* 0x41615252  RRaA */	uchar	res[480];	uchar	sigb[4];		/* 0x61417272  rrAa */	uchar	free[4];	uchar	nxtfree[4];	uchar	res1[12];	uchar	sigc[4];}; typedef struct Dosdir	Dosdir;struct Dosdir{	uchar	name[8];	uchar	ext[3];	uchar	attr;	uchar	reserved[1];	uchar	ctime[3];		/* creation time */	uchar	cdate[2];		/* creation date */	uchar	adate[2];		/* last access date */	uchar	hstart[2];		/* high bits of start for fat32 */	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. */int nbootprog = 188;	/* no. of bytes of boot program, including the first 0x3E */uchar bootprog[512] ={[0x000]	0xEB, 0x3C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,[0x03E] 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,[0x1F0]	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA,}; Fsinfo fsinfo ={.siga	= {'R', 'R', 'a', 'A', },.sigb	= {'r', 'r', 'A', 'a', },.free	= {0xff, 0xff, 0xff, 0xff, },.nxtfree	= {0xff, 0xff, 0xff, 0xff, },.sigc	= {0x00, 0x00, 0x55, 0xaa, },}; char *dev;int clustersize;uchar *fat;	/* the fat */int fatbits;uint fatsecs;uint fatlast;	/* last cluster allocated */uvlong clusters;uvlong volsecs;uchar *root;	/* first block of root */int rootsecs;uvlong 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 */}; void	dosfs(int, int, Disk*, char*, int, char*[], int);ulong	clustalloc(int);void	addrname(uchar*, Dir*, char*, ulong);void	sanitycheck(Disk*); #define	chat(...)	if(chatty) fprint(2, __VA_ARGS__); else {} voidusage(void){	fprint(2, "usage: disk/format [-df] [-b bootblock] [-c csize] "		"[-l label] [-r nresrv] [-t type] disk [files ...]\n");	exits("usage");} voidfatal(char *fmt, ...){	char err[128];	va_list arg; 	va_start(arg, fmt);	vsnprint(err, sizeof(err), fmt, arg);	va_end(arg);	fprint(2, "format: %s\n", err);	if(fflag && file)		remove(file);	exits(err);}#pragma	varargck	argpos	fatal	1 voidmain(int argc, char **argv){	int fd, n, writepbs;	char buf[512], label[11];	char *a;	Disk *disk; 	dos = 0;	type = nil;	clustersize = 0;	writepbs = 0;	memmove(label, "CYLINDRICAL", sizeof(label));	ARGBEGIN {	case 'b':		pbs = EARGF(usage());		writepbs = 1;		break;	case 'c':		clustersize = atoi(EARGF(usage()));		break;	case 'd':		dos = 1;		writepbs = 1;		break;	case 'f':		fflag = 1;		break;	case 'l':		a = EARGF(usage());		n = strlen(a);		if(n > sizeof(label))			n = sizeof(label);		memmove(label, a, n);		while(n < sizeof(label))			label[n++] = ' ';		break;	case 'r':		nresrv = atoi(EARGF(usage()));		break;	case 't':		type = EARGF(usage());		break;	case 'v':		chatty++;		break;	case 'x':		xflag = 1;		break;	default:		usage();	} ARGEND 	if(argc < 1)		usage(); 	disk = opendisk(argv[0], 0, 0);	if(disk == nil) {		if(fflag) {			if((fd = create(argv[0], ORDWR, 0666)) >= 0) {				file = argv[0];				close(fd);				disk = opendisk(argv[0], 0, 0);			}		}	}	if(disk == nil)		fatal("opendisk: %r"); 	if(disk->type == Tfile)		fflag = 1; 	if(type == nil) {		switch(disk->type){		case Tfile:			type = "3½HD";			break;		case Tfloppy:			seek(disk->ctlfd, 0, 0);			n = read(disk->ctlfd, buf, 10);			if(n <= 0 || n >= 10)				fatal("reading floppy type");			buf[n] = 0;			type = strdup(buf);			if(type == nil)				fatal("out of memory");			break;		case Tsd:			type = "hard";			break;		default:			type = "unknown";			break;		}	} 	if(!fflag && disk->type == Tfloppy)		if(fprint(disk->ctlfd, "format %s", type) < 0)			fatal("formatting floppy as %s: %r", type); 	if(disk->type != Tfloppy)		sanitycheck(disk); 	/* check that everything will succeed */	dosfs(dos, writepbs, disk, label, argc-1, argv+1, 0); 	/* commit */	dosfs(dos, writepbs, disk, label, argc-1, argv+1, 1); 	print("used %lld bytes\n", fatlast*clustersize*disk->secsize);	exits(0);} /* * 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. */voidsanitycheck(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 */voidputdriveno(Disk *disk, uchar media, uchar *driveno){	char buf[64], *p; 	if(media != 0xF8){		*driveno = 0;		return;	}	buf[0] = 0;	*driveno = 0x80;	/* first hard disk */	if(disk->type != Tsd && fd2path(disk->fd, buf, sizeof(buf)) < 0)		buf[0] = 0; 	/*	 * 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] = '/'; 	for(p=buf; *p; p++)		if(p[0] == 's' && p[1] == 'd' && (p[2]=='C' || p[2]=='D') &&		    (p[3]=='0' || p[3]=='1'))			*driveno = 0x80 + (p[2]-'C')*2 + (p[3]-'0');} longwriten(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;} intpwr2chk(uvlong u, uvlong max){	uvlong i; 	if(u > max)		return -1;	for(i = 0; i < 8*sizeof i; i++)		if((u & ~(1ull<<i)) == 0)			return 0;	return -1;} voidfatchecks(Disk *d){	uvlong secsize; 	secsize = d->secsize; 	/* fat 1.03 restrictions */	if(pwr2chk(secsize, 4096) || secsize < 512)		fatal("illegal sector size");	if(secsize * clustersize > 32*1024)		fatal("secsize * clustersize must be <= 32k");	if(pwr2chk(clustersize, 64) == -1)		fatal("illegal clustersize");	if(nresrv == 0)		fatal("nresrv may not be 0"); 	if(xflag)			/* botch; other xflag will have exited */		return;	if(clustersize > 32)		fatal("clustersize should be <= 32; use -x to allow");} #define Rskip	nresrv voidwfsinfo(Disk *d, Dosboot *b, uvlong secsize, int bits){	uvlong off; 	if(bits != 32)		return;	PUTLONG(fsinfo.free, clusters - fatlast - 1);	PUTLONG(fsinfo.nxtfree, fatlast+1);	off = GETSHORT(b->fsinfo);	off *= secsize;	chat("fsinfo at %lld size %d\n", off, sizeof fsinfo);	if(pwrite(d->wfd, &fsinfo, sizeof fsinfo, off) != sizeof fsinfo)		fatal("pwrite fsinfo: %r");} voiddosfs(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, npbs, n, sysfd;	ulong x;	uvlong length, data, secsize, newclusters, bits, rootclust; 	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); 	if(t->sectors == 0 && strcmp(type, "hard") == 0) {		t->sectors = disk->s;		t->heads = disk->h;		t->tracks = disk->c;	} 	if(t->sectors == 0 && dofat)		fatal("cannot format fat with type %s: geometry unknown\n", type); 	if(fflag){		disk->size = (uvlong)t->bytes*t->sectors*t->heads*t->tracks;		disk->secsize = t->bytes;		disk->secs = disk->size / disk->secsize;	}	fatchecks(disk); 	secsize = disk->secsize;	length = disk->size;

Lines 1–500 of 944.