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