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