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