|
|
1.1 root 1: /* #define DEBUG 1 */
2: /* dos3.c */
3:
4: #include "dos0.h"
5:
6: MDIR *smdp;
7: DIR *sdp;
8: char *scp, *sname;
9: char *trim();
10:
11: /*
12: * Find the given filename relative to the given directory.
13: * Return a pointer to the MDIR identifying the file, or NULL if not found.
14: * Store a DIR pointer through the supplied dpp.
15: * The stored DIR pointer gives the containing DIR for non-directory files
16: * and the subdirectory DIR for directories.
17: */
18: MDIR *
19: find(name, dp, dpp) char *name; register DIR *dp; DIR **dpp;
20: {
21: register MDIR *mdp;
22: register char *s;
23: register char *cp;
24: char *tname;
25:
26: dbprintf(("find(%s)\n", name));
27: if ((s = strchr(name, '/')) == NULL)
28: {
29: /* No pathname, look for name in the directory. */
30: tname = trim(name);
31: cp = dosname(tname);
32: for (mdp = dp->d_dir; mdp < dp->d_edp; mdp++)
33: {
34: s = mdp->m_name;
35: if ((*s == MEMPTY) || (*s == MFREE))
36: continue;
37: dbprintf(("lmatch(%s,%s) = %d\n", tname, cohn(s),
38: lmatch(tname, cohn(s))));
39: if (lmatch(tname, cohn(s)) == 1)
40: {
41: if((strncmp (s, cp, 11) ==0) && isdir(mdp))
42: {
43: /* Subdirectory, find its DIR. */
44: for (dp = dp->d_child; dp != NULL;
45: dp = dp->d_sibling)
46: if (strncmp(dp->d_dname, cp,
47: 11) == 0)
48: break;
49: if (dp == NULL)
50: fatal("find subdirectory botch");
51: /* Read in the MDIR if necessary. */
52: if (dp->d_dir == NULL)
53: readmdir(dp);
54: }
55: if (dpp != NULL)
56: *dpp = dp;
57: smdp = mdp;
58: scp = cp;
59: sdp = dp;
60: sname = name;
61: return mdp;
62: }
63: }
64: return NULL;
65: }
66: else if (s == name)
67: return find(++s, dp, dpp); /* "/foo" means look for "foo" */
68: /* Explicit pathname, find the directory and recur. */
69: *s = '\0'; /* NUL-terminate dirname */
70: cp = dosname(name);
71: *s++ = '/'; /* Restore the '/' */
72: for (dp = dp->d_child; dp != NULL; dp = dp->d_sibling)
73: if (strncmp(dp->d_dname, cp, 11) == 0)
74: break;
75: if (dp == NULL)
76: return NULL; /* Not found */
77: if (dp->d_dir == NULL)
78: readmdir(dp);
79: return find(s, dp, dpp);
80: }
81:
82: MDIR *
83: findnext(dpp) DIR **dpp;
84: {
85: register MDIR *mdp = ++smdp;
86: register char *s;
87: register char *cp = scp;
88: register DIR *dp = sdp;
89:
90: dbprintf(("findnext(%s)\n", sname));
91: for (; mdp < dp->d_edp; mdp++)
92: {
93: s = mdp->m_name;
94: if ((*s == MEMPTY) || (*s == MFREE))
95: continue;
96: dbprintf(("lmatch(%s,%s) = %d\n", sname, cohn(s), lmatch(sname, cohn(s))));
97: if (lmatch(sname, cohn(s)) == 1)
98: {
99: if ((strncmp (s, cp, 11) ==0) && isdir(mdp))
100: {
101: /* Subdirectory, find its DIR. */
102: for (dp = dp->d_child; dp != NULL;
103: dp = dp->d_sibling)
104: if (strncmp(dp->d_dname, cp, 11) == 0)
105: break;
106: if (dp == NULL)
107: fatal("find subdirectory botch");
108: /* Read in the MDIR if necessary. */
109: if (dp->d_dir == NULL)
110: readmdir(dp);
111: }
112: if (dpp != NULL)
113: *dpp = dp;
114: smdp = mdp;
115: return mdp;
116: }
117: }
118: return NULL;
119: }
120:
121:
122: /*
123: * See if a pattern matches a string.
124: * '\' escapes the next character.
125: */
126: lmatch(pp, sp)
127: register char *pp;
128: register char *sp;
129: {
130: short c2;
131: register short c1;
132:
133: if ((*sp == '.') && ((sp[1] == '.') || (sp[1] == '\0')))
134: return 0;
135:
136: if ((strcspn(pp, " ") == 0) && (strcspn(sp, " ") == 0))
137: return 1;
138: while ((c1=*pp++)) {
139: switch (c1) {
140: case '?':
141: if (*sp++)
142: continue;
143: return (0);
144: case '*':
145: do {
146: if (lmatch(pp, sp))
147: return (1);
148: } while (*sp++);
149: return (0);
150: case '[':
151: if ((c2=*sp++) == '\0')
152: return (0);
153: for (;;) {
154: if ((c1=*pp++) == '\0' || c1 == ']')
155: return (0);
156: if (c1 == '\\' && (c1=*pp++) == '\0')
157: return (0);
158: if (c1 == c2)
159: break;
160: if (*pp == '-') {
161: pp += 1;
162: if (c2 < c1)
163: continue;
164: if ((c1=*pp++) == '\0')
165: return (0);
166: if (c1 == '\\' && (c1=*pp++) == '\0')
167: return (0);
168: if (c2 <= c1)
169: break;
170: }
171: }
172: while ((c1 = *pp++) != ']') {
173: if (c1 == '\0')
174: return (0);
175: if (c1 == '\\' && *pp++ == '\0')
176: return (0);
177: }
178: continue;
179: case '\\':
180: if ((c1=*pp++) == '\0')
181: return (0);
182: /* fall through */
183: default:
184: if (c1 == *sp++)
185: continue;
186: return (0);
187: }
188: }
189: return (*sp=='\0');
190: }
191:
192:
193: char *
194: trim(name) register char *name;
195: {
196: register char *s, *dotp;
197: char c;
198: static char buf[16];
199:
200: dotp = strrchr(name, '.');
201: if (dotp == name)
202: dotp = NULL;
203: for (s = buf; name != dotp && (c = *name) != '\0'; name++)
204: if (s < &buf[8]) /* copy name */
205: *s++ = (c == '.') ? '_' : c;
206: if (name++ == dotp) {
207: *s++ = '.';
208: for ( ; *name != '\0'; name++)
209: if (s < &buf[12])
210: *s++ = *name; /* copy extension */
211: }
212: *s = '\0'; /* NUL terminate */
213: return buf;
214: }
215:
216: char * cohn(name) char * name;
217: {
218: static char lname[22];
219: char *tmp = lname;
220: short i = 0;
221:
222: do {
223: if (*name == ' ')
224: *name++;
225: else {
226: *(tmp++) = tolower(*name);
227: name++;
228: }
229: i++;
230: } while (i<8);
231:
232: if ((*name != ' ')) {
233: *(tmp++) = '.';
234: do {
235: if (*name == ' ')
236: *name++;
237: else {
238: *(tmp++) = tolower(*name);
239: name++;
240: }
241: i++;
242: } while (i<11);
243: }
244: *tmp = '\0';
245:
246: return lname;
247: }
248:
249:
250: /*
251: * Input up to nb characters into bp from COHERENT file fp,
252: * taking into account the ASCII flag.
253: * Pad to nb characters with NUL or CTRLZ.
254: * Return the number of characters actually read.
255: */
256: short
257: finput(fp, bp, nb) FILE *fp; register char *bp; unsigned short nb;
258: {
259: register short c;
260: register unsigned short n, n2;
261: register char *ep;
262: static char needlf = 0;
263:
264: if (!aflag) {
265: n2 = n = read(fileno(fp), bp, nb);
266: while (n2 && n < nb)
267: {
268: n2 = read(fileno(fp), bp + n, nb - n);
269: n += n2;
270: }
271: for (ep = bp+nb, bp += n; bp < ep; )
272: *bp++ = '\0';
273: return n;
274: }
275: for (n = 0, ep = bp+nb; bp < ep; ) {
276: if (needlf) {
277: c = '\n';
278: needlf = 0;
279: } else {
280: if ((c = getc(fp)) == '\r')
281: continue;
282: else if (c == '\n') {
283: c = '\r';
284: needlf++;
285: } else if (c == EOF)
286: c = CTRLZ;
287: }
288: if (c == CTRLZ)
289: break;
290: n++;
291: *bp++ = c;
292: }
293: while (bp < ep)
294: *bp++ = CTRLZ; /* pad with EOFs */
295: return n;
296: }
297:
298: /*
299: * Format an MS-DOS filesystem.
300: * The optional argument is a boot block.
301: */
302: void
303: format(nargs, args) short nargs; char *args[];
304: {
305: register char *cp;
306: short i, c;
307: char *bp;
308: unsigned short nsize;
309: struct stat sbuf;
310:
311: /* Prompt to make sure. */
312: printf("Are you sure you want to build an MS-DOS filesystem on device %s? ", device);
313: fflush(stdout);
314: c = getchar();
315: while (c != '\n' && (i = getchar()) != '\n' && i != EOF)
316: ;
317: if (c != 'y' && c != 'Y') {
318: rm_lock();
319: exit(1);
320: }
321: if (nargs > 1)
322: fatal("format: only one bootstrap file allowed");
323:
324: /* Get BPB for the specified format. */
325: if (fstat(fsfd, &sbuf) < 0)
326: fatal("format: cannot stat");
327: i = sbuf.st_rdev;
328: if (major(i) != FL_MAJOR)
329: fatal("format: illegal device major number");
330: switch (minor(i) & 0x0F) {
331: case 0: bpb = &s8floppy; break;
332: case 3: bpb = &s9floppy; break;
333: case 9: bpb = &d8floppy; break;
334: case 12: bpb = &d9floppy; break;
335: case 13: bpb = &q9floppy; break;
336: case 14: bpb = &d15floppy; break;
337: case 15: bpb = &d18floppy; break;
338: default:
339: fatal("format: unsupported diskette type %d", minor(i) & 0x0F);
340: }
341: setglobals();
342:
343: /* Read boot block or build one. */
344: if (nargs > 0) {
345: if ((i=open(args[0], 0)) < 0)
346: fatal("format: cannot open boot block file \"%s\"", args[0]);
347: if (read(i, bootb, BBSIZE) != BBSIZE)
348: fatal("format: boot block read error");
349: close(i);
350: } else {
351: /* Patch in "jmp short ." with required flag byte. */
352: bootb[0] = 0xEB; /* JMP short */
353: bootb[1] = 0xFE; /* . (PC-relative) */
354: bootb[2] = 0x90; /* required flag */
355: strncpy(&bootb[3], "COHERENT", 8);
356: for (cp=&bootb[BPBOFF], bp=bpb, i=0; i < sizeof(BPB); i++)
357: *cp++ = *bp++; /* copy the BPB */
358: }
359: if (write(fsfd, bootb, BBSIZE) != BBSIZE)
360: fatal("format: boot block write error");
361:
362: /* Write the FATs (media id and zero bytes). */
363: if (fatbytes != 1)
364: fatal("format: fatbytes=%d", fatbytes);
365: nsize = (maxcluster + 1) * sizeof(short);
366: if (nsize < fatsize * ssize)
367: nsize = fatsize * ssize;
368: if ((fatcache = calloc(nsize, 1)) == NULL)
369: fatal("format: FAT allocation failed");
370: fatcache[0] = 0xFF00 | bpb->b_media;
371: fatcache[1] = CLEOF;
372: fatcfirst = 0;
373: fatccount = fatsize;
374: fatcflag = 1;
375: writefat();
376: free(fatcache);
377:
378: /* Write the directory (all zero bytes). */
379: if ((cp = calloc(dirsize, ssize)) == NULL)
380: fatal("format: directory allocation failed");
381: diskwrite(cp, (long)dirbase, dirsize, "directory");
382: free(cp);
383: }
384:
385: /*
386: * Output nb characters from bp to COHERENT file fp,
387: * taking into account the ASCII flag.
388: * Return the number of characters actually written.
389: */
390: short
391: foutput(fn, fp, bp, nb) char *fn; FILE *fp; register char *bp; unsigned short nb;
392: {
393: register unsigned short n;
394: register char *ep;
395:
396: if (!aflag) {
397: if (write(fileno(fp), bp, nb) != nb)
398: fatal("extract: write error on file \"%s\"", fn);
399: return nb;
400: }
401: for (n = 0, ep = bp+nb; bp < ep; bp++) {
402: if (*bp == '\r')
403: continue;
404: else if (*bp == CTRLZ)
405: break;
406: n++;
407: putc(*bp, fp);
408: }
409: if (ferror(fp))
410: fatal("extract: write error on file \"%s\"", fn);
411: return n;
412: }
413:
414: /*
415: * Return the next free cluster on the diskette.
416: * Stick an EOF marker in the cluster.
417: * Failure is fatal.
418: */
419: unsigned short
420: freecluster()
421: {
422: register unsigned short n;
423:
424: for (n = 2; n <= maxcluster; n++)
425: if (getcluster(n) == CLFREE) {
426: putcluster(n, CLEOF);
427: return n;
428: }
429: fatal("out of space on MS-DOS disk");
430: }
431:
432: /*
433: * Read the key for the command.
434: * Set globals accordingly.
435: * Return the required device mode for the command.
436: */
437: short
438: key(s) register char *s;
439: {
440: register short c, nfun;
441:
442: nfun = 0;
443: bflag = 1; /* assume binary */
444: if (*s == '-')
445: ++s; /* ignore optional '-' */
446: while ((c = *s++) != '\0')
447: switch (c) {
448:
449: /* Functions. */
450: case 'd': fun = delete; ++nfun; break;
451: case 'F': fun = format; ++nfun; break;
452: case 'l': fun = label; ++nfun; break;
453: case 'r': fun = replace; ++nfun; break;
454: case 't': fun = table; ++nfun; break;
455: case 'x': fun = extract; ++nfun; break;
456:
457: /* Flags. */
458: case 'a': aflag++; bflag--; break;
459: case 'c': cflag++; break;
460: case 'k': kflag++; break;
461: case 'n': nflag++; break;
462: case 'p': pflag++; break;
463: case 's': sflag++; break;
464: case 'v': vflag++; break;
465: case 'V':
466: fprintf(stderr, "dos: V%s\n", VERSION);
467: break;
468: case '1':
469: case '2':
470: case '3':
471: case '4':
472: case '5':
473: case '6':
474: case '7':
475: case '8':
476: case '9':
477: xpart = c - '0';
478: break;
479:
480: default:
481: usage();
482: }
483:
484: if (nfun == 0)
485: fun = table; /* default */
486: else if (nfun > 1)
487: fatal("must specify one function [dFlrtx]");
488: return (cflag || fun==table || fun==extract) ? 0 : 2;
489: }
490:
491: /*
492: * Label a disk with a volume label.
493: */
494: void
495: label(nargs, args) short nargs; char *args[];
496: {
497: char tmp[13], *b;
498: short i;
499:
500: if (nargs > 1)
501: fatal("label: single argument required");
502: else if (nargs == 0) {
503: if (volume == NULL)
504: printf("Volume in Drive %s is unlabeled.\n",adev);
505: else {
506: strncpy(tmp, volume->m_name, 11);
507: tmp[11] = '\0';
508: printf("Volume in Drive %s is labeled %s.\n",adev,tmp);
509: }
510: }
511: else {
512: if ((i = strlen(args[0])) > 8) {
513: if (i > 11)
514: args[0][11] = '\0';
515: strncpy(tmp, args[0], 8);
516: tmp[8] = '.';
517: strcpy(&tmp[9], &args[0][8]);
518:
519: b = tmp;
520: }
521: else
522: b= args[0];
523:
524: if (volume != NULL)
525: deletefile(volume, root);
526: if (find(b, root, NULL) != NULL)
527: fatal("label: file \"%s\" already exists", b);
528: if (strchr(b, '/') != NULL)
529: fatal("label: label cannot use character '/'");
530: volume = creatfile(b, root);
531: volume->m_attr = MVOLUME;
532: }
533: }
534:
535: /*
536: * Initialize an MDIR with the current time and date,
537: * the given name, attribute and cluster, and size 0L.
538: * Set the flag requiring the DIR to be written.
539: */
540: void
541: mdirinit(mdp, dp, name, attr, cluster)
542: register MDIR *mdp;
543: DIR *dp;
544: char *name;
545: unsigned short attr, cluster;
546: {
547: register short i;
548:
549: dbprintf(("mdirinit(mdp=%x dp=\"%s\" name=\"%s\" attr=%x cl=%x)\n", mdp, dp->d_dname, name, attr, cluster));
550: strncpy(mdp->m_name, name, 11);
551: mdp->m_attr = attr;
552: for (i=0; i<10; i++)
553: mdp->m_junk[i] = 0;
554: dostime(mdp, NULL);
555: mdp->m_cluster = cluster;
556: mdp->m_size = 0;
557: dp->d_dirflag = 1;
558: }
559:
560: /* end of dos3.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.