xref: /plan9/sys/src/cmd/disk/format.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1bd389b36SDavid du Colombier #include <u.h>
2bd389b36SDavid du Colombier #include <libc.h>
3bd389b36SDavid du Colombier 
4bd389b36SDavid du Colombier /*
5bd389b36SDavid du Colombier  *  floppy types (all MFM encoding)
6bd389b36SDavid du Colombier  */
7bd389b36SDavid du Colombier typedef struct Type	Type;
8bd389b36SDavid du Colombier struct Type
9bd389b36SDavid du Colombier {
10bd389b36SDavid du Colombier 	char	*name;
11bd389b36SDavid du Colombier 	int	bytes;		/* bytes/sector */
12bd389b36SDavid du Colombier 	int	sectors;	/* sectors/track */
13bd389b36SDavid du Colombier 	int	heads;		/* number of heads */
14bd389b36SDavid du Colombier 	int	tracks;		/* tracks/disk */
15bd389b36SDavid du Colombier 	int	media;		/* media descriptor byte */
16bd389b36SDavid du Colombier 	int	cluster;	/* default cluster size */
17bd389b36SDavid du Colombier };
18bd389b36SDavid du Colombier Type floppytype[] =
19bd389b36SDavid du Colombier {
20bd389b36SDavid du Colombier  { "3½HD",	512, 18, 2, 80,	0xf0, 1, },
21bd389b36SDavid du Colombier  { "3½DD",	512,  9, 2, 80,	0xf9, 2, },
22bd389b36SDavid du Colombier  { "5¼HD",	512, 15, 2, 80,	0xf9, 1, },
23bd389b36SDavid du Colombier  { "5¼DD",	512,  9, 2, 40,	0xfd, 2, },
24bd389b36SDavid du Colombier };
25bd389b36SDavid du Colombier #define NTYPES (sizeof(floppytype)/sizeof(Type))
26bd389b36SDavid du Colombier 
27bd389b36SDavid du Colombier typedef struct Dosboot	Dosboot;
28bd389b36SDavid du Colombier struct Dosboot{
29bd389b36SDavid du Colombier 	uchar	magic[3];	/* really an xx86 JMP instruction */
30bd389b36SDavid du Colombier 	uchar	version[8];
31bd389b36SDavid du Colombier 	uchar	sectsize[2];
32bd389b36SDavid du Colombier 	uchar	clustsize;
33bd389b36SDavid du Colombier 	uchar	nresrv[2];
34bd389b36SDavid du Colombier 	uchar	nfats;
35bd389b36SDavid du Colombier 	uchar	rootsize[2];
36bd389b36SDavid du Colombier 	uchar	volsize[2];
37bd389b36SDavid du Colombier 	uchar	mediadesc;
38bd389b36SDavid du Colombier 	uchar	fatsize[2];
39bd389b36SDavid du Colombier 	uchar	trksize[2];
40bd389b36SDavid du Colombier 	uchar	nheads[2];
41bd389b36SDavid du Colombier 	uchar	nhidden[4];
42bd389b36SDavid du Colombier 	uchar	bigvolsize[4];
43bd389b36SDavid du Colombier 	uchar	driveno;
44bd389b36SDavid du Colombier 	uchar	reserved0;
45bd389b36SDavid du Colombier 	uchar	bootsig;
46bd389b36SDavid du Colombier 	uchar	volid[4];
47bd389b36SDavid du Colombier 	uchar	label[11];
48*219b2ee8SDavid du Colombier 	uchar	type[8];
49bd389b36SDavid du Colombier };
50bd389b36SDavid du Colombier #define	PUTSHORT(p, v) { (p)[1] = (v)>>8; (p)[0] = (v); }
51bd389b36SDavid du Colombier #define	PUTLONG(p, v) { PUTSHORT((p), (v)); PUTSHORT((p)+2, (v)>>16); }
52bd389b36SDavid du Colombier 
53bd389b36SDavid du Colombier typedef struct Dosdir	Dosdir;
54bd389b36SDavid du Colombier struct Dosdir
55bd389b36SDavid du Colombier {
56bd389b36SDavid du Colombier 	uchar	name[8];
57bd389b36SDavid du Colombier 	uchar	ext[3];
58bd389b36SDavid du Colombier 	uchar	attr;
59bd389b36SDavid du Colombier 	uchar	reserved[10];
60bd389b36SDavid du Colombier 	uchar	time[2];
61bd389b36SDavid du Colombier 	uchar	date[2];
62bd389b36SDavid du Colombier 	uchar	start[2];
63bd389b36SDavid du Colombier 	uchar	length[4];
64bd389b36SDavid du Colombier };
65bd389b36SDavid du Colombier 
66bd389b36SDavid du Colombier #define	DRONLY	0x01
67bd389b36SDavid du Colombier #define	DHIDDEN	0x02
68bd389b36SDavid du Colombier #define	DSYSTEM	0x04
69bd389b36SDavid du Colombier #define	DVLABEL	0x08
70bd389b36SDavid du Colombier #define	DDIR	0x10
71bd389b36SDavid du Colombier #define	DARCH	0x20
72bd389b36SDavid du Colombier 
73bd389b36SDavid du Colombier /*
74*219b2ee8SDavid du Colombier  *  the boot program for the boot sector.
75bd389b36SDavid du Colombier  */
76bd389b36SDavid du Colombier uchar bootprog[512] =
77bd389b36SDavid du Colombier {
78*219b2ee8SDavid du Colombier [0x000]	0xEB, 0x3C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
79bd389b36SDavid du Colombier 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80*219b2ee8SDavid du Colombier [0x03E] 0xFA, 0xFC, 0x8C, 0xC8, 0x8E, 0xD8, 0x8E, 0xD0,
81*219b2ee8SDavid du Colombier 	0xBC, 0x00, 0x7C, 0xBE, 0x77, 0x7C, 0xE8, 0x19,
82*219b2ee8SDavid du Colombier 	0x00, 0x33, 0xC0, 0xCD, 0x16, 0xBB, 0x40, 0x00,
83*219b2ee8SDavid du Colombier 	0x8E, 0xC3, 0xBB, 0x72, 0x00, 0xB8, 0x34, 0x12,
84*219b2ee8SDavid du Colombier 	0x26, 0x89, 0x07, 0xEA, 0x00, 0x00, 0xFF, 0xFF,
85*219b2ee8SDavid du Colombier 	0xEB, 0xD6, 0xAC, 0x0A, 0xC0, 0x74, 0x09, 0xB4,
86*219b2ee8SDavid du Colombier 	0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2,
87*219b2ee8SDavid du Colombier 	0xC3,  'N',  'o',  't',  ' ',  'a',  ' ',  'b',
88*219b2ee8SDavid du Colombier 	 'o',  'o',  't',  'a',  'b',  'l',  'e',  ' ',
89*219b2ee8SDavid du Colombier 	 'd',  'i',  's',  'c',  ' ',  'o',  'r',  ' ',
90*219b2ee8SDavid du Colombier 	 'd',  'i',  's',  'c',  ' ',  'e',  'r',  'r',
91*219b2ee8SDavid du Colombier 	 'o',  'r', '\r', '\n',  'P',  'r',  'e',  's',
92*219b2ee8SDavid du Colombier 	 's',  ' ',  'a',  'l',  'm',  'o',  's',  't',
93*219b2ee8SDavid du Colombier 	 ' ',  'a',  'n',  'y',  ' ',  'k',  'e',  'y',
94*219b2ee8SDavid du Colombier 	 ' ',  't',  'o',  ' ',  'r',  'e',  'b',  'o',
95*219b2ee8SDavid du Colombier 	 'o',  't',  '.',  '.',  '.', 0x00, 0x00, 0x00,
96*219b2ee8SDavid du Colombier [0x1F0]	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97*219b2ee8SDavid du Colombier 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA,
98bd389b36SDavid du Colombier };
99bd389b36SDavid du Colombier 
100bd389b36SDavid du Colombier char *dev;
101bd389b36SDavid du Colombier int clustersize;
102bd389b36SDavid du Colombier uchar *fat;	/* the fat */
103bd389b36SDavid du Colombier int fatbits;
104bd389b36SDavid du Colombier int fatsecs;
105bd389b36SDavid du Colombier int fatlast;	/* last cluster allocated */
106bd389b36SDavid du Colombier int clusters;
107bd389b36SDavid du Colombier int fatsecs;
108bd389b36SDavid du Colombier int volsecs;
109bd389b36SDavid du Colombier uchar *root;	/* first block of root */
110bd389b36SDavid du Colombier int rootsecs;
111bd389b36SDavid du Colombier int rootfiles;
112bd389b36SDavid du Colombier int rootnext;
113bd389b36SDavid du Colombier Type *t;
114*219b2ee8SDavid du Colombier int fflag;
115*219b2ee8SDavid du Colombier char file[64];	/* output file name */
116*219b2ee8SDavid du Colombier char *bootfile;
117*219b2ee8SDavid du Colombier char *type;
118bd389b36SDavid du Colombier 
119bd389b36SDavid du Colombier enum
120bd389b36SDavid du Colombier {
121bd389b36SDavid du Colombier 	Sof = 1,	/* start of file */
122bd389b36SDavid du Colombier 	Eof = 2,	/* end of file */
123bd389b36SDavid du Colombier };
124bd389b36SDavid du Colombier 
125bd389b36SDavid du Colombier 
126*219b2ee8SDavid du Colombier void	dosfs(int, char*, int, char*[]);
127bd389b36SDavid du Colombier ulong	clustalloc(int);
128*219b2ee8SDavid du Colombier void	addrname(uchar*, Dir*, ulong);
129bd389b36SDavid du Colombier 
130bd389b36SDavid du Colombier void
131bd389b36SDavid du Colombier usage(void)
132bd389b36SDavid du Colombier {
133*219b2ee8SDavid du Colombier 	fprint(2, "usage: format [-b bfile] [-c csize] [-df] [-l label] [-t type] file [args ...]\n");
134bd389b36SDavid du Colombier 	exits("usage");
135bd389b36SDavid du Colombier }
136bd389b36SDavid du Colombier 
137bd389b36SDavid du Colombier void
138bd389b36SDavid du Colombier fatal(char *fmt, ...)
139bd389b36SDavid du Colombier {
140bd389b36SDavid du Colombier 	int n;
141bd389b36SDavid du Colombier 	char err[128];
142bd389b36SDavid du Colombier 
143bd389b36SDavid du Colombier 	n = doprint(err, err+sizeof(err), fmt, &fmt+1) - err;
144bd389b36SDavid du Colombier 	err[n] = 0;
145bd389b36SDavid du Colombier 	fprint(2, "format: %s\n", err);
146*219b2ee8SDavid du Colombier 	if(fflag && file[0])
147*219b2ee8SDavid du Colombier 		remove(file);
148bd389b36SDavid du Colombier 	exits(err);
149bd389b36SDavid du Colombier }
150bd389b36SDavid du Colombier 
151bd389b36SDavid du Colombier void
152bd389b36SDavid du Colombier main(int argc, char **argv)
153bd389b36SDavid du Colombier {
154*219b2ee8SDavid du Colombier 	int n, dos;
155bd389b36SDavid du Colombier 	int cfd;
156bd389b36SDavid du Colombier 	char buf[512];
157bd389b36SDavid du Colombier 	char label[11];
158bd389b36SDavid du Colombier 	char *a;
159bd389b36SDavid du Colombier 
160bd389b36SDavid du Colombier 	dos = 0;
161*219b2ee8SDavid du Colombier 	type = 0;
162bd389b36SDavid du Colombier 	clustersize = 0;
163*219b2ee8SDavid du Colombier 	memmove(label, "CYLINDRICAL", sizeof(label));
164bd389b36SDavid du Colombier 	ARGBEGIN {
165*219b2ee8SDavid du Colombier 	case 'b':
166*219b2ee8SDavid du Colombier 		bootfile = ARGF();
167*219b2ee8SDavid du Colombier 		break;
168bd389b36SDavid du Colombier 	case 'd':
169bd389b36SDavid du Colombier 		dos = 1;
170bd389b36SDavid du Colombier 		break;
171bd389b36SDavid du Colombier 	case 'c':
172bd389b36SDavid du Colombier 		clustersize = atoi(ARGF());
173bd389b36SDavid du Colombier 		break;
174*219b2ee8SDavid du Colombier 	case 'f':
175*219b2ee8SDavid du Colombier 		fflag = 1;
176*219b2ee8SDavid du Colombier 		break;
177bd389b36SDavid du Colombier 	case 'l':
178bd389b36SDavid du Colombier 		a = ARGF();
179bd389b36SDavid du Colombier 		n = strlen(a);
180bd389b36SDavid du Colombier 		if(n > sizeof(label))
181bd389b36SDavid du Colombier 			n = sizeof(label);
182bd389b36SDavid du Colombier 		memmove(label, a, n);
183*219b2ee8SDavid du Colombier 		while(n < sizeof(label))
184*219b2ee8SDavid du Colombier 			label[n++] = ' ';
185bd389b36SDavid du Colombier 		break;
186*219b2ee8SDavid du Colombier 	case 't':
187*219b2ee8SDavid du Colombier 		type = ARGF();
188bd389b36SDavid du Colombier 		break;
189bd389b36SDavid du Colombier 	default:
190bd389b36SDavid du Colombier 		usage();
191bd389b36SDavid du Colombier 	} ARGEND
192bd389b36SDavid du Colombier 
193bd389b36SDavid du Colombier 	if(argc < 1)
194bd389b36SDavid du Colombier 		usage();
195*219b2ee8SDavid du Colombier 
196*219b2ee8SDavid du Colombier 	dev = argv[0];
197*219b2ee8SDavid du Colombier 	cfd = -1;
198*219b2ee8SDavid du Colombier 	if(fflag == 0){
199bd389b36SDavid du Colombier 		n = strlen(argv[0]);
200bd389b36SDavid du Colombier 		if(n > 4 && strcmp(argv[0]+n-4, "disk") == 0)
201bd389b36SDavid du Colombier 			*(argv[0]+n-4) = 0;
202*219b2ee8SDavid du Colombier 		else if(n > 3 && strcmp(argv[0]+n-3, "ctl") == 0)
203bd389b36SDavid du Colombier 			*(argv[0]+n-3) = 0;
204bd389b36SDavid du Colombier 
205bd389b36SDavid du Colombier 		sprint(buf, "%sctl", dev);
206bd389b36SDavid du Colombier 		cfd = open(buf, ORDWR);
207bd389b36SDavid du Colombier 		if(cfd < 0)
208bd389b36SDavid du Colombier 			fatal("opening %s: %r", buf);
209bd389b36SDavid du Colombier 		print("Formatting floppy %s\n", dev);
210*219b2ee8SDavid du Colombier 		if(type)
211*219b2ee8SDavid du Colombier 			sprint(buf, "format %s", type);
212bd389b36SDavid du Colombier 		else
213bd389b36SDavid du Colombier 			strcpy(buf, "format");
214bd389b36SDavid du Colombier 		if(write(cfd, buf, strlen(buf)) < 0)
215bd389b36SDavid du Colombier 			fatal("formatting tracks: %r");
216bd389b36SDavid du Colombier 	}
217bd389b36SDavid du Colombier 
218bd389b36SDavid du Colombier 	if(dos)
219*219b2ee8SDavid du Colombier 		dosfs(cfd, label, argc-1, argv+1);
220*219b2ee8SDavid du Colombier 	if(cfd >= 0)
221bd389b36SDavid du Colombier 		close(cfd);
222bd389b36SDavid du Colombier 	exits(0);
223bd389b36SDavid du Colombier }
224bd389b36SDavid du Colombier 
225bd389b36SDavid du Colombier void
226*219b2ee8SDavid du Colombier dosfs(int cfd, char *label, int argc, char *argv[])
227bd389b36SDavid du Colombier {
228bd389b36SDavid du Colombier 	char r[16];
229bd389b36SDavid du Colombier 	Dosboot *b;
230bd389b36SDavid du Colombier 	uchar *buf;
231bd389b36SDavid du Colombier 	Dir d;
232*219b2ee8SDavid du Colombier 	int n, fd, sysfd;
233*219b2ee8SDavid du Colombier 	ulong length, x;
234*219b2ee8SDavid du Colombier 	uchar *p;
235bd389b36SDavid du Colombier 
236*219b2ee8SDavid du Colombier 	print("Initialising MS-DOS file system\n");
237bd389b36SDavid du Colombier 
238*219b2ee8SDavid du Colombier 	if(fflag){
239*219b2ee8SDavid du Colombier 		sprint(file, "%s", dev);
240*219b2ee8SDavid du Colombier 		if((fd = create(dev, ORDWR, 0666)) < 0)
241*219b2ee8SDavid du Colombier 			fatal("create %s: %r", file);
242*219b2ee8SDavid du Colombier 		t = floppytype;
243*219b2ee8SDavid du Colombier 		if(type){
244*219b2ee8SDavid du Colombier 			for(t = floppytype; t < &floppytype[NTYPES]; t++)
245*219b2ee8SDavid du Colombier 				if(strcmp(type, t->name) == 0)
246*219b2ee8SDavid du Colombier 					break;
247*219b2ee8SDavid du Colombier 			if(t == &floppytype[NTYPES])
248*219b2ee8SDavid du Colombier 				fatal("unknown floppy type %s", type);
249*219b2ee8SDavid du Colombier 		}
250*219b2ee8SDavid du Colombier 		length = t->bytes*t->sectors*t->heads*t->tracks;
251*219b2ee8SDavid du Colombier 	}
252*219b2ee8SDavid du Colombier 	else{
253bd389b36SDavid du Colombier 		sprint(file, "%sdisk", dev);
254bd389b36SDavid du Colombier 		fd = open(file, ORDWR);
255bd389b36SDavid du Colombier 		if(fd < 0)
256*219b2ee8SDavid du Colombier 			fatal("open %s: %r", file);
257bd389b36SDavid du Colombier 		if(dirfstat(fd, &d) < 0)
258*219b2ee8SDavid du Colombier 			fatal("stat %s: %r", file);
259*219b2ee8SDavid du Colombier 		length = d.length;
260bd389b36SDavid du Colombier 
261bd389b36SDavid du Colombier 		t = 0;
262bd389b36SDavid du Colombier 		seek(cfd, 0, 0);
263bd389b36SDavid du Colombier 		n = read(cfd, file, sizeof(file)-1);
264bd389b36SDavid du Colombier 		if(n < 0)
265bd389b36SDavid du Colombier 			fatal("reading floppy type");
266bd389b36SDavid du Colombier 		else {
267bd389b36SDavid du Colombier 			file[n] = 0;
268bd389b36SDavid du Colombier 			for(t = floppytype; t < &floppytype[NTYPES]; t++)
269bd389b36SDavid du Colombier 				if(strcmp(file, t->name) == 0)
270bd389b36SDavid du Colombier 					break;
271bd389b36SDavid du Colombier 			if(t == &floppytype[NTYPES])
272bd389b36SDavid du Colombier 				fatal("unknown floppy type %s", file);
273bd389b36SDavid du Colombier 		}
274*219b2ee8SDavid du Colombier 	}
275bd389b36SDavid du Colombier 	print("floppy type %s, %d tracks, %d heads, %d sectors/track, %d bytes/sec\n",
276bd389b36SDavid du Colombier 		t->name, t->tracks, t->heads, t->sectors, t->bytes);
277bd389b36SDavid du Colombier 
278bd389b36SDavid du Colombier 	if(clustersize == 0)
279bd389b36SDavid du Colombier 		clustersize = t->cluster;
280*219b2ee8SDavid du Colombier 	clusters = length/(t->bytes*clustersize);
281bd389b36SDavid du Colombier 	if(clusters < 4087)
282bd389b36SDavid du Colombier 		fatbits = 12;
283bd389b36SDavid du Colombier 	else
284bd389b36SDavid du Colombier 		fatbits = 16;
285*219b2ee8SDavid du Colombier 	volsecs = length/t->bytes;
286bd389b36SDavid du Colombier 	fatsecs = (fatbits*clusters + 8*t->bytes - 1)/(8*t->bytes);
287bd389b36SDavid du Colombier 	rootsecs = volsecs/200;
288*219b2ee8SDavid du Colombier 	rootfiles = rootsecs * (t->bytes/sizeof(Dosdir));
289bd389b36SDavid du Colombier 	buf = malloc(t->bytes);
290bd389b36SDavid du Colombier 	if(buf == 0)
291bd389b36SDavid du Colombier 		fatal("out of memory");
292bd389b36SDavid du Colombier 
293bd389b36SDavid du Colombier 	/*
294bd389b36SDavid du Colombier 	 *  write bootstrap & parameter block
295bd389b36SDavid du Colombier 	 */
296*219b2ee8SDavid du Colombier 	if(bootfile){
297*219b2ee8SDavid du Colombier 		if((sysfd = open(bootfile, OREAD)) < 0)
298*219b2ee8SDavid du Colombier 			fatal("open %s: %r", bootfile);
299*219b2ee8SDavid du Colombier 		if(read(sysfd, buf, t->bytes) < 0)
300*219b2ee8SDavid du Colombier 			fatal("read %s: %r", bootfile);
301*219b2ee8SDavid du Colombier 		close(sysfd);
302*219b2ee8SDavid du Colombier 	}
303*219b2ee8SDavid du Colombier 	else
304bd389b36SDavid du Colombier 		memmove(buf, bootprog, sizeof(bootprog));
305bd389b36SDavid du Colombier 	b = (Dosboot*)buf;
306*219b2ee8SDavid du Colombier 	b->magic[0] = 0xEB;
307*219b2ee8SDavid du Colombier 	b->magic[1] = 0x3C;
308*219b2ee8SDavid du Colombier 	b->magic[2] = 0x90;
309*219b2ee8SDavid du Colombier 	memmove(b->version, "Plan9.00", sizeof(b->version));
310bd389b36SDavid du Colombier 	PUTSHORT(b->sectsize, t->bytes);
311bd389b36SDavid du Colombier 	b->clustsize = clustersize;
312bd389b36SDavid du Colombier 	PUTSHORT(b->nresrv, 1);
313bd389b36SDavid du Colombier 	b->nfats = 2;
314bd389b36SDavid du Colombier 	PUTSHORT(b->rootsize, rootfiles);
315bd389b36SDavid du Colombier 	if(volsecs < (1<<16)){
316bd389b36SDavid du Colombier 		PUTSHORT(b->volsize, volsecs);
317bd389b36SDavid du Colombier 	}
318bd389b36SDavid du Colombier 	PUTLONG(b->bigvolsize, volsecs);
319bd389b36SDavid du Colombier 	b->mediadesc = t->media;
320bd389b36SDavid du Colombier 	PUTSHORT(b->fatsize, fatsecs);
321bd389b36SDavid du Colombier 	PUTSHORT(b->trksize, t->sectors);
322bd389b36SDavid du Colombier 	PUTSHORT(b->nheads, t->heads);
323bd389b36SDavid du Colombier 	PUTLONG(b->nhidden, 0);
324bd389b36SDavid du Colombier 	b->driveno = 0;
325bd389b36SDavid du Colombier 	b->bootsig = 0x29;
326bd389b36SDavid du Colombier 	x = time(0);
327bd389b36SDavid du Colombier 	PUTLONG(b->volid, x);
328bd389b36SDavid du Colombier 	memmove(b->label, label, sizeof(b->label));
329bd389b36SDavid du Colombier 	sprint(r, "FAT%d    ", fatbits);
330*219b2ee8SDavid du Colombier 	memmove(b->type, r, sizeof(b->type));
331*219b2ee8SDavid du Colombier 	buf[t->bytes-2] = 0x55;
332*219b2ee8SDavid du Colombier 	buf[t->bytes-1] = 0xAA;
333*219b2ee8SDavid du Colombier 	if(seek(fd, 0, 0) < 0)
334*219b2ee8SDavid du Colombier 		fatal("seek to boot sector: %r\n");
335bd389b36SDavid du Colombier 	if(write(fd, buf, t->bytes) != t->bytes)
336bd389b36SDavid du Colombier 		fatal("writing boot sector: %r");
337bd389b36SDavid du Colombier 	free(buf);
338bd389b36SDavid du Colombier 
339bd389b36SDavid du Colombier 	/*
340bd389b36SDavid du Colombier 	 *  allocate an in memory fat
341bd389b36SDavid du Colombier 	 */
342bd389b36SDavid du Colombier 	fat = malloc(fatsecs*t->bytes);
343bd389b36SDavid du Colombier 	if(fat == 0)
344bd389b36SDavid du Colombier 		fatal("out of memory");
345*219b2ee8SDavid du Colombier 	memset(fat, 0, fatsecs*t->bytes);
346bd389b36SDavid du Colombier 	fat[0] = t->media;
347bd389b36SDavid du Colombier 	fat[1] = 0xff;
348bd389b36SDavid du Colombier 	fat[2] = 0xff;
349bd389b36SDavid du Colombier 	if(fatbits == 16)
350bd389b36SDavid du Colombier 		fat[3] = 0xff;
351bd389b36SDavid du Colombier 	fatlast = 1;
352bd389b36SDavid du Colombier 	seek(fd, 2*fatsecs*t->bytes, 1);	/* 2 fats */
353bd389b36SDavid du Colombier 
354bd389b36SDavid du Colombier 	/*
355bd389b36SDavid du Colombier 	 *  allocate an in memory root
356bd389b36SDavid du Colombier 	 */
357bd389b36SDavid du Colombier 	root = malloc(rootsecs*t->bytes);
358bd389b36SDavid du Colombier 	if(root == 0)
359bd389b36SDavid du Colombier 		fatal("out of memory");
360*219b2ee8SDavid du Colombier 	memset(root, 0, rootsecs*t->bytes);
361*219b2ee8SDavid du Colombier 	seek(fd, rootsecs*t->bytes, 1);		/* rootsecs */
362bd389b36SDavid du Colombier 
363bd389b36SDavid du Colombier 	/*
364*219b2ee8SDavid du Colombier 	 * Now positioned at the Files Area.
365*219b2ee8SDavid du Colombier 	 * If we have any arguments, process
366*219b2ee8SDavid du Colombier 	 * them and write out.
367bd389b36SDavid du Colombier 	 */
368*219b2ee8SDavid du Colombier 	for(p = root; argc > 0; argc--, argv++, p += sizeof(Dosdir)){
369*219b2ee8SDavid du Colombier 		if(p >= (root+(rootsecs*t->bytes)))
370*219b2ee8SDavid du Colombier 			fatal("too many files in root");
371*219b2ee8SDavid du Colombier 		/*
372*219b2ee8SDavid du Colombier 		 * Open the file and get its length.
373*219b2ee8SDavid du Colombier 		 */
374*219b2ee8SDavid du Colombier 		if((sysfd = open(*argv, OREAD)) < 0)
375*219b2ee8SDavid du Colombier 			fatal("open %s: %r", *argv);
376*219b2ee8SDavid du Colombier 		if(dirfstat(sysfd, &d) < 0)
377*219b2ee8SDavid du Colombier 			fatal("stat %s: %r", *argv);
378*219b2ee8SDavid du Colombier 		print("Adding file %s, length %ld\n", *argv, d.length);
379*219b2ee8SDavid du Colombier 
380*219b2ee8SDavid du Colombier 		length = d.length;
381*219b2ee8SDavid du Colombier 		if(length){
382*219b2ee8SDavid du Colombier 			/*
383*219b2ee8SDavid du Colombier 			 * Allocate a buffer to read the entire file into.
384*219b2ee8SDavid du Colombier 			 * This must be rounded up to a cluster boundary.
385*219b2ee8SDavid du Colombier 			 *
386*219b2ee8SDavid du Colombier 			 * Read the file and write it out to the Files Area.
387*219b2ee8SDavid du Colombier 			 */
388*219b2ee8SDavid du Colombier 			length += t->bytes*clustersize - 1;
389*219b2ee8SDavid du Colombier 			length /= t->bytes*clustersize;
390*219b2ee8SDavid du Colombier 			length *= t->bytes*clustersize;
391*219b2ee8SDavid du Colombier 			if((buf = malloc(length)) == 0)
392*219b2ee8SDavid du Colombier 				fatal("out of memory");
393*219b2ee8SDavid du Colombier 
394*219b2ee8SDavid du Colombier 			if(read(sysfd, buf, d.length) < 0)
395*219b2ee8SDavid du Colombier 				fatal("read %s: %r", *argv);
396*219b2ee8SDavid du Colombier 			memset(buf+d.length, 0, length-d.length);
397*219b2ee8SDavid du Colombier 			if(write(fd, buf, length) < 0)
398*219b2ee8SDavid du Colombier 				fatal("write %s: %r", *argv);
399*219b2ee8SDavid du Colombier 			free(buf);
400*219b2ee8SDavid du Colombier 
401*219b2ee8SDavid du Colombier 			close(sysfd);
402*219b2ee8SDavid du Colombier 
403*219b2ee8SDavid du Colombier 			/*
404*219b2ee8SDavid du Colombier 			 * Allocate the FAT clusters.
405*219b2ee8SDavid du Colombier 			 * We're assuming here that where we
406*219b2ee8SDavid du Colombier 			 * wrote the file is in sync with
407*219b2ee8SDavid du Colombier 			 * the cluster allocation.
408*219b2ee8SDavid du Colombier 			 * Save the starting cluster.
409*219b2ee8SDavid du Colombier 			 */
410*219b2ee8SDavid du Colombier 			length /= t->bytes*clustersize;
411*219b2ee8SDavid du Colombier 			x = clustalloc(Sof);
412*219b2ee8SDavid du Colombier 			for(n = 0; n < length-1; n++)
413*219b2ee8SDavid du Colombier 				clustalloc(0);
414*219b2ee8SDavid du Colombier 			clustalloc(Eof);
415*219b2ee8SDavid du Colombier 		}
416*219b2ee8SDavid du Colombier 		else
417*219b2ee8SDavid du Colombier 			x = 0;
418*219b2ee8SDavid du Colombier 
419*219b2ee8SDavid du Colombier 		/*
420*219b2ee8SDavid du Colombier 		 * Add the filename to the root.
421*219b2ee8SDavid du Colombier 		 */
422*219b2ee8SDavid du Colombier 		addrname(p, &d, x);
423*219b2ee8SDavid du Colombier 	}
424bd389b36SDavid du Colombier 
425bd389b36SDavid du Colombier 	/*
426bd389b36SDavid du Colombier 	 *  write the fats and root
427bd389b36SDavid du Colombier 	 */
428bd389b36SDavid du Colombier 	seek(fd, t->bytes, 0);
429bd389b36SDavid du Colombier 	if(write(fd, fat, fatsecs*t->bytes) < 0)
430bd389b36SDavid du Colombier 		fatal("writing fat #1: %r");
431bd389b36SDavid du Colombier 	if(write(fd, fat, fatsecs*t->bytes) < 0)
432bd389b36SDavid du Colombier 		fatal("writing fat #2: %r");
433bd389b36SDavid du Colombier 	if(write(fd, root, rootsecs*t->bytes) < 0)
434bd389b36SDavid du Colombier 		fatal("writing root: %r");
435*219b2ee8SDavid du Colombier 
436*219b2ee8SDavid du Colombier 	if(fflag){
437*219b2ee8SDavid du Colombier 		seek(fd, t->bytes*t->sectors*t->heads*t->tracks-1, 0);
438*219b2ee8SDavid du Colombier 		write(fd, "9", 1);
439*219b2ee8SDavid du Colombier 	}
440bd389b36SDavid du Colombier }
441bd389b36SDavid du Colombier 
442bd389b36SDavid du Colombier /*
443bd389b36SDavid du Colombier  *  allocate a cluster
444bd389b36SDavid du Colombier  */
445bd389b36SDavid du Colombier ulong
446bd389b36SDavid du Colombier clustalloc(int flag)
447bd389b36SDavid du Colombier {
448bd389b36SDavid du Colombier 	ulong o, x;
449bd389b36SDavid du Colombier 
450bd389b36SDavid du Colombier 	if(flag != Sof){
451bd389b36SDavid du Colombier 		x = (flag == Eof) ? 0xffff : (fatlast+1);
452bd389b36SDavid du Colombier 		if(fatbits == 12){
453bd389b36SDavid du Colombier 			x &= 0xfff;
454bd389b36SDavid du Colombier 			o = (3*fatlast)/2;
455bd389b36SDavid du Colombier 			if(fatlast & 1){
456bd389b36SDavid du Colombier 				fat[o] = (fat[o]&0x0f) | (x<<4);
457*219b2ee8SDavid du Colombier 				fat[o+1] = (x>>4);
458bd389b36SDavid du Colombier 			} else {
459bd389b36SDavid du Colombier 				fat[o] = x;
460*219b2ee8SDavid du Colombier 				fat[o+1] = (fat[o+1]&0xf0) | ((x>>8) & 0x0F);
461bd389b36SDavid du Colombier 			}
462bd389b36SDavid du Colombier 		} else {
463bd389b36SDavid du Colombier 			o = 2*fatlast;
464bd389b36SDavid du Colombier 			fat[o] = x;
465bd389b36SDavid du Colombier 			fat[o+1] = x>>8;
466bd389b36SDavid du Colombier 		}
467bd389b36SDavid du Colombier 	}
468bd389b36SDavid du Colombier 
469bd389b36SDavid du Colombier 	if(flag == Eof)
470bd389b36SDavid du Colombier 		return 0;
471bd389b36SDavid du Colombier 	else
472bd389b36SDavid du Colombier 		return ++fatlast;
473bd389b36SDavid du Colombier }
474bd389b36SDavid du Colombier 
475bd389b36SDavid du Colombier void
476*219b2ee8SDavid du Colombier putname(char *p, Dosdir *d)
477bd389b36SDavid du Colombier {
478*219b2ee8SDavid du Colombier 	int i;
479bd389b36SDavid du Colombier 
480*219b2ee8SDavid du Colombier 	memset(d->name, ' ', sizeof d->name+sizeof d->ext);
481*219b2ee8SDavid du Colombier 	for(i = 0; i< sizeof(d->name); i++){
482*219b2ee8SDavid du Colombier 		if(*p == 0 || *p == '.')
483bd389b36SDavid du Colombier 			break;
484*219b2ee8SDavid du Colombier 		d->name[i] = toupper(*p++);
485bd389b36SDavid du Colombier 	}
486*219b2ee8SDavid du Colombier 	p = strrchr(p, '.');
487*219b2ee8SDavid du Colombier 	if(p){
488*219b2ee8SDavid du Colombier 		for(i = 0; i < sizeof d->ext; i++){
489*219b2ee8SDavid du Colombier 			if(*++p == 0)
490*219b2ee8SDavid du Colombier 				break;
491*219b2ee8SDavid du Colombier 			d->ext[i] = toupper(*p);
492*219b2ee8SDavid du Colombier 		}
493*219b2ee8SDavid du Colombier 	}
494*219b2ee8SDavid du Colombier }
495bd389b36SDavid du Colombier 
496*219b2ee8SDavid du Colombier void
497*219b2ee8SDavid du Colombier puttime(Dosdir *d)
498*219b2ee8SDavid du Colombier {
499*219b2ee8SDavid du Colombier 	Tm *t = localtime(time(0));
500*219b2ee8SDavid du Colombier 	ushort x;
501*219b2ee8SDavid du Colombier 
502*219b2ee8SDavid du Colombier 	x = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
503*219b2ee8SDavid du Colombier 	d->time[0] = x;
504*219b2ee8SDavid du Colombier 	d->time[1] = x>>8;
505*219b2ee8SDavid du Colombier 	x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
506*219b2ee8SDavid du Colombier 	d->date[0] = x;
507*219b2ee8SDavid du Colombier 	d->date[1] = x>>8;
508*219b2ee8SDavid du Colombier }
509*219b2ee8SDavid du Colombier 
510*219b2ee8SDavid du Colombier void
511*219b2ee8SDavid du Colombier addrname(uchar *entry, Dir *dir, ulong start)
512*219b2ee8SDavid du Colombier {
513*219b2ee8SDavid du Colombier 	Dosdir *d;
514*219b2ee8SDavid du Colombier 
515*219b2ee8SDavid du Colombier 	d = (Dosdir*)entry;
516*219b2ee8SDavid du Colombier 	putname(dir->name, d);
517*219b2ee8SDavid du Colombier 	d->attr = DRONLY;
518*219b2ee8SDavid du Colombier 	puttime(d);
519*219b2ee8SDavid du Colombier 	d->start[0] = start;
520*219b2ee8SDavid du Colombier 	d->start[1] = start>>8;
521*219b2ee8SDavid du Colombier 	d->length[0] = dir->length;
522*219b2ee8SDavid du Colombier 	d->length[1] = dir->length>>8;
523*219b2ee8SDavid du Colombier 	d->length[2] = dir->length>>16;
524*219b2ee8SDavid du Colombier 	d->length[3] = dir->length>>24;
525bd389b36SDavid du Colombier }
526