xref: /plan9/sys/src/cmd/disk/format.c (revision 9f2726c34299ea5a81cda1b22133dd5a4b421e04)
1bd389b36SDavid du Colombier #include <u.h>
2bd389b36SDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <ctype.h>
47dd7cddfSDavid du Colombier #include <disk.h>
5bd389b36SDavid du Colombier 
6bd389b36SDavid du Colombier /*
77dd7cddfSDavid du Colombier  *  disk types (all MFM encoding)
8bd389b36SDavid du Colombier  */
9bd389b36SDavid du Colombier typedef struct Type	Type;
10bd389b36SDavid du Colombier struct Type
11bd389b36SDavid du Colombier {
12bd389b36SDavid du Colombier 	char	*name;
13bd389b36SDavid du Colombier 	int	bytes;		/* bytes/sector */
14bd389b36SDavid du Colombier 	int	sectors;	/* sectors/track */
15bd389b36SDavid du Colombier 	int	heads;		/* number of heads */
16bd389b36SDavid du Colombier 	int	tracks;		/* tracks/disk */
17bd389b36SDavid du Colombier 	int	media;		/* media descriptor byte */
18bd389b36SDavid du Colombier 	int	cluster;	/* default cluster size */
19bd389b36SDavid du Colombier };
20bd389b36SDavid du Colombier Type floppytype[] =
21bd389b36SDavid du Colombier {
22bd389b36SDavid du Colombier  { "3½HD",	512, 18,  2, 80, 0xf0, 1, },
23bd389b36SDavid du Colombier  { "3½DD",	512,  9,  2, 80, 0xf9, 2, },
249a747e4fSDavid du Colombier  { "3½QD",	512, 36, 2, 80, 0xf9, 2, },	/* invented */
25bd389b36SDavid du Colombier  { "5¼HD",	512, 15,  2, 80, 0xf9, 1, },
26bd389b36SDavid du Colombier  { "5¼DD",	512,  9,  2, 40, 0xfd, 2, },
277dd7cddfSDavid du Colombier  { "hard",	512,  0,  0, 0, 0xf8, 4, },
28bd389b36SDavid du Colombier };
297dd7cddfSDavid du Colombier 
30bd389b36SDavid du Colombier #define NTYPES (sizeof(floppytype)/sizeof(Type))
31bd389b36SDavid du Colombier 
32bd389b36SDavid du Colombier typedef struct Dosboot	Dosboot;
33bd389b36SDavid du Colombier struct Dosboot{
347dd7cddfSDavid du Colombier 	uchar	magic[3];	/* really an x86 JMP instruction */
35bd389b36SDavid du Colombier 	uchar	version[8];
36bd389b36SDavid du Colombier 	uchar	sectsize[2];
37bd389b36SDavid du Colombier 	uchar	clustsize;
38bd389b36SDavid du Colombier 	uchar	nresrv[2];
39bd389b36SDavid du Colombier 	uchar	nfats;
40bd389b36SDavid du Colombier 	uchar	rootsize[2];
41bd389b36SDavid du Colombier 	uchar	volsize[2];
42bd389b36SDavid du Colombier 	uchar	mediadesc;
43bd389b36SDavid du Colombier 	uchar	fatsize[2];
44bd389b36SDavid du Colombier 	uchar	trksize[2];
45bd389b36SDavid du Colombier 	uchar	nheads[2];
46bd389b36SDavid du Colombier 	uchar	nhidden[4];
47bd389b36SDavid du Colombier 	uchar	bigvolsize[4];
48bd389b36SDavid du Colombier 	uchar	driveno;
49bd389b36SDavid du Colombier 	uchar	reserved0;
50bd389b36SDavid du Colombier 	uchar	bootsig;
51bd389b36SDavid du Colombier 	uchar	volid[4];
52bd389b36SDavid du Colombier 	uchar	label[11];
53219b2ee8SDavid du Colombier 	uchar	type[8];
54bd389b36SDavid du Colombier };
55bd389b36SDavid du Colombier #define	PUTSHORT(p, v) { (p)[1] = (v)>>8; (p)[0] = (v); }
56bd389b36SDavid du Colombier #define	PUTLONG(p, v) { PUTSHORT((p), (v)); PUTSHORT((p)+2, (v)>>16); }
577dd7cddfSDavid du Colombier #define	GETSHORT(p)	(((p)[1]<<8)|(p)[0])
587dd7cddfSDavid du Colombier #define	GETLONG(p)	(((ulong)GETSHORT(p+2)<<16)|(ulong)GETSHORT(p))
59bd389b36SDavid du Colombier 
60bd389b36SDavid du Colombier typedef struct Dosdir	Dosdir;
61bd389b36SDavid du Colombier struct Dosdir
62bd389b36SDavid du Colombier {
63bd389b36SDavid du Colombier 	uchar	name[8];
64bd389b36SDavid du Colombier 	uchar	ext[3];
65bd389b36SDavid du Colombier 	uchar	attr;
66bd389b36SDavid du Colombier 	uchar	reserved[10];
67bd389b36SDavid du Colombier 	uchar	time[2];
68bd389b36SDavid du Colombier 	uchar	date[2];
69bd389b36SDavid du Colombier 	uchar	start[2];
70bd389b36SDavid du Colombier 	uchar	length[4];
71bd389b36SDavid du Colombier };
72bd389b36SDavid du Colombier 
73bd389b36SDavid du Colombier #define	DRONLY	0x01
74bd389b36SDavid du Colombier #define	DHIDDEN	0x02
75bd389b36SDavid du Colombier #define	DSYSTEM	0x04
76bd389b36SDavid du Colombier #define	DVLABEL	0x08
77bd389b36SDavid du Colombier #define	DDIR	0x10
78bd389b36SDavid du Colombier #define	DARCH	0x20
79bd389b36SDavid du Colombier 
80bd389b36SDavid du Colombier /*
81219b2ee8SDavid du Colombier  *  the boot program for the boot sector.
82bd389b36SDavid du Colombier  */
837dd7cddfSDavid du Colombier int nbootprog = 188;	/* no. of bytes of boot program, including the first 0x3E */
84bd389b36SDavid du Colombier uchar bootprog[512] =
85bd389b36SDavid du Colombier {
86219b2ee8SDavid du Colombier [0x000]	0xEB, 0x3C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
87bd389b36SDavid du Colombier 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88219b2ee8SDavid du Colombier [0x03E] 0xFA, 0xFC, 0x8C, 0xC8, 0x8E, 0xD8, 0x8E, 0xD0,
89219b2ee8SDavid du Colombier 	0xBC, 0x00, 0x7C, 0xBE, 0x77, 0x7C, 0xE8, 0x19,
90219b2ee8SDavid du Colombier 	0x00, 0x33, 0xC0, 0xCD, 0x16, 0xBB, 0x40, 0x00,
91219b2ee8SDavid du Colombier 	0x8E, 0xC3, 0xBB, 0x72, 0x00, 0xB8, 0x34, 0x12,
92219b2ee8SDavid du Colombier 	0x26, 0x89, 0x07, 0xEA, 0x00, 0x00, 0xFF, 0xFF,
93219b2ee8SDavid du Colombier 	0xEB, 0xD6, 0xAC, 0x0A, 0xC0, 0x74, 0x09, 0xB4,
94219b2ee8SDavid du Colombier 	0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2,
95219b2ee8SDavid du Colombier 	0xC3,  'N',  'o',  't',  ' ',  'a',  ' ',  'b',
96219b2ee8SDavid du Colombier 	 'o',  'o',  't',  'a',  'b',  'l',  'e',  ' ',
97219b2ee8SDavid du Colombier 	 'd',  'i',  's',  'c',  ' ',  'o',  'r',  ' ',
98219b2ee8SDavid du Colombier 	 'd',  'i',  's',  'c',  ' ',  'e',  'r',  'r',
99219b2ee8SDavid du Colombier 	 'o',  'r', '\r', '\n',  'P',  'r',  'e',  's',
100219b2ee8SDavid du Colombier 	 's',  ' ',  'a',  'l',  'm',  'o',  's',  't',
101219b2ee8SDavid du Colombier 	 ' ',  'a',  'n',  'y',  ' ',  'k',  'e',  'y',
102219b2ee8SDavid du Colombier 	 ' ',  't',  'o',  ' ',  'r',  'e',  'b',  'o',
103219b2ee8SDavid du Colombier 	 'o',  't',  '.',  '.',  '.', 0x00, 0x00, 0x00,
104219b2ee8SDavid du Colombier [0x1F0]	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105219b2ee8SDavid du Colombier 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA,
106bd389b36SDavid du Colombier };
107bd389b36SDavid du Colombier 
108bd389b36SDavid du Colombier char *dev;
109bd389b36SDavid du Colombier int clustersize;
110bd389b36SDavid du Colombier uchar *fat;	/* the fat */
111bd389b36SDavid du Colombier int fatbits;
112bd389b36SDavid du Colombier int fatsecs;
113bd389b36SDavid du Colombier int fatlast;	/* last cluster allocated */
114bd389b36SDavid du Colombier int clusters;
115bd389b36SDavid du Colombier int fatsecs;
1167dd7cddfSDavid du Colombier vlong volsecs;
117bd389b36SDavid du Colombier uchar *root;	/* first block of root */
118bd389b36SDavid du Colombier int rootsecs;
119bd389b36SDavid du Colombier int rootfiles;
120bd389b36SDavid du Colombier int rootnext;
1217dd7cddfSDavid du Colombier int nresrv = 1;
1227dd7cddfSDavid du Colombier int chatty;
1237dd7cddfSDavid du Colombier vlong length;
124bd389b36SDavid du Colombier Type *t;
125219b2ee8SDavid du Colombier int fflag;
1267dd7cddfSDavid du Colombier int hflag;
1277dd7cddfSDavid du Colombier int xflag;
1287dd7cddfSDavid du Colombier char *file;
1297dd7cddfSDavid du Colombier char *pbs;
130219b2ee8SDavid du Colombier char *type;
1317dd7cddfSDavid du Colombier char *bootfile;
132223a736eSDavid du Colombier int dos;
133bd389b36SDavid du Colombier 
134bd389b36SDavid du Colombier enum
135bd389b36SDavid du Colombier {
136bd389b36SDavid du Colombier 	Sof = 1,	/* start of file */
137bd389b36SDavid du Colombier 	Eof = 2,	/* end of file */
138bd389b36SDavid du Colombier };
139bd389b36SDavid du Colombier 
1407dd7cddfSDavid du Colombier void	dosfs(int, int, Disk*, char*, int, char*[], int);
141bd389b36SDavid du Colombier ulong	clustalloc(int);
1429a747e4fSDavid du Colombier void	addrname(uchar*, Dir*, char*, ulong);
1437dd7cddfSDavid du Colombier void	sanitycheck(Disk*);
144bd389b36SDavid du Colombier 
145bd389b36SDavid du Colombier void
usage(void)146bd389b36SDavid du Colombier usage(void)
147bd389b36SDavid du Colombier {
148*9f2726c3SDavid du Colombier 	fprint(2, "usage: disk/format [-df] [-b bootblock] [-c csize] "
149*9f2726c3SDavid du Colombier 		"[-l label] [-r nresrv] [-t type] disk [files ...]\n");
150bd389b36SDavid du Colombier 	exits("usage");
151bd389b36SDavid du Colombier }
152bd389b36SDavid du Colombier 
153bd389b36SDavid du Colombier void
fatal(char * fmt,...)154bd389b36SDavid du Colombier fatal(char *fmt, ...)
155bd389b36SDavid du Colombier {
156bd389b36SDavid du Colombier 	char err[128];
1577dd7cddfSDavid du Colombier 	va_list arg;
158bd389b36SDavid du Colombier 
1597dd7cddfSDavid du Colombier 	va_start(arg, fmt);
1609a747e4fSDavid du Colombier 	vsnprint(err, sizeof(err), fmt, arg);
1617dd7cddfSDavid du Colombier 	va_end(arg);
162bd389b36SDavid du Colombier 	fprint(2, "format: %s\n", err);
1637dd7cddfSDavid du Colombier 	if(fflag && file)
164219b2ee8SDavid du Colombier 		remove(file);
165bd389b36SDavid du Colombier 	exits(err);
166bd389b36SDavid du Colombier }
167bd389b36SDavid du Colombier 
168bd389b36SDavid du Colombier void
main(int argc,char ** argv)169bd389b36SDavid du Colombier main(int argc, char **argv)
170bd389b36SDavid du Colombier {
171*9f2726c3SDavid du Colombier 	int fd, n, writepbs;
172*9f2726c3SDavid du Colombier 	char buf[512], label[11];
173bd389b36SDavid du Colombier 	char *a;
1747dd7cddfSDavid du Colombier 	Disk *disk;
175bd389b36SDavid du Colombier 
176bd389b36SDavid du Colombier 	dos = 0;
1777dd7cddfSDavid du Colombier 	type = nil;
178bd389b36SDavid du Colombier 	clustersize = 0;
1797dd7cddfSDavid du Colombier 	writepbs = 0;
180219b2ee8SDavid du Colombier 	memmove(label, "CYLINDRICAL", sizeof(label));
181bd389b36SDavid du Colombier 	ARGBEGIN {
182*9f2726c3SDavid du Colombier 	case 'b':
183*9f2726c3SDavid du Colombier 		pbs = EARGF(usage());
184*9f2726c3SDavid du Colombier 		writepbs = 1;
185*9f2726c3SDavid du Colombier 		break;
1867dd7cddfSDavid du Colombier 	case 'c':
187*9f2726c3SDavid du Colombier 		clustersize = atoi(EARGF(usage()));
188219b2ee8SDavid du Colombier 		break;
189bd389b36SDavid du Colombier 	case 'd':
190bd389b36SDavid du Colombier 		dos = 1;
1917dd7cddfSDavid du Colombier 		writepbs = 1;
192bd389b36SDavid du Colombier 		break;
193219b2ee8SDavid du Colombier 	case 'f':
194219b2ee8SDavid du Colombier 		fflag = 1;
195219b2ee8SDavid du Colombier 		break;
196bd389b36SDavid du Colombier 	case 'l':
197*9f2726c3SDavid du Colombier 		a = EARGF(usage());
198bd389b36SDavid du Colombier 		n = strlen(a);
199bd389b36SDavid du Colombier 		if(n > sizeof(label))
200bd389b36SDavid du Colombier 			n = sizeof(label);
201bd389b36SDavid du Colombier 		memmove(label, a, n);
202219b2ee8SDavid du Colombier 		while(n < sizeof(label))
203219b2ee8SDavid du Colombier 			label[n++] = ' ';
204bd389b36SDavid du Colombier 		break;
2057dd7cddfSDavid du Colombier 	case 'r':
206*9f2726c3SDavid du Colombier 		nresrv = atoi(EARGF(usage()));
2077dd7cddfSDavid du Colombier 		break;
208219b2ee8SDavid du Colombier 	case 't':
209*9f2726c3SDavid du Colombier 		type = EARGF(usage());
210bd389b36SDavid du Colombier 		break;
2117dd7cddfSDavid du Colombier 	case 'v':
2127dd7cddfSDavid du Colombier 		chatty++;
2137dd7cddfSDavid du Colombier 		break;
2147dd7cddfSDavid du Colombier 	case 'x':
2157dd7cddfSDavid du Colombier 		xflag = 1;
2167dd7cddfSDavid du Colombier 		break;
217bd389b36SDavid du Colombier 	default:
218bd389b36SDavid du Colombier 		usage();
219bd389b36SDavid du Colombier 	} ARGEND
220bd389b36SDavid du Colombier 
221bd389b36SDavid du Colombier 	if(argc < 1)
222bd389b36SDavid du Colombier 		usage();
223219b2ee8SDavid du Colombier 
2247dd7cddfSDavid du Colombier 	disk = opendisk(argv[0], 0, 0);
2257dd7cddfSDavid du Colombier 	if(disk == nil) {
2267dd7cddfSDavid du Colombier 		if(fflag) {
2277dd7cddfSDavid du Colombier 			if((fd = create(argv[0], ORDWR, 0666)) >= 0) {
2287dd7cddfSDavid du Colombier 				file = argv[0];
2297dd7cddfSDavid du Colombier 				close(fd);
2307dd7cddfSDavid du Colombier 				disk = opendisk(argv[0], 0, 0);
2317dd7cddfSDavid du Colombier 			}
2327dd7cddfSDavid du Colombier 		}
2337dd7cddfSDavid du Colombier 	}
2347dd7cddfSDavid du Colombier 	if(disk == nil)
2357dd7cddfSDavid du Colombier 		fatal("opendisk: %r");
236bd389b36SDavid du Colombier 
2377dd7cddfSDavid du Colombier 	if(disk->type == Tfile)
2387dd7cddfSDavid du Colombier 		fflag = 1;
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 	if(type == nil) {
2417dd7cddfSDavid du Colombier 		switch(disk->type){
2427dd7cddfSDavid du Colombier 		case Tfile:
2437dd7cddfSDavid du Colombier 			type = "3½HD";
2447dd7cddfSDavid du Colombier 			break;
2457dd7cddfSDavid du Colombier 		case Tfloppy:
2467dd7cddfSDavid du Colombier 			seek(disk->ctlfd, 0, 0);
2477dd7cddfSDavid du Colombier 			n = read(disk->ctlfd, buf, 10);
2487dd7cddfSDavid du Colombier 			if(n <= 0 || n >= 10)
2497dd7cddfSDavid du Colombier 				fatal("reading floppy type");
2507dd7cddfSDavid du Colombier 			buf[n] = 0;
25159cc4ca5SDavid du Colombier 			type = strdup(buf);
25259cc4ca5SDavid du Colombier 			if(type == nil)
25359cc4ca5SDavid du Colombier 				fatal("out of memory");
2547dd7cddfSDavid du Colombier 			break;
2557dd7cddfSDavid du Colombier 		case Tsd:
2567dd7cddfSDavid du Colombier 			type = "hard";
2577dd7cddfSDavid du Colombier 			break;
2587dd7cddfSDavid du Colombier 		default:
2597dd7cddfSDavid du Colombier 			type = "unknown";
2607dd7cddfSDavid du Colombier 			break;
2617dd7cddfSDavid du Colombier 		}
262bd389b36SDavid du Colombier 	}
263bd389b36SDavid du Colombier 
2647dd7cddfSDavid du Colombier 	if(!fflag && disk->type == Tfloppy)
2657dd7cddfSDavid du Colombier 		if(fprint(disk->ctlfd, "format %s", type) < 0)
2667dd7cddfSDavid du Colombier 			fatal("formatting floppy as %s: %r", type);
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier 	if(disk->type != Tfloppy)
2697dd7cddfSDavid du Colombier 		sanitycheck(disk);
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 	/* check that everything will succeed */
2727dd7cddfSDavid du Colombier 	dosfs(dos, writepbs, disk, label, argc-1, argv+1, 0);
2737dd7cddfSDavid du Colombier 
2747dd7cddfSDavid du Colombier 	/* commit */
2757dd7cddfSDavid du Colombier 	dosfs(dos, writepbs, disk, label, argc-1, argv+1, 1);
2767dd7cddfSDavid du Colombier 
2779a747e4fSDavid du Colombier 	print("used %lld bytes\n", fatlast*clustersize*disk->secsize);
278bd389b36SDavid du Colombier 	exits(0);
279bd389b36SDavid du Colombier }
280bd389b36SDavid du Colombier 
2817dd7cddfSDavid du Colombier /*
2827dd7cddfSDavid du Colombier  * Look for a partition table on sector 1, as would be the
2837dd7cddfSDavid du Colombier  * case if we were erroneously formatting 9fat without -r 2.
2847dd7cddfSDavid du Colombier  * If it's there and nresrv is not big enough, complain and exit.
2857dd7cddfSDavid du Colombier  * I've blown away my partition table too many times.
2867dd7cddfSDavid du Colombier  */
287bd389b36SDavid du Colombier void
sanitycheck(Disk * disk)2887dd7cddfSDavid du Colombier sanitycheck(Disk *disk)
2897dd7cddfSDavid du Colombier {
2907dd7cddfSDavid du Colombier 	char buf[512];
2917dd7cddfSDavid du Colombier 	int bad;
2927dd7cddfSDavid du Colombier 
2937dd7cddfSDavid du Colombier 	if(xflag)
2947dd7cddfSDavid du Colombier 		return;
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier 	bad = 0;
297223a736eSDavid du Colombier 	if(dos && nresrv < 2 && seek(disk->fd, disk->secsize, 0) == disk->secsize
2987dd7cddfSDavid du Colombier 	&& read(disk->fd, buf, sizeof(buf)) >= 5 && strncmp(buf, "part ", 5) == 0) {
2997dd7cddfSDavid du Colombier 		fprint(2,
3007dd7cddfSDavid du Colombier 			"there's a plan9 partition on the disk\n"
3017dd7cddfSDavid du Colombier 			"and you didn't specify -r 2 (or greater).\n"
3027dd7cddfSDavid du Colombier 			"either specify -r 2 or -x to disable this check.\n");
3037dd7cddfSDavid du Colombier 		bad = 1;
3047dd7cddfSDavid du Colombier 	}
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier 	if(disk->type == Tsd && disk->offset == 0LL) {
3077dd7cddfSDavid du Colombier 		fprint(2,
3087dd7cddfSDavid du Colombier 			"you're attempting to format your disk (/dev/sdXX/data)\n"
3097dd7cddfSDavid du Colombier 			"rather than a partition like /dev/sdXX/9fat;\n"
3107dd7cddfSDavid du Colombier 			"this is likely a mistake.  specify -x to disable this check.\n");
3117dd7cddfSDavid du Colombier 		bad = 1;
3127dd7cddfSDavid du Colombier 	}
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier 	if(bad)
3157dd7cddfSDavid du Colombier 		exits("failed disk sanity check");
3167dd7cddfSDavid du Colombier }
3177dd7cddfSDavid du Colombier 
3187dd7cddfSDavid du Colombier /*
3197dd7cddfSDavid du Colombier  * Return the BIOS drive number for the disk.
3207dd7cddfSDavid du Colombier  * 0x80 is the first fixed disk, 0x81 the next, etc.
3217dd7cddfSDavid du Colombier  * We map sdC0=0x80, sdC1=0x81, sdD0=0x82, sdD1=0x83
3227dd7cddfSDavid du Colombier  */
3237dd7cddfSDavid du Colombier int
getdriveno(Disk * disk)3247dd7cddfSDavid du Colombier getdriveno(Disk *disk)
3257dd7cddfSDavid du Colombier {
3269a747e4fSDavid du Colombier 	char buf[64], *p;
3277dd7cddfSDavid du Colombier 
3287dd7cddfSDavid du Colombier 	if(disk->type != Tsd)
3297dd7cddfSDavid du Colombier 		return 0x80;	/* first hard disk */
3307dd7cddfSDavid du Colombier 
3317dd7cddfSDavid du Colombier 	if(fd2path(disk->fd, buf, sizeof(buf)) < 0)
3327dd7cddfSDavid du Colombier 		return 0x80;
3337dd7cddfSDavid du Colombier 
3347dd7cddfSDavid du Colombier 	/*
3357dd7cddfSDavid du Colombier 	 * The name is of the format #SsdC0/foo
3367dd7cddfSDavid du Colombier 	 * or /dev/sdC0/foo.
3377dd7cddfSDavid du Colombier 	 * So that we can just look for /sdC0, turn
3387dd7cddfSDavid du Colombier 	 * #SsdC0/foo into #/sdC0/foo.
3397dd7cddfSDavid du Colombier 	 */
3407dd7cddfSDavid du Colombier 	if(buf[0] == '#' && buf[1] == 'S')
3417dd7cddfSDavid du Colombier 		buf[1] = '/';
3427dd7cddfSDavid du Colombier 
3437dd7cddfSDavid du Colombier 	for(p=buf; *p; p++)
344*9f2726c3SDavid du Colombier 		if(p[0] == 's' && p[1] == 'd' && (p[2]=='C' || p[2]=='D') &&
345*9f2726c3SDavid du Colombier 		    (p[3]=='0' || p[3]=='1'))
3467dd7cddfSDavid du Colombier 			return 0x80 + (p[2]-'C')*2 + (p[3]-'0');
3477dd7cddfSDavid du Colombier 
3487dd7cddfSDavid du Colombier 	return 0x80;
3497dd7cddfSDavid du Colombier }
3507dd7cddfSDavid du Colombier 
3513ff48bf5SDavid du Colombier long
writen(int fd,void * buf,long n)3523ff48bf5SDavid du Colombier writen(int fd, void *buf, long n)
3533ff48bf5SDavid du Colombier {
3543ff48bf5SDavid du Colombier 	long m, tot;
3553ff48bf5SDavid du Colombier 
356*9f2726c3SDavid du Colombier 	/* write 8k at a time, to be nice to the disk subsystem */
3573ff48bf5SDavid du Colombier 	for(tot=0; tot<n; tot+=m){
3583ff48bf5SDavid du Colombier 		m = n - tot;
3593ff48bf5SDavid du Colombier 		if(m > 8192)
3603ff48bf5SDavid du Colombier 			m = 8192;
3613ff48bf5SDavid du Colombier 		if(write(fd, (uchar*)buf+tot, m) != m)
3623ff48bf5SDavid du Colombier 			break;
3633ff48bf5SDavid du Colombier 	}
3643ff48bf5SDavid du Colombier 	return tot;
3653ff48bf5SDavid du Colombier }
3663ff48bf5SDavid du Colombier 
3677dd7cddfSDavid du Colombier void
dosfs(int dofat,int dopbs,Disk * disk,char * label,int argc,char * argv[],int commit)3687dd7cddfSDavid du Colombier dosfs(int dofat, int dopbs, Disk *disk, char *label, int argc, char *argv[], int commit)
369bd389b36SDavid du Colombier {
370bd389b36SDavid du Colombier 	char r[16];
371bd389b36SDavid du Colombier 	Dosboot *b;
3727dd7cddfSDavid du Colombier 	uchar *buf, *pbsbuf, *p;
3739a747e4fSDavid du Colombier 	Dir *d;
3743ff48bf5SDavid du Colombier 	int i, data, newclusters, npbs, n, sysfd;
3757dd7cddfSDavid du Colombier 	ulong x;
376*9f2726c3SDavid du Colombier 	vlong length, secsize;
377bd389b36SDavid du Colombier 
3787dd7cddfSDavid du Colombier 	if(dofat == 0 && dopbs == 0)
3797dd7cddfSDavid du Colombier 		return;
380bd389b36SDavid du Colombier 
381219b2ee8SDavid du Colombier 	for(t = floppytype; t < &floppytype[NTYPES]; t++)
382219b2ee8SDavid du Colombier 		if(strcmp(type, t->name) == 0)
383219b2ee8SDavid du Colombier 			break;
384219b2ee8SDavid du Colombier 	if(t == &floppytype[NTYPES])
385219b2ee8SDavid du Colombier 		fatal("unknown floppy type %s", type);
386bd389b36SDavid du Colombier 
3877dd7cddfSDavid du Colombier 	if(t->sectors == 0 && strcmp(type, "hard") == 0) {
3887dd7cddfSDavid du Colombier 		t->sectors = disk->s;
3897dd7cddfSDavid du Colombier 		t->heads = disk->h;
3907dd7cddfSDavid du Colombier 		t->tracks = disk->c;
391bd389b36SDavid du Colombier 	}
392bd389b36SDavid du Colombier 
3937dd7cddfSDavid du Colombier 	if(t->sectors == 0 && dofat)
3947dd7cddfSDavid du Colombier 		fatal("cannot format fat with type %s: geometry unknown\n", type);
3957dd7cddfSDavid du Colombier 
3967dd7cddfSDavid du Colombier 	if(fflag){
3977dd7cddfSDavid du Colombier 		disk->size = t->bytes*t->sectors*t->heads*t->tracks;
3987dd7cddfSDavid du Colombier 		disk->secsize = t->bytes;
3997dd7cddfSDavid du Colombier 		disk->secs = disk->size / disk->secsize;
4007dd7cddfSDavid du Colombier 	}
4017dd7cddfSDavid du Colombier 
4027dd7cddfSDavid du Colombier 	secsize = disk->secsize;
4037dd7cddfSDavid du Colombier 	length = disk->size;
4047dd7cddfSDavid du Colombier 
4057dd7cddfSDavid du Colombier 	buf = malloc(secsize);
406bd389b36SDavid du Colombier 	if(buf == 0)
407bd389b36SDavid du Colombier 		fatal("out of memory");
408bd389b36SDavid du Colombier 
409bd389b36SDavid du Colombier 	/*
4107dd7cddfSDavid du Colombier 	 * Make disk full size if a file.
411bd389b36SDavid du Colombier 	 */
4129a747e4fSDavid du Colombier 	if(fflag && disk->type == Tfile){
4139a747e4fSDavid du Colombier 		if((d = dirfstat(disk->wfd)) == nil)
4147dd7cddfSDavid du Colombier 			fatal("fstat disk: %r");
4159a747e4fSDavid du Colombier 		if(commit && d->length < disk->size) {
4167dd7cddfSDavid du Colombier 			if(seek(disk->wfd, disk->size-1, 0) < 0)
4177dd7cddfSDavid du Colombier 				fatal("seek to 9: %r");
4187dd7cddfSDavid du Colombier 			if(write(disk->wfd, "9", 1) < 0)
4197dd7cddfSDavid du Colombier 				fatal("writing 9: @%lld %r", seek(disk->wfd, 0LL, 1));
420219b2ee8SDavid du Colombier 		}
4219a747e4fSDavid du Colombier 		free(d);
4227dd7cddfSDavid du Colombier 	}
4237dd7cddfSDavid du Colombier 
4247dd7cddfSDavid du Colombier 	/*
4257dd7cddfSDavid du Colombier 	 * Start with initial sector from disk
4267dd7cddfSDavid du Colombier 	 */
4277dd7cddfSDavid du Colombier 	if(seek(disk->fd, 0, 0) < 0)
4287dd7cddfSDavid du Colombier 		fatal("seek to boot sector: %r\n");
4297dd7cddfSDavid du Colombier 	if(commit && read(disk->fd, buf, secsize) != secsize)
4307dd7cddfSDavid du Colombier 		fatal("reading boot sector: %r");
4317dd7cddfSDavid du Colombier 
4327dd7cddfSDavid du Colombier 	if(dofat)
4337dd7cddfSDavid du Colombier 		memset(buf, 0, sizeof(Dosboot));
4347dd7cddfSDavid du Colombier 
4357dd7cddfSDavid du Colombier 	/*
4367dd7cddfSDavid du Colombier 	 * Jump instruction and OEM name.
4377dd7cddfSDavid du Colombier 	 */
438bd389b36SDavid du Colombier 	b = (Dosboot*)buf;
439219b2ee8SDavid du Colombier 	b->magic[0] = 0xEB;
440219b2ee8SDavid du Colombier 	b->magic[1] = 0x3C;
441219b2ee8SDavid du Colombier 	b->magic[2] = 0x90;
442219b2ee8SDavid du Colombier 	memmove(b->version, "Plan9.00", sizeof(b->version));
4437dd7cddfSDavid du Colombier 
4447dd7cddfSDavid du Colombier 	/*
4457dd7cddfSDavid du Colombier 	 * Add bootstrapping code; assume it starts
4467dd7cddfSDavid du Colombier 	 * at 0x3E (the destination of the jump we just
4477dd7cddfSDavid du Colombier 	 * wrote to b->magic).
4487dd7cddfSDavid du Colombier 	 */
4497dd7cddfSDavid du Colombier 	if(dopbs) {
4507dd7cddfSDavid du Colombier 		pbsbuf = malloc(secsize);
4517dd7cddfSDavid du Colombier 		if(pbsbuf == 0)
4527dd7cddfSDavid du Colombier 			fatal("out of memory");
4537dd7cddfSDavid du Colombier 
4547dd7cddfSDavid du Colombier 		if(pbs){
4557dd7cddfSDavid du Colombier 			if((sysfd = open(pbs, OREAD)) < 0)
4567dd7cddfSDavid du Colombier 				fatal("open %s: %r", pbs);
4577dd7cddfSDavid du Colombier 			if((npbs = read(sysfd, pbsbuf, secsize)) < 0)
4587dd7cddfSDavid du Colombier 				fatal("read %s: %r", pbs);
4597dd7cddfSDavid du Colombier 
4607dd7cddfSDavid du Colombier 			if(npbs > secsize-2)
4617dd7cddfSDavid du Colombier 				fatal("boot block too large");
4627dd7cddfSDavid du Colombier 
4637dd7cddfSDavid du Colombier 			close(sysfd);
4647dd7cddfSDavid du Colombier 		}
4657dd7cddfSDavid du Colombier 		else {
4667dd7cddfSDavid du Colombier 			memmove(pbsbuf, bootprog, sizeof(bootprog));
4677dd7cddfSDavid du Colombier 			npbs = nbootprog;
4687dd7cddfSDavid du Colombier 		}
4697dd7cddfSDavid du Colombier 		if(npbs <= 0x3E)
4707dd7cddfSDavid du Colombier 			fprint(2, "warning: pbs too small\n");
4717dd7cddfSDavid du Colombier 		else
4727dd7cddfSDavid du Colombier 			memmove(buf+0x3E, pbsbuf+0x3E, npbs-0x3E);
4737dd7cddfSDavid du Colombier 
4747dd7cddfSDavid du Colombier 		free(pbsbuf);
4757dd7cddfSDavid du Colombier 	}
4767dd7cddfSDavid du Colombier 
4777dd7cddfSDavid du Colombier 	/*
4787dd7cddfSDavid du Colombier 	 * Add FAT BIOS parameter block.
4797dd7cddfSDavid du Colombier 	 */
4807dd7cddfSDavid du Colombier 	if(dofat) {
4817dd7cddfSDavid du Colombier 		if(commit) {
482f8d0ebfeSDavid du Colombier 			print("Initializing FAT file system\n");
4837dd7cddfSDavid du Colombier 			print("type %s, %d tracks, %d heads, %d sectors/track, %lld bytes/sec\n",
4847dd7cddfSDavid du Colombier 				t->name, t->tracks, t->heads, t->sectors, secsize);
4857dd7cddfSDavid du Colombier 		}
4867dd7cddfSDavid du Colombier 
4877dd7cddfSDavid du Colombier 		if(clustersize == 0)
4887dd7cddfSDavid du Colombier 			clustersize = t->cluster;
4893ff48bf5SDavid du Colombier 		/*
4903ff48bf5SDavid du Colombier 		 * the number of fat bits depends on how much disk is left
4913ff48bf5SDavid du Colombier 		 * over after you subtract out the space taken up by the fat tables.
4923ff48bf5SDavid du Colombier 		 * try both.  what a crock.
4933ff48bf5SDavid du Colombier 		 */
4947dd7cddfSDavid du Colombier 		fatbits = 12;
4953ff48bf5SDavid du Colombier Tryagain:
4967dd7cddfSDavid du Colombier 		volsecs = length/secsize;
4973ff48bf5SDavid du Colombier 		/*
4983ff48bf5SDavid du Colombier 		 * here's a crock inside a crock.  even having fixed fatbits,
4993ff48bf5SDavid du Colombier 		 * the number of fat sectors depends on the number of clusters,
5003ff48bf5SDavid du Colombier 		 * but of course we don't know yet.  maybe iterating will get us there.
5013ff48bf5SDavid du Colombier 		 * or maybe it will cycle.
5023ff48bf5SDavid du Colombier 		 */
5033ff48bf5SDavid du Colombier 		clusters = 0;
5043ff48bf5SDavid du Colombier 		for(i=0;; i++){
5057dd7cddfSDavid du Colombier 			fatsecs = (fatbits*clusters + 8*secsize - 1)/(8*secsize);
5067dd7cddfSDavid du Colombier 			rootsecs = volsecs/200;
5077dd7cddfSDavid du Colombier 			rootfiles = rootsecs * (secsize/sizeof(Dosdir));
5087dd7cddfSDavid du Colombier 			if(rootfiles > 512){
5097dd7cddfSDavid du Colombier 				rootfiles = 512;
5107dd7cddfSDavid du Colombier 				rootsecs = rootfiles/(secsize/sizeof(Dosdir));
5117dd7cddfSDavid du Colombier 			}
5123ff48bf5SDavid du Colombier 			data = nresrv + 2*fatsecs + (rootfiles*sizeof(Dosdir) + secsize-1)/secsize;
5133ff48bf5SDavid du Colombier 			newclusters = 2 + (volsecs - data)/clustersize;
5143ff48bf5SDavid du Colombier 			if(newclusters == clusters)
5153ff48bf5SDavid du Colombier 				break;
5163ff48bf5SDavid du Colombier 			clusters = newclusters;
5173ff48bf5SDavid du Colombier 			if(i > 10)
5183ff48bf5SDavid du Colombier 				fatal("can't decide how many clusters to use (%d? %d?)", clusters, newclusters);
5193ff48bf5SDavid du Colombier if(chatty) print("clusters %d\n", clusters);
5203ff48bf5SDavid du Colombier 		}
5217dd7cddfSDavid du Colombier 
5223ff48bf5SDavid du Colombier if(chatty) print("try %d fatbits => %d clusters of %d\n", fatbits, clusters, clustersize);
5233ff48bf5SDavid du Colombier 		switch(fatbits){
5243ff48bf5SDavid du Colombier 		case 12:
5253ff48bf5SDavid du Colombier 			if(clusters >= 4087){
5263ff48bf5SDavid du Colombier 				fatbits = 16;
5273ff48bf5SDavid du Colombier 				goto Tryagain;
5283ff48bf5SDavid du Colombier 			}
5293ff48bf5SDavid du Colombier 			break;
5303ff48bf5SDavid du Colombier 		case 16:
5313ff48bf5SDavid du Colombier 			if(clusters >= 65527)
5323ff48bf5SDavid du Colombier 				fatal("disk too big; implement fat32");
5333ff48bf5SDavid du Colombier 			break;
5343ff48bf5SDavid du Colombier 		}
5357dd7cddfSDavid du Colombier 		PUTSHORT(b->sectsize, secsize);
536bd389b36SDavid du Colombier 		b->clustsize = clustersize;
5377dd7cddfSDavid du Colombier 		PUTSHORT(b->nresrv, nresrv);
538bd389b36SDavid du Colombier 		b->nfats = 2;
539bd389b36SDavid du Colombier 		PUTSHORT(b->rootsize, rootfiles);
5407dd7cddfSDavid du Colombier 		if(volsecs < (1<<16))
541bd389b36SDavid du Colombier 			PUTSHORT(b->volsize, volsecs);
542bd389b36SDavid du Colombier 		b->mediadesc = t->media;
543bd389b36SDavid du Colombier 		PUTSHORT(b->fatsize, fatsecs);
544bd389b36SDavid du Colombier 		PUTSHORT(b->trksize, t->sectors);
545bd389b36SDavid du Colombier 		PUTSHORT(b->nheads, t->heads);
5467dd7cddfSDavid du Colombier 		PUTLONG(b->nhidden, disk->offset);
5477dd7cddfSDavid du Colombier 		PUTLONG(b->bigvolsize, volsecs);
5487dd7cddfSDavid du Colombier 
5497dd7cddfSDavid du Colombier 		/*
5507dd7cddfSDavid du Colombier 		 * Extended BIOS Parameter Block.
5517dd7cddfSDavid du Colombier 		 */
5527dd7cddfSDavid du Colombier 		if(t->media == 0xF8)
5537dd7cddfSDavid du Colombier 			b->driveno = getdriveno(disk);
5547dd7cddfSDavid du Colombier 		else
555bd389b36SDavid du Colombier 			b->driveno = 0;
5567dd7cddfSDavid du Colombier if(chatty) print("driveno = %ux\n", b->driveno);
5577dd7cddfSDavid du Colombier 
558bd389b36SDavid du Colombier 		b->bootsig = 0x29;
5597dd7cddfSDavid du Colombier 		x = disk->offset + b->nfats*fatsecs + nresrv;
560bd389b36SDavid du Colombier 		PUTLONG(b->volid, x);
5617dd7cddfSDavid du Colombier if(chatty) print("volid = %lux %lux\n", x, GETLONG(b->volid));
562bd389b36SDavid du Colombier 		memmove(b->label, label, sizeof(b->label));
563bd389b36SDavid du Colombier 		sprint(r, "FAT%d    ", fatbits);
564219b2ee8SDavid du Colombier 		memmove(b->type, r, sizeof(b->type));
5657dd7cddfSDavid du Colombier 	}
5667dd7cddfSDavid du Colombier 
5677dd7cddfSDavid du Colombier 	buf[secsize-2] = 0x55;
5687dd7cddfSDavid du Colombier 	buf[secsize-1] = 0xAA;
5697dd7cddfSDavid du Colombier 
5707dd7cddfSDavid du Colombier 	if(commit) {
5717dd7cddfSDavid du Colombier 		if(seek(disk->wfd, 0, 0) < 0)
572219b2ee8SDavid du Colombier 			fatal("seek to boot sector: %r\n");
5737dd7cddfSDavid du Colombier 		if(write(disk->wfd, buf, secsize) != secsize)
574bd389b36SDavid du Colombier 			fatal("writing boot sector: %r");
5757dd7cddfSDavid du Colombier 	}
5767dd7cddfSDavid du Colombier 
577bd389b36SDavid du Colombier 	free(buf);
578bd389b36SDavid du Colombier 
579bd389b36SDavid du Colombier 	/*
5807dd7cddfSDavid du Colombier 	 * If we were only called to write the PBS, leave now.
5817dd7cddfSDavid du Colombier 	 */
5827dd7cddfSDavid du Colombier 	if(dofat == 0)
5837dd7cddfSDavid du Colombier 		return;
5847dd7cddfSDavid du Colombier 
5857dd7cddfSDavid du Colombier 	/*
586bd389b36SDavid du Colombier 	 *  allocate an in memory fat
587bd389b36SDavid du Colombier 	 */
5887dd7cddfSDavid du Colombier 	if(seek(disk->wfd, nresrv*secsize, 0) < 0)
5897dd7cddfSDavid du Colombier 		fatal("seek to fat: %r\n");
5907dd7cddfSDavid du Colombier if(chatty) print("fat @%lluX\n", seek(disk->wfd, 0, 1));
5917dd7cddfSDavid du Colombier 	fat = malloc(fatsecs*secsize);
592bd389b36SDavid du Colombier 	if(fat == 0)
593bd389b36SDavid du Colombier 		fatal("out of memory");
5947dd7cddfSDavid du Colombier 	memset(fat, 0, fatsecs*secsize);
595bd389b36SDavid du Colombier 	fat[0] = t->media;
596bd389b36SDavid du Colombier 	fat[1] = 0xff;
597bd389b36SDavid du Colombier 	fat[2] = 0xff;
598bd389b36SDavid du Colombier 	if(fatbits == 16)
599bd389b36SDavid du Colombier 		fat[3] = 0xff;
600bd389b36SDavid du Colombier 	fatlast = 1;
6017dd7cddfSDavid du Colombier 	if(seek(disk->wfd, 2*fatsecs*secsize, 1) < 0)	/* 2 fats */
6027dd7cddfSDavid du Colombier 		fatal("seek to root: %r");
6037dd7cddfSDavid du Colombier if(chatty) print("root @%lluX\n", seek(disk->wfd, 0LL, 1));
604bd389b36SDavid du Colombier 
605bd389b36SDavid du Colombier 	/*
606bd389b36SDavid du Colombier 	 *  allocate an in memory root
607bd389b36SDavid du Colombier 	 */
6087dd7cddfSDavid du Colombier 	root = malloc(rootsecs*secsize);
609bd389b36SDavid du Colombier 	if(root == 0)
610bd389b36SDavid du Colombier 		fatal("out of memory");
6117dd7cddfSDavid du Colombier 	memset(root, 0, rootsecs*secsize);
6127dd7cddfSDavid du Colombier 	if(seek(disk->wfd, rootsecs*secsize, 1) < 0)	/* rootsecs */
6137dd7cddfSDavid du Colombier 		fatal("seek to files: %r");
6147dd7cddfSDavid du Colombier if(chatty) print("files @%lluX\n", seek(disk->wfd, 0LL, 1));
615bd389b36SDavid du Colombier 
616bd389b36SDavid du Colombier 	/*
617219b2ee8SDavid du Colombier 	 * Now positioned at the Files Area.
618219b2ee8SDavid du Colombier 	 * If we have any arguments, process
619219b2ee8SDavid du Colombier 	 * them and write out.
620bd389b36SDavid du Colombier 	 */
621219b2ee8SDavid du Colombier 	for(p = root; argc > 0; argc--, argv++, p += sizeof(Dosdir)){
6227dd7cddfSDavid du Colombier 		if(p >= (root+(rootsecs*secsize)))
623219b2ee8SDavid du Colombier 			fatal("too many files in root");
624219b2ee8SDavid du Colombier 		/*
625219b2ee8SDavid du Colombier 		 * Open the file and get its length.
626219b2ee8SDavid du Colombier 		 */
627219b2ee8SDavid du Colombier 		if((sysfd = open(*argv, OREAD)) < 0)
628219b2ee8SDavid du Colombier 			fatal("open %s: %r", *argv);
6299a747e4fSDavid du Colombier 		if((d = dirfstat(sysfd)) == nil)
630219b2ee8SDavid du Colombier 			fatal("stat %s: %r", *argv);
63122a127bbSDavid du Colombier 		if(d->length > 0xFFFFFFFFU)
6329a747e4fSDavid du Colombier 			fatal("file %s too big\n", *argv, d->length);
6337dd7cddfSDavid du Colombier 		if(commit)
6349a747e4fSDavid du Colombier 			print("Adding file %s, length %lld\n", *argv, d->length);
635219b2ee8SDavid du Colombier 
6369a747e4fSDavid du Colombier 		length = d->length;
637219b2ee8SDavid du Colombier 		if(length){
638219b2ee8SDavid du Colombier 			/*
639219b2ee8SDavid du Colombier 			 * Allocate a buffer to read the entire file into.
640219b2ee8SDavid du Colombier 			 * This must be rounded up to a cluster boundary.
641219b2ee8SDavid du Colombier 			 *
642219b2ee8SDavid du Colombier 			 * Read the file and write it out to the Files Area.
643219b2ee8SDavid du Colombier 			 */
6447dd7cddfSDavid du Colombier 			length += secsize*clustersize - 1;
6457dd7cddfSDavid du Colombier 			length /= secsize*clustersize;
6467dd7cddfSDavid du Colombier 			length *= secsize*clustersize;
647219b2ee8SDavid du Colombier 			if((buf = malloc(length)) == 0)
648219b2ee8SDavid du Colombier 				fatal("out of memory");
649219b2ee8SDavid du Colombier 
6503ff48bf5SDavid du Colombier 			if(readn(sysfd, buf, d->length) != d->length)
651219b2ee8SDavid du Colombier 				fatal("read %s: %r", *argv);
6529a747e4fSDavid du Colombier 			memset(buf+d->length, 0, length-d->length);
6539a747e4fSDavid du Colombier if(chatty) print("%s @%lluX\n", d->name, seek(disk->wfd, 0LL, 1));
6543ff48bf5SDavid du Colombier 			if(commit && writen(disk->wfd, buf, length) != length)
655219b2ee8SDavid du Colombier 				fatal("write %s: %r", *argv);
656219b2ee8SDavid du Colombier 			free(buf);
657219b2ee8SDavid du Colombier 
658219b2ee8SDavid du Colombier 			close(sysfd);
659219b2ee8SDavid du Colombier 
660219b2ee8SDavid du Colombier 			/*
661219b2ee8SDavid du Colombier 			 * Allocate the FAT clusters.
662219b2ee8SDavid du Colombier 			 * We're assuming here that where we
663219b2ee8SDavid du Colombier 			 * wrote the file is in sync with
664219b2ee8SDavid du Colombier 			 * the cluster allocation.
665219b2ee8SDavid du Colombier 			 * Save the starting cluster.
666219b2ee8SDavid du Colombier 			 */
6677dd7cddfSDavid du Colombier 			length /= secsize*clustersize;
668219b2ee8SDavid du Colombier 			x = clustalloc(Sof);
669219b2ee8SDavid du Colombier 			for(n = 0; n < length-1; n++)
670219b2ee8SDavid du Colombier 				clustalloc(0);
671219b2ee8SDavid du Colombier 			clustalloc(Eof);
672219b2ee8SDavid du Colombier 		}
673219b2ee8SDavid du Colombier 		else
674219b2ee8SDavid du Colombier 			x = 0;
675219b2ee8SDavid du Colombier 
676219b2ee8SDavid du Colombier 		/*
677219b2ee8SDavid du Colombier 		 * Add the filename to the root.
678219b2ee8SDavid du Colombier 		 */
6793ff48bf5SDavid du Colombier fprint(2, "add %s at clust %lux\n", d->name, x);
6809a747e4fSDavid du Colombier 		addrname(p, d, *argv, x);
6819a747e4fSDavid du Colombier 		free(d);
682219b2ee8SDavid du Colombier 	}
683bd389b36SDavid du Colombier 
684bd389b36SDavid du Colombier 	/*
685bd389b36SDavid du Colombier 	 *  write the fats and root
686bd389b36SDavid du Colombier 	 */
6877dd7cddfSDavid du Colombier 	if(commit) {
6887dd7cddfSDavid du Colombier 		if(seek(disk->wfd, nresrv*secsize, 0) < 0)
6897dd7cddfSDavid du Colombier 			fatal("seek to fat #1: %r");
6907dd7cddfSDavid du Colombier 		if(write(disk->wfd, fat, fatsecs*secsize) < 0)
691bd389b36SDavid du Colombier 			fatal("writing fat #1: %r");
6927dd7cddfSDavid du Colombier 		if(write(disk->wfd, fat, fatsecs*secsize) < 0)
693bd389b36SDavid du Colombier 			fatal("writing fat #2: %r");
6947dd7cddfSDavid du Colombier 		if(write(disk->wfd, root, rootsecs*secsize) < 0)
695bd389b36SDavid du Colombier 			fatal("writing root: %r");
696219b2ee8SDavid du Colombier 	}
6977dd7cddfSDavid du Colombier 
6987dd7cddfSDavid du Colombier 	free(fat);
6997dd7cddfSDavid du Colombier 	free(root);
700bd389b36SDavid du Colombier }
701bd389b36SDavid du Colombier 
702bd389b36SDavid du Colombier /*
703bd389b36SDavid du Colombier  *  allocate a cluster
704bd389b36SDavid du Colombier  */
705bd389b36SDavid du Colombier ulong
clustalloc(int flag)706bd389b36SDavid du Colombier clustalloc(int flag)
707bd389b36SDavid du Colombier {
708bd389b36SDavid du Colombier 	ulong o, x;
709bd389b36SDavid du Colombier 
710bd389b36SDavid du Colombier 	if(flag != Sof){
711bd389b36SDavid du Colombier 		x = (flag == Eof) ? 0xffff : (fatlast+1);
712bd389b36SDavid du Colombier 		if(fatbits == 12){
713bd389b36SDavid du Colombier 			x &= 0xfff;
714bd389b36SDavid du Colombier 			o = (3*fatlast)/2;
715bd389b36SDavid du Colombier 			if(fatlast & 1){
716bd389b36SDavid du Colombier 				fat[o] = (fat[o]&0x0f) | (x<<4);
717219b2ee8SDavid du Colombier 				fat[o+1] = (x>>4);
718bd389b36SDavid du Colombier 			} else {
719bd389b36SDavid du Colombier 				fat[o] = x;
720219b2ee8SDavid du Colombier 				fat[o+1] = (fat[o+1]&0xf0) | ((x>>8) & 0x0F);
721bd389b36SDavid du Colombier 			}
722bd389b36SDavid du Colombier 		} else {
723bd389b36SDavid du Colombier 			o = 2*fatlast;
724bd389b36SDavid du Colombier 			fat[o] = x;
725bd389b36SDavid du Colombier 			fat[o+1] = x>>8;
726bd389b36SDavid du Colombier 		}
727bd389b36SDavid du Colombier 	}
728bd389b36SDavid du Colombier 
729bd389b36SDavid du Colombier 	if(flag == Eof)
730bd389b36SDavid du Colombier 		return 0;
7319a747e4fSDavid du Colombier 	else{
7329a747e4fSDavid du Colombier 		++fatlast;
7339a747e4fSDavid du Colombier 		if(fatlast >= clusters)
7349a747e4fSDavid du Colombier 			sysfatal("data does not fit on disk (%d %d)", fatlast, clusters);
7359a747e4fSDavid du Colombier 		return fatlast;
7369a747e4fSDavid du Colombier 	}
737bd389b36SDavid du Colombier }
738bd389b36SDavid du Colombier 
739bd389b36SDavid du Colombier void
putname(char * p,Dosdir * d)740219b2ee8SDavid du Colombier putname(char *p, Dosdir *d)
741bd389b36SDavid du Colombier {
742219b2ee8SDavid du Colombier 	int i;
743bd389b36SDavid du Colombier 
744219b2ee8SDavid du Colombier 	memset(d->name, ' ', sizeof d->name+sizeof d->ext);
745219b2ee8SDavid du Colombier 	for(i = 0; i< sizeof(d->name); i++){
746219b2ee8SDavid du Colombier 		if(*p == 0 || *p == '.')
747bd389b36SDavid du Colombier 			break;
748219b2ee8SDavid du Colombier 		d->name[i] = toupper(*p++);
749bd389b36SDavid du Colombier 	}
750219b2ee8SDavid du Colombier 	p = strrchr(p, '.');
751219b2ee8SDavid du Colombier 	if(p){
752219b2ee8SDavid du Colombier 		for(i = 0; i < sizeof d->ext; i++){
753219b2ee8SDavid du Colombier 			if(*++p == 0)
754219b2ee8SDavid du Colombier 				break;
755219b2ee8SDavid du Colombier 			d->ext[i] = toupper(*p);
756219b2ee8SDavid du Colombier 		}
757219b2ee8SDavid du Colombier 	}
758219b2ee8SDavid du Colombier }
759bd389b36SDavid du Colombier 
760219b2ee8SDavid du Colombier void
puttime(Dosdir * d)761219b2ee8SDavid du Colombier puttime(Dosdir *d)
762219b2ee8SDavid du Colombier {
763219b2ee8SDavid du Colombier 	Tm *t = localtime(time(0));
764219b2ee8SDavid du Colombier 	ushort x;
765219b2ee8SDavid du Colombier 
766219b2ee8SDavid du Colombier 	x = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
767219b2ee8SDavid du Colombier 	d->time[0] = x;
768219b2ee8SDavid du Colombier 	d->time[1] = x>>8;
769219b2ee8SDavid du Colombier 	x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
770219b2ee8SDavid du Colombier 	d->date[0] = x;
771219b2ee8SDavid du Colombier 	d->date[1] = x>>8;
772219b2ee8SDavid du Colombier }
773219b2ee8SDavid du Colombier 
774219b2ee8SDavid du Colombier void
addrname(uchar * entry,Dir * dir,char * name,ulong start)7759a747e4fSDavid du Colombier addrname(uchar *entry, Dir *dir, char *name, ulong start)
776219b2ee8SDavid du Colombier {
7779a747e4fSDavid du Colombier 	char *s;
778219b2ee8SDavid du Colombier 	Dosdir *d;
779219b2ee8SDavid du Colombier 
7809a747e4fSDavid du Colombier 	s = strrchr(name, '/');
7819a747e4fSDavid du Colombier 	if(s)
7829a747e4fSDavid du Colombier 		s++;
7839a747e4fSDavid du Colombier 	else
7849a747e4fSDavid du Colombier 		s = name;
7859a747e4fSDavid du Colombier 
786219b2ee8SDavid du Colombier 	d = (Dosdir*)entry;
7879a747e4fSDavid du Colombier 	putname(s, d);
7889a747e4fSDavid du Colombier 	if(strcmp(s, "9load") == 0)
7897dd7cddfSDavid du Colombier 		d->attr = DSYSTEM;
7907dd7cddfSDavid du Colombier 	else
7917dd7cddfSDavid du Colombier 		d->attr = 0;
792219b2ee8SDavid du Colombier 	puttime(d);
793219b2ee8SDavid du Colombier 	d->start[0] = start;
794219b2ee8SDavid du Colombier 	d->start[1] = start>>8;
795219b2ee8SDavid du Colombier 	d->length[0] = dir->length;
796219b2ee8SDavid du Colombier 	d->length[1] = dir->length>>8;
797219b2ee8SDavid du Colombier 	d->length[2] = dir->length>>16;
798219b2ee8SDavid du Colombier 	d->length[3] = dir->length>>24;
799bd389b36SDavid du Colombier }
800