xref: /csrg-svn/old/arff/arff.c (revision 37979)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)arff.c	5.7 (Berkeley) 05/11/89";
15 #endif not lint
16 
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/time.h>
20 #include <sys/signal.h>
21 #include <sys/file.h>
22 #include <stdio.h>
23 #include "pathnames.h"
24 
25 #define dbprintf printf
26 
27 struct rt_dat {
28 	u_short	rt_yr:5;	/* year-1972 */
29 	u_short	rt_dy:5;	/* day */
30 	u_short	rt_mo:5;	/* month */
31 };
32 
33 struct	rt_axent {
34 	char	rt_sent[14];
35 };
36 
37 struct rt_ent {
38 	char	rt_pad;		/* unusued */
39 	u_char	rt_stat;	/* type of entry, or end of seg */
40 	u_short	rt_name[3];	/* name, 3 words in rad50 form */
41 	u_short	rt_len;		/* length of file */
42 	u_char	rt_chan;	/* only used in temporary files */
43 	char	rt_job;		/* only used in temporary files */
44 	struct	rt_dat rt_date;	/* creation date */
45 };
46 
47 #define RT_TEMP		1
48 #define RT_NULL		2
49 #define RT_FILE		4
50 #define RT_PFILE	(0200|RT_FILE)	/* protected file */
51 #define RT_ESEG		8
52 
53 #define RT_BLOCK	512	/* block size */
54 #define RT_DIRSIZE	31	/* max # of directory segments */
55 
56 struct rt_head {
57 	short	rt_numseg;	/* # of segments available */
58 	short	rt_nxtseg;	/* # of next logical segment */
59 	short	rt_lstseg;	/* highest seg currently open */
60 	u_short	rt_entpad;	/* extra words/directory entry */
61 	short	rt_stfile;	/* block # where files begin */
62 };
63 
64 struct	rt_dir {
65 	struct rt_head	rt_axhead;
66 	struct rt_ent	rt_ents[72];
67 	char		_dirpad[6];
68 };
69 
70 #define rd_numseg rt_axhead.rt_numseg
71 #define rd_nxtseg rt_axhead.rt_nxtseg
72 #define rd_lstseg rt_axhead.rt_lstseg
73 #define rd_entpad rt_axhead.rt_entpad
74 #define rd_stfile rt_axhead.rt_stfile
75 
76 typedef struct fldope {
77 	int	startad;
78 	int	count;
79 struct	rt_ent	*rtdope;
80 } FLDOPE;
81 
82 FLDOPE *lookup();
83 
84 #define	rt(p)	((struct rt_ent *) p )
85 #define	Ain1	03100
86 #define	Ain2	050
87 #define	flag(c)	(flg[('c') - 'a'])
88 
89 char	*man = "rxtd";
90 char	zeroes[512];
91 
92 extern char *val;
93 extern char table[256];
94 struct rt_dir rt_dir[RT_DIRSIZE] = {
95 	{
96 	{ 4, 0, 1, 0, 14 },
97 	{ { 0, RT_NULL, { 0, 0, 0 }, 486, 0 },
98 	  { 0, RT_ESEG } }
99 	}
100 };
101 
102 struct rt_dir rt_nulldir = {
103 	{ 0, 0, 0, 0, 0 },
104 	{ { 0, RT_NULL, { 0, 0, 0 }, 0, 0 },
105 	  { 0, RT_ESEG } }
106 };
107 
108 int	rt_entsiz;
109 int	rt_nleft;
110 struct rt_ent *rt_curend[RT_DIRSIZE];
111 int	floppydes;
112 int	dirdirty;
113 char	*rt_last;
114 char	*defdev = _PATH_FLOPPY;
115 
116 char *opt = "vfbcm";
117 
118 extern long lseek();
119 int	rcmd(), dcmd(), xcmd(), tcmd();
120 
121 int	(*comfun)();
122 char	flg[26];
123 char	**namv;
124 int	namc;
125 
126 main(argc, argv)
127 	char *argv[];
128 {
129 	register char *cp;
130 
131 	if (argc < 2)
132 		usage();
133 	for (cp = argv[1]; *cp; cp++)
134 		switch (*cp) {
135 
136 		case 'm':
137 		case 'v':
138 		case 'u':
139 		case 'w':
140 		case 'b':
141 			flg[*cp-'a']++;
142 			continue;
143 		case 'c':
144 			flag(c)++;
145 			dirdirty++;
146 			continue;
147 
148 		case 'r':
149 			setcom(rcmd);
150 			flag(r)++;
151 			continue;
152 
153 		case 'd':
154 			setcom(dcmd);
155 			flag(d)++;
156 			continue;
157 
158 		case 'x':
159 			setcom(xcmd);
160 			continue;
161 
162 		case 't':
163 			setcom(tcmd);
164 			continue;
165 
166 		case 'f':
167 			defdev = argv[2];
168 			argv++;
169 			argc--;
170 			continue;
171 
172 		default:
173 			fprintf(stderr, "arff: bad option `%c'\n", *cp);
174 			exit(1);
175 		}
176 
177 	namv = argv+2;
178 	namc = argc-2;
179 	if (comfun == 0) {
180 		if (flag(u) == 0) {
181 			fprintf(stderr, "arff: one of [%s] must be specified\n",
182 				man);
183 			exit(1);
184 		}
185 		setcom(rcmd);
186 	}
187 	(*comfun)();
188 	exit(notfound());
189 }
190 
191 setcom(fun)
192 	int (*fun)();
193 {
194 	if (comfun != 0) {
195 		fprintf(stderr, "arff: only one of [%s] allowed\n", man);
196 		exit(1);
197 	}
198 	comfun = fun;
199 }
200 
201 usage()
202 {
203 	fprintf(stderr, "usage: ar [%s][%s] archive files ...\n", opt, man);
204 	exit(1);
205 }
206 
207 notfound()
208 {
209 	register i, n = 0;
210 
211 	for (i = 0; i < namc; i++)
212 		if (namv[i]) {
213 			fprintf(stderr, "arff: %s not found\n", namv[i]);
214 			n++;
215 		}
216 	return (n);
217 }
218 
219 tcmd()
220 {
221 	register char *de, *last;
222 	FLDOPE *lookup(), *dope;
223 	int segnum, nleft;
224 	register i;
225 	register struct rt_ent *rde;
226 
227 	rt_init();
228 	if (namc != 0) {
229 		for (i = 0; i < namc; i++)
230 			if (dope = lookup(namv[i])) {
231 				rde = dope->rtdope;
232 				(void) rtls(rde);
233 				namv[i] = 0;
234 			}
235 		return;
236 	}
237 	for (segnum = 0; segnum != -1;
238 	  segnum = rt_dir[segnum].rd_nxtseg - 1) {
239 		last = rt_last + segnum*2*RT_BLOCK;
240 		for (de = ((char *)&rt_dir[segnum])+10; de <= last;
241 		    de += rt_entsiz)
242 			if (rtls(rt(de))) {
243 				nleft = (last-de)/rt_entsiz;
244 #define ENTRIES "\n%d entries remaining in directory segment %d.\n"
245 				printf(ENTRIES, nleft, segnum+1);
246 				break;
247 			}
248 	}
249 }
250 
251 rtls(de)
252 	register struct rt_ent *de;
253 {
254 	int month, day, year;
255 	char name[12], ext[4];
256 
257 	switch (de->rt_stat) {
258 
259 	case RT_TEMP:
260 		if (flag(v))
261 			printf("Tempfile:\n");
262 		/* fall thru...*/
263 
264 	case RT_FILE:
265 	case RT_PFILE:
266 		if (!flag(v)) {
267 			sunrad50(name, de->rt_name);
268 			printf("%s\n", name);
269 			break;
270 		}
271 		unrad50(2, de->rt_name, name);
272 		unrad50(1, &(de->rt_name[2]), ext);
273 		day = de->rt_date.rt_dy;
274 		year = de->rt_date.rt_yr+72;
275 		month = de->rt_date.rt_mo;
276 		printf("%6.6s  %3.3s	%02d/%02d/%02d	%d\n",name,
277 			ext, month, day, year, de->rt_len);
278 		break;
279 
280 	case RT_NULL:
281 		printf("%-25.9s	%d\n","<UNUSED>", de->rt_len);
282 		break;
283 
284 	case RT_ESEG:
285 		return (1);
286 	}
287 	return (0);
288 }
289 
290 xcmd()
291 {
292 	register char *de, *last;
293 	int segnum;
294 	char name[12];
295 	register int i;
296 
297 	rt_init();
298 	if (namc != 0) {
299 		for (i = 0; i < namc; i++)
300 			if (rtx(namv[i]) == 0)
301 				namv[i] = 0;
302 		return;
303 	}
304 	for (segnum = 0; segnum != -1;
305 	     segnum = rt_dir[segnum].rd_nxtseg-1)
306 		for (last = rt_last+(segnum*2*RT_BLOCK),
307 		     de = ((char *)&rt_dir[segnum])+10; de <= last;
308 		     de += rt_entsiz) {
309 			switch (rt(de)->rt_stat) {
310 
311 			case RT_ESEG:
312 				break;	/* exit loop and try next segment */
313 
314 			case RT_TEMP:
315 			case RT_FILE:
316 			case RT_PFILE:
317 				sunrad50(name,rt(de)->rt_name);
318 				(void) rtx(name);
319 
320 			case RT_NULL:
321 			default:
322 				continue;
323 			}
324 			break;
325 		}
326 }
327 
328 rtx(name)
329 	char *name;
330 {
331 	register FLDOPE *dope;
332 	FLDOPE *lookup();
333 	register startad, count;
334 	int file;
335 	char buff[512];
336 
337 
338 	if (dope = lookup(name)) {
339 		if (flag(v))
340 			(void) rtls(dope->rtdope);
341 		else
342 			printf("x - %s\n",name);
343 
344 		if ((file = creat(name, 0666)) < 0)
345 			return (1);
346 		count = dope->count;
347 		startad = dope->startad;
348 		for( ; count > 0 ; count -= 512) {
349 			(void) lread(startad, 512, buff);
350 			(void) write(file, buff, 512);
351 			startad += 512;
352 		}
353 		(void) close(file);
354 		return (0);
355 	}
356 	return (1);
357 }
358 
359 rt_init()
360 {
361 	static initized = 0;
362 	register char *de, *last;
363 	register i;
364 	int dirnum;
365 	char *mode;
366 	FILE *temp_floppydes;
367 
368 	if (initized)
369 		return;
370 	initized = 1;
371 	if (flag(c)) {
372 		struct stat sb;
373 		char response[128];
374 		int tty;
375 
376 		if (stat(defdev, &sb) >= 0 && (sb.st_mode & S_IFMT) == S_IFREG)
377 			goto ignore;
378 		tty = open(_PATH_TTY, O_RDWR);
379 #define SURE	"Are you sure you want to clobber the floppy? "
380 		(void) write(tty, SURE, sizeof (SURE));
381 		(void) read(tty, response, sizeof (response));
382 		if (*response != 'y')
383 			exit(50);
384 		(void) close(tty);
385 ignore:
386 		;
387 	}
388 	if (flag(c) || flag(d) || flag(r))
389 		mode = "r+";
390 	else
391 		mode = "r";
392 	if ((temp_floppydes = fopen(defdev, mode)) == NULL) {
393 		perror(defdev);
394 		exit(1);
395 	} else
396 		floppydes = fileno(temp_floppydes);
397 	if (!flag(c)) {
398 		if (lread(6*RT_BLOCK, 2*RT_BLOCK, (char *)&rt_dir[0]))
399 			exit(2);
400 		dirnum = rt_dir[0].rd_numseg;
401 		/* check for blank/uninitialized diskette */
402 		if (dirnum <= 0) {
403 			fprintf(stderr,"arff: bad directory format\n");
404 			exit(1);
405 		}
406 		if (dirnum > RT_DIRSIZE) {
407 			fprintf(stderr,"arff: too many directory segments\n");
408 			exit(1);
409 		}
410 		for (i = 1; i < dirnum; i++)
411 		    if (lread((6+2*i)*RT_BLOCK, 2*RT_BLOCK, (char *)&rt_dir[i]))
412 			exit(1);
413 	} else {
414 		dirnum = 1;
415 		if (flag(b)) {
416 			rt_dir[0].rd_numseg = 31;
417 			rt_dir[0].rd_stfile = 68;
418 			rt_dir[0].rt_ents[0].rt_len = 20480 - 68;
419 		}
420 	}
421 
422 	rt_entsiz = 2*rt_dir[0].rd_entpad + 14;
423 	/*
424 	 * We assume that the directory entries have no padding.  This
425 	 * may not be a valid assumption, but there are numerous point
426 	 * in the code where it assumes it is an rt_ent structure and
427 	 * not an rt_entsiz sized structure.
428 	 */
429 	rt_entsiz = 14;
430 	rt_last = ((char *) &rt_dir[0]) + 10 + 1014/rt_entsiz*rt_entsiz;
431 	rt_nleft = 0;
432 
433 	for (i = 0; i < dirnum; i++) {
434 		last = rt_last + i*2*RT_BLOCK;
435 		for (de = ((char *)&rt_dir[i])+10; de <= last; de += rt_entsiz)
436 			if (rt(de)->rt_stat == RT_ESEG)
437 				break;
438 		rt_curend[i] = rt(de);
439 		rt_nleft += (last-de)/rt_entsiz;
440 	}
441 }
442 
443 static FLDOPE result;
444 
445 FLDOPE *
446 lookup(name)
447 	char *name;
448 {
449 	unsigned short rname[3];
450 	register char *de;
451 	int segnum;
452 	register index;
453 
454 	srad50(name,rname);
455 
456 	/*
457 	 *  Search for name, accumulate blocks in index
458 	 */
459 	rt_init();
460 	for (segnum = 0; segnum != -1;
461 	     segnum = rt_dir[segnum].rd_nxtseg - 1)
462 	{
463 		index = 0;
464 		for (de=((char *)&rt_dir[segnum])+10;
465 		     rt(de)->rt_stat != RT_ESEG; de += rt_entsiz)
466 			switch(rt(de)->rt_stat) {
467 
468 			case RT_FILE:
469 			case RT_PFILE:
470 			case RT_TEMP:
471 				if(samename(rname,rt(de)->rt_name)) {
472 					result.count = rt(de)->rt_len * 512;
473 					result.startad = 512*
474 					    (rt_dir[segnum].rd_stfile + index);
475 					result.rtdope = (struct rt_ent *) de;
476 					return (&result);
477 				}
478 
479 			case RT_NULL:
480 				index += rt(de)->rt_len;
481 			}
482         }
483 	return ((FLDOPE *) 0);
484 
485 }
486 
487 static
488 samename(a, b)
489 	u_short a[], b[];
490 {
491 	return (*a == *b && a[1] == b[1] && a[2] == b[2] );
492 }
493 
494 rad50(cp, out)
495 	register u_char *cp;
496 	u_short *out;
497 {
498 	register index, temp;
499 
500 	for (index = 0; *cp; index++) {
501 		temp = Ain1 * table[*cp++];
502 		if (*cp!=0) {
503 			temp += Ain2 * table[*cp++];
504 			if(*cp!=0)
505 				temp += table[*cp++];
506 		}
507 		out[index] = temp;
508 	}
509 }
510 
511 #define reduce(x, p, q) (x = v[p/q], p %= q);
512 
513 unrad50(count, in, cp)
514 	u_short *in;
515 	register char *cp;
516 {
517 	register i, temp;
518 	register u_char *v = (u_char *) val;
519 
520 	for (i = 0; i < count; i++) {
521 		temp = in[i];
522 		reduce(*cp++, temp, Ain1);
523 		reduce(*cp++, temp, Ain2);
524 		reduce(*cp++, temp, 1);
525 	}
526 	*cp=0;
527 }
528 
529 srad50(name, rname)
530 	register char *name;
531 	register u_short *rname;
532 {
533 	register index;
534 	register char *cp;
535 	char file[7], ext[4];
536 
537 	/*
538 	 * Find end of pathname
539 	 */
540 	for (cp = name; *cp++; )
541 		;
542 	while (cp >= name && *--cp != '/')
543 		;
544 	cp++;
545 	/*
546 	 * Change to rad50
547 	 */
548 	for (index = 0; *cp; ) {
549 		file[index++] = *cp++;
550 		if (*cp == '.') {
551 			cp++;
552 			break;
553 		}
554 		if (index >= 6) {
555 			break;
556 		}
557 	}
558 	file[index] = 0;
559 	for (index = 0; *cp; ) {
560 		ext[index++] = *cp++;
561 		if (*cp == '.' || index >= 3)
562 			break;
563 	}
564 	ext[index]=0;
565 	rname[0] = rname[1] = rname[2] = 0;
566 	rad50((u_char *)file, rname);
567 	rad50((u_char *)ext, rname+2);
568 }
569 
570 sunrad50(name, rname)
571 	u_short rname[];
572 	register char *name;
573 {
574 	register char *cp, *cp2;
575 	char ext[4];
576 
577 	unrad50(2, rname, name);
578 	unrad50(1, rname + 2, ext);
579 	/*
580 	 * Jam name and extension together with a dot
581 	 * deleting white space
582 	 */
583 	for (cp = name; *cp++;)
584 		;
585 	--cp;
586 	while (*--cp == ' ' && cp >= name)
587 		;
588 	*++cp = '.';
589 	cp++;
590 	for (cp2 = ext; *cp2 != ' ' && cp2 < ext+3;)
591 		*cp++ = *cp2++;
592 	*cp=0;
593 	if (cp[-1] == '.')
594 		cp[-1] = 0;
595 }
596 
597 static char *val = " abcdefghijklmnopqrstuvwxyz$.@0123456789";
598 
599 static char table[256] = {
600 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
601 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
602 0, 29, 29, 29, 27, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29,
603 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 29, 29, 29, 29, 29, 29,
604 29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
605 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29, 29,
606 29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
607 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29, 29,
608 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
609 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
610 0, 29, 29, 29, 27, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 29,
611 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 29, 29, 29, 29, 29, 29,
612 29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
613 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29, 29,
614 29, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
615 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 29, 29, 29 };
616 
617 /*
618  * Logical to physical adress translation
619  */
620 long
621 trans(logical)
622 	register int logical;
623 {
624 	register int sector, bytes, track;
625 
626 	logical += 26*128;
627 	bytes = (logical&127);
628 	logical >>= 7;
629 	sector = logical%26;
630 	if(sector >= 13)
631 		sector = sector*2+1;
632 	else
633 		sector *= 2;
634 	sector += 26 + ((track = (logical/26))-1)*6;
635 	sector %= 26;
636 	return ((((track*26)+sector) << 7) + bytes);
637 }
638 
639 lread(startad, count, obuff)
640 	register startad, count;
641 	register char *obuff;
642 {
643 	long trans();
644 	extern floppydes;
645 	register int size = flag(m) ? 512 : 128;
646 	int error = 0;
647 	extern int errno;
648 
649 	rt_init();
650 	while ((count -= size) >= 0) {
651 		(void) lseek(floppydes, flag(m) ?
652 			(long)startad : trans(startad), 0);
653 		if (read(floppydes, obuff, size) != size) {
654 			error = errno;
655 			fprintf(stderr, "arff: read error block %d: ",
656 				startad/size);
657 			errno = error;
658 			perror("");
659 		}
660 		obuff += size;
661 		startad += size;
662 	}
663 	return (error);
664 }
665 
666 lwrite(startad, count, obuff)
667 	register startad, count;
668 	register char *obuff;
669 {
670 	long trans();
671 	extern floppydes;
672 	register int size = flag(m) ? 512 : 128;
673 
674 	rt_init();
675 	while ((count -= size) >= 0) {
676 		(void) lseek(floppydes, flag(m) ?
677 			(long)startad : trans(startad), 0);
678 		if (write(floppydes, obuff, size) != size)
679 			fprintf(stderr, "arff: write error block %d\n",
680 				startad/size);
681 		obuff += size;
682 		startad += size;
683 	}
684 }
685 
686 rcmd()
687 {
688 	register int i;
689 
690 	rt_init();
691 	if (namc > 0)
692 		for (i = 0; i < namc; i++)
693 			if (rtr(namv[i]) == 0)
694 				namv[i] = 0;
695 }
696 
697 rtr(name)
698 	char *name;
699 {
700 	register FLDOPE *dope;
701 	register struct rt_ent *de;
702 	struct stat buf;
703 	register struct stat *bufp = &buf;
704 	int segnum;
705 	char type;
706 
707 	if (stat(name, bufp) < 0) {
708 		perror(name);
709 		return (-1);
710 	}
711 	type = 'a';
712 	if (dope = lookup(name)) {
713 		/* can replace, no problem */
714 		de = dope->rtdope;
715 		if (bufp->st_size <= (de->rt_len * 512)) {
716 			printf("r - %s\n",name);
717 			toflop(name, bufp->st_size, dope);
718 			goto found;
719 		} else {
720 			de = dope->rtdope;
721 			type = 'r';
722 			de->rt_stat = RT_NULL;
723 			de->rt_name[0] = 0;
724 			de->rt_name[1] = 0;
725 			de->rt_name[2] = 0;
726 			*((u_short *)&(de->rt_date)) = 0;
727 			scrunch();
728 		}
729 	}
730 	/*
731 	 * Search for vacant spot
732 	 */
733 	for (segnum = 0; segnum != -1;
734 	     segnum = rt_dir[segnum].rd_nxtseg - 1)
735 	{
736 		for (de = rt_dir[segnum].rt_ents;
737 		    rt(de)->rt_stat != RT_ESEG; de++)
738 			if ((de)->rt_stat == RT_NULL) {
739 				if (bufp->st_size <= (de->rt_len*512)) {
740 					printf("%c - %s\n", type, name),
741 					mkent(de, segnum, bufp,name);
742 					goto found;
743 				}
744 				continue;
745 			}
746 	}
747 	if (type == 'r')
748 		printf("%s: no slot for file, file deleted\n",name);
749 	else
750 		printf("%s: no slot for file\n", name);
751 	return (-1);
752 
753 found:
754 	if (dope = lookup(name)) {
755 		toflop(name, bufp->st_size, dope);
756 		return (0);
757 	}
758 	printf("%s: internal error, added then not found\n", name);
759 	return (-1);
760 }
761 
762 mkent(de, segnum, bufp, name)
763 	register struct rt_ent *de;
764 	int segnum;
765 	register struct stat *bufp;
766 	char *name;
767 {
768 	struct tm *localtime();
769 	register struct tm *timp;
770 	register struct rt_ent *workp;
771 	int count;
772 
773 	count = (((bufp->st_size -1) >>9) + 1);
774 	/* make sure there is room */
775 	if (de->rt_len == count)
776 		goto overwrite;
777 	if ((char *)rt_curend[segnum] == (rt_last + (segnum*2*RT_BLOCK))) {
778 		/* no entries left on segment, trying adding new segment */
779 		if (rt_dir[0].rd_numseg > rt_dir[0].rd_lstseg) {
780 			short newseg;
781 			register int i;
782 			int maxseg;
783 			short size;
784 
785 			newseg = rt_dir[0].rd_lstseg++;
786 			rt_dir[newseg] = rt_nulldir;
787 			rt_dir[newseg].rd_nxtseg = rt_dir[segnum].rd_nxtseg;
788 			rt_dir[segnum].rd_nxtseg = newseg + 1;
789 			rt_dir[newseg].rd_entpad = rt_dir[0].rd_entpad;
790 			rt_dir[newseg].rd_numseg = rt_dir[0].rd_numseg;
791 			size = 0;
792 			maxseg = 0;
793 			for(i = newseg - 1; i >= 0; i--) {
794 				workp = rt_curend[i] - 1;
795 				if (workp->rt_stat != RT_NULL)
796 					continue;
797 				if (workp->rt_len < size)
798 					continue;
799 				size = workp->rt_len;
800 				maxseg = i;
801 			}
802 			size = 0;
803 			for (workp = &rt_dir[maxseg].rt_ents[0];
804 			    workp->rt_stat != RT_ESEG; workp++) {
805 				size += workp->rt_len;
806 			}
807 			workp--;
808 			rt_dir[newseg].rt_ents[0].rt_len = workp->rt_len;
809 			rt_dir[newseg].rd_stfile =
810 			    rt_dir[maxseg].rd_stfile + size - workp->rt_len;
811 			workp->rt_len = 0;
812 			rt_curend[newseg] = &rt_dir[newseg].rt_ents[1];
813 			lwrite(6*RT_BLOCK, 2*RT_BLOCK, (char *)&rt_dir[0]);
814 			if (segnum != 0)
815 				lwrite((6+segnum*2)*RT_BLOCK, 2*RT_BLOCK,
816 				    (char *)&rt_dir[segnum]);
817 			lwrite((6+newseg*2)*RT_BLOCK, 2*RT_BLOCK,
818 			    (char *)&rt_dir[newseg]);
819 			segnum = newseg;
820 			de = &rt_dir[newseg].rt_ents[0];
821 		} else {
822 			fprintf(stderr, "All directory segments full on  %s\n",
823 				defdev);
824 			exit(1);
825 		}
826 	}
827 	/* copy directory entries up */
828 	for (workp = rt_curend[segnum]+1; workp > de; workp--)
829 		*workp = workp[-1];
830 	de[1].rt_len -= count;
831 	de->rt_len = count;
832 	rt_curend[segnum]++;
833 	rt_nleft--;
834 
835 overwrite:
836 	srad50(name,de->rt_name);
837 	timp = localtime(&bufp->st_mtime);
838 	de->rt_date.rt_dy = timp->tm_mday;
839 	de->rt_date.rt_mo = timp->tm_mon + 1;
840 	de->rt_date.rt_yr = timp->tm_year - 72;
841 	de->rt_stat = RT_FILE;
842 	de->rt_pad = 0;
843 	de->rt_chan = 0;
844 	de->rt_job = 0;
845 	lwrite((6+segnum*2)*RT_BLOCK, 2*RT_BLOCK, (char *)&rt_dir[segnum]);
846 }
847 
848 toflop(name, ocount, dope)
849 	char *name;
850 	register FLDOPE *dope;
851 	long ocount;
852 {
853 	register file, n, startad = dope->startad, count = ocount;
854 	char buff[512];
855 
856 	file = open(name, 0);
857 	if (file < 0) {
858 		fprintf(stderr, "arff: couldn't open %s\n",name);
859 		exit(1);
860 	}
861 	for( ; count >= 512; count -= 512) {
862 		(void) read(file, buff, 512);
863 		lwrite(startad, 512, buff);
864 		startad += 512;
865 	}
866 	(void) read(file, buff, count);
867 	(void) close(file);
868 	if (count <= 0)
869 		return;
870 	for (n = count; n < 512; n ++)
871 		buff[n] = 0;
872 	lwrite(startad, 512, buff);
873 	count = (dope->rtdope->rt_len*512-ocount)/512 ;
874 	if (count <= 0)
875 		return;
876 	for ( ; count > 0 ; count--) {
877 		startad += 512;
878 		lwrite(startad, 512, zeroes);
879 	}
880 }
881 
882 dcmd()
883 {
884 	register int i;
885 
886 	rt_init();
887 	if (namc)
888 		for (i = 0; i < namc; i++)
889 			if (rtk(namv[i])==0)
890 				namv[i]=0;
891 	if (dirdirty)
892 		scrunch();
893 }
894 
895 rtk(name)
896 	char *name;
897 {
898 	register FLDOPE *dope;
899 	register struct rt_ent *de;
900 	FLDOPE *lookup();
901 
902 	if (dope = lookup(name)) {
903 		printf("d - %s\n",name);
904 		de = dope->rtdope;
905 		de->rt_stat = RT_NULL;
906 		de->rt_name[0] = 0;
907 		de->rt_name[1] = 0;
908 		de->rt_name[2] = 0;
909 		*((u_short *)&(de->rt_date)) = 0;
910 		dirdirty = 1;
911 		return (0);
912 	}
913 	return (1);
914 }
915 
916 scrunch()
917 {
918 	register struct rt_ent *de , *workp;
919 	register segnum;
920 
921 	for (segnum = 0; segnum != -1;
922 	     segnum = rt_dir[segnum].rd_nxtseg - 1) {
923 		for (de = rt_dir[segnum].rt_ents; de <= rt_curend[segnum]; de++)
924 			if (de->rt_stat == RT_NULL &&
925 			    (de+1)->rt_stat == RT_NULL) {
926 				(de+1)->rt_len += de->rt_len;
927 				for (workp=de; workp<rt_curend[segnum]; workp++)
928 					*workp = workp[1];
929 				de--;
930 				rt_curend[segnum]--;
931 				rt_nleft++;
932 			}
933 		lwrite((6+segnum*2)*RT_BLOCK, 2*RT_BLOCK,
934 			(char *)&rt_dir[segnum]);
935 	}
936 	dirdirty = 0;
937 }
938