xref: /original-bsd/local/local.cmd/cpio.c (revision 2301fdfb)
1 /* Copyright (c) 1983 Regents of the University of California */
2 
3 #ifndef lint
4 static char sccsid[] = "@(#)cpio.c	4.3	(Berkeley)	01/26/88";
5 #endif not lint
6 
7 /*	cpio	COMPILE:	cc -O cpio.c -s -i -o cpio
8 	cpio -- copy file collections
9 
10 */
11 #include <stdio.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <signal.h>
15 #ifdef RT
16 #define S_IFEXT 0120000	/*  allocated by extents  */
17 #define S_IF1EXT 0130000	/*  one extent  */
18 #endif
19 #define EQ(x,y)	(strcmp(x,y)==0)
20 /* for VAX, Interdata, ... */
21 #define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];}
22 #define MAGIC	070707
23 #define IN	1
24 #define OUT	2
25 #define PASS	3
26 #define HDRSIZE	((sizeof Hdr)-256)
27 #define LINKS	1000
28 #define MERT 0
29 #define CHARS 76
30 #ifdef RT
31 #define MERT 1	/* yes = 1 ;  no = 0 */
32 extern long filespace;
33 #endif
34 
35 struct	stat	Statb, Xstatb;
36 
37 struct header {
38 	short	h_magic,
39 		h_dev;
40 	unsigned short	h_ino,
41 		h_mode,
42 		h_uid,
43 		h_gid;
44 	short	h_nlink,
45 		h_rdev,
46 		h_mtime[2],
47 		h_namesize,
48 		h_filesize[2];
49 	char	h_name[256];
50 } Hdr;
51 
52 int	Bufsize = 512;
53 short	Buf[256], *Dbuf;
54 char    BBuf[512];
55 char    *Cbuf;
56 int	Wct,Wc;
57 short	*Wp;
58 char    *Cp;
59 #ifdef RT
60 short Actual_size[2];	/* MERT variable */
61 struct{
62 	long long_size;
63 };
64 #endif
65 
66 short	Option,
67 	Dir,
68 	Uncond,
69 	Link,
70 	Rename,
71 	Toc,
72 	Verbose,
73 	Select,
74 	Mod_time,
75 	Acc_time,
76 	Cflag,
77 	Swap;
78 
79 int	Ifile,
80 	Ofile,
81 	Input = 0,
82 	Output = 1;
83 long	Blocks,
84 	Longfile,
85 	Longtime;
86 
87 char	Fullname[256],
88 	Name[256];
89 int	Pathend;
90 
91 FILE	*Rtty,
92 	*Wtty;
93 
94 char	*Pattern[100];
95 char	Strhdr[500];
96 char	*Chdr = Strhdr;
97 short	Dev,
98 	Uid,
99 	Gid,
100 	A_directory,
101 	A_special,
102 #ifdef RT
103 	One_extent,
104 	Multi_extent,
105 #endif
106 	Filetype = S_IFMT;
107 #ifdef RT
108 short Remove_mode = 0007777;
109 short New_mode;
110 #endif
111 
112 extern	errno;
113 char	*malloc();
114 char 	*cd();
115 char	*Cd_name;
116 FILE 	*popen();
117 
118 union { long l; short s[2]; char c[4]; } U;
119 
120 /* for VAX, Interdata, ... */
121 long mklong(v)
122 short v[];
123 {
124 	U.l = 1;
125 	if(U.c[0])
126 		U.s[0] = v[1], U.s[1] = v[0];
127 	else
128 		U.s[0] = v[0], U.s[1] = v[1];
129 	return U.l;
130 }
131 
132 main(argc, argv)
133 char **argv;
134 {
135 	register ct;
136 	long	filesz;
137 	long lng;
138 	register char *fullp;
139 	register i;
140 
141 	signal(SIGSYS, 1);
142 	if(*argv[1] != '-')
143 		usage();
144 	Uid = getuid();
145 	umask(0);
146 	Gid = getgid();
147 	Pattern[0] = "*";
148 
149 	while(*++argv[1]) {
150 		switch(*argv[1]) {
151 		case 'a':
152 			Acc_time++;
153 			break;
154 		case 'B':
155 			Bufsize = 5120;
156 			break;
157 		case 'i':
158 			Option = IN;
159 			if(argc > 2 ) {
160 				for(i = 0; (i+2) < argc; ++i)
161 					Pattern[i] = argv[i+2];
162 			}
163 			break;
164 		case 'o':
165 			if(argc != 2)
166 				usage();
167 			Option = OUT;
168 			break;
169 		case 'p':
170 			if(argc != 3)
171 				usage();
172 			if(access(argv[2], 2) == -1) {
173 accerr:
174 				err("cannot write in <%s>\n", argv[2]);
175 				exit(2);
176 			}
177 			strcpy(Fullname, argv[2]);
178 			strcat(Fullname, "/");
179 			stat(Fullname, &Xstatb);
180 			if((Xstatb.st_mode&S_IFMT) != S_IFDIR)
181 				goto accerr;
182 			Option = PASS;
183 			Dev = Xstatb.st_dev;
184 			break;
185 		case 'c':
186 			Cflag++;
187 			break;
188 		case 'd':
189 			Dir++;
190 			break;
191 		case 'l':
192 			Link++;
193 			break;
194 		case 'm':
195 			Mod_time++;
196 			break;
197 		case 'r':
198 			Rename++;
199 			Rtty = fopen("/dev/tty", "r");
200 			Wtty = fopen("/dev/tty", "w");
201 			if(Rtty==NULL || Wtty==NULL) {
202 				err(
203 				  "Cannot rename (/dev/tty missing)\n");
204 				exit(2);
205 			}
206 			break;
207 		case 's':
208 			Swap++;
209 			break;
210 		case 't':
211 			Toc++;
212 			break;
213 		case 'u':
214 			Uncond++;
215 			break;
216 		case 'v':
217 			Verbose++;
218 			break;
219 		case '6':
220 			Filetype = 060000;
221 			break;
222 		default:
223 			usage();
224 		}
225 	}
226 	if(!Option) {
227 		err("Options must include o|i|p\n");
228 		exit(2);
229 	}
230 
231 	if (Cflag && Swap)  {
232 		err("Swap flag is ignored with Cflag\n");
233 		Swap = 0;
234 	}
235 
236 	if(Option != PASS)  {
237 		Wp = Dbuf = (short *)malloc(Bufsize);
238 		Cp = Cbuf = (char *)malloc(Bufsize);
239 	}
240 	     Wct = Bufsize >> 1;
241 	     Wc = Bufsize;
242 
243 	if(Option == PASS && Rename) {
244 		err("Pass and Rename cannot be used together");
245 		exit(2);
246 	}
247 	switch(Option) {
248 
249 	case OUT:
250 		while(getname()) {
251 			if( mklong(Hdr.h_filesize) == 0L) {
252 				if ( Cflag )
253 				     writehdr(Chdr,CHARS+Hdr.h_namesize);
254 				else
255 				     bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
256 #ifdef RT
257 				if( (MERT) && (((Hdr.h_mode & Filetype) == S_IF1EXT)
258 					|| ((Hdr.h_mode & Filetype) == S_IFEXT))) {
259 					actsize();
260 					bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
261 				}
262 #endif
263 				continue;
264 			}
265 			if((Ifile = open(Hdr.h_name, 0)) < 0) {
266 				err("<%s> ?\n", Hdr.h_name);
267 				continue;
268 			}
269 			if ( Cflag )
270 			     writehdr(Chdr,CHARS+Hdr.h_namesize);
271 			else
272 			     bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
273 #ifdef RT
274 			if( (MERT) && (((Hdr.h_mode & Filetype) == S_IF1EXT)
275 				|| ((Hdr.h_mode & Filetype) == S_IFEXT))) {
276 				actsize();
277 				bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
278 			}
279 #endif
280 			for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= 512){
281 				ct = filesz>512? 512: filesz;
282 				   if(read(Ifile, Cflag? BBuf: (char *)Buf, ct) < 0) {
283 					err("Cannot read %s\n", Hdr.h_name);
284 					continue;
285 				   }
286 				Cflag? writehdr(BBuf,ct): bwrite(Buf,ct);
287 			}
288 			close(Ifile);
289 			if(Acc_time)
290 				utime(Hdr.h_name, &Statb.st_atime);
291 			if(Verbose)
292 				err("%s\n", Hdr.h_name);
293 		}
294 		strcpy(Hdr.h_name, "TRAILER!!!");
295 		Hdr.h_magic = MAGIC;
296 		MKSHORT(Hdr.h_filesize, 0L);
297 		Hdr.h_namesize = strlen("TRAILER!!!") + 1;
298 		if ( Cflag )  {
299 		     lng = 0;
300 		     bintochar(lng);
301 		     writehdr(Chdr,CHARS+Hdr.h_namesize);
302 		}
303 		else
304 		     bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
305 		Cflag? writehdr(Cbuf, Bufsize): bwrite(Dbuf, Bufsize);
306 		break;
307 
308 	case IN:
309 		pwd();
310 		while(gethdr()) {
311 			Ofile = ckname(Hdr.h_name)? openout(Hdr.h_name): 0;
312 			for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= 512){
313 				ct = filesz>512? 512: filesz;
314 				Cflag? readhdr(BBuf, ct): bread(Buf, ct);
315 				if(Ofile) {
316 					if(Swap)
317 						swap(Buf, ct);
318 					   if(write(Ofile, Cflag? BBuf: (char *)Buf, ct) < 0) {
319 					      err("Cannot write %s\n", Hdr.h_name);
320 					      continue;
321 					   }
322 				}
323 			}
324 			if(Ofile) {
325 				close(Ofile);
326 				set_time(Cd_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
327 			}
328 			if(!Select)
329 				continue;
330 			if(Verbose)
331 				if(Toc)
332 					pentry(Hdr.h_name);
333 				else
334 					puts(Hdr.h_name);
335 			else if(Toc)
336 				puts(Hdr.h_name);
337 		}
338 		break;
339 
340 	case PASS:
341 		fullp = Fullname + strlen(Fullname);
342 
343 		while(getname()) {
344 			if(!ckname(Hdr.h_name))
345 				continue;
346 			strcpy(fullp, Hdr.h_name);
347 
348 			if(Link
349 			&& !A_directory
350 			&& Dev == Statb.st_dev) {
351 /* ???			&& (Uid == Statb.st_uid || !Uid)) {*/
352 				if(link(Hdr.h_name, Fullname) < 0) { /* missing dir.? */
353 					unlink(Fullname);
354 					missdir(Fullname);
355 					if(link(Hdr.h_name, Fullname) < 0) {
356 						err(
357 						 "Cannot link <%s> & <%s>\n",
358 						 Hdr.h_name, Fullname);
359 						continue;
360 					}
361 				}
362 				set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
363 				goto ckverbose;
364 			}
365 			if(!(Ofile = openout(Fullname)))
366 				continue;
367 			if((Ifile = open(Hdr.h_name, 0)) < 0) {
368 				err("<%s> ?\n", Hdr.h_name);
369 				close(Ofile);
370 				continue;
371 			}
372 			filesz = Statb.st_size;
373 			for(; filesz > 0; filesz -= 512) {
374 				ct = filesz>512? 512: filesz;
375 				    if(read(Ifile, Buf, ct) < 0) {
376 					err("Cannot read %s\n", Hdr.h_name);
377 					break;
378 				    }
379 				if(Ofile)
380 					if(write(Ofile, Buf, ct) < 0) {
381 					  err("Cannot write %s\n", Hdr.h_name);
382 					  break;
383 					}
384 				++Blocks;
385 			}
386 			close(Ifile);
387 			if(Acc_time)
388 				utime(Hdr.h_name, &Statb.st_atime);
389 			if(Ofile) {
390 				close(Ofile);
391 				set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime));
392 ckverbose:
393 				if(Verbose)
394 					puts(Fullname);
395 			}
396 		}
397 	}
398 	err("%ld blocks\n", Blocks * (Bufsize>>9));
399 	exit(0);
400 }
401 usage()
402 {
403 	err("Usage: cpio -o[acvB] <name-list >collection\n%s\n%s\n",
404 	"       cpio -i[cdmrstuvB6] [pattern ...] <collection",
405 	"       cpio -p[adlmruv] directory <name-list");
406 	exit(2);
407 }
408 
409 getname()
410 {
411 	register char *namep = Name;
412 	long tlong;
413 
414 	for(;;) {
415 		if(gets(namep) == NULL)
416 			return 0;
417 		if(*namep == '.' && namep[1] == '/')
418 			namep += 2;
419 		strcpy(Hdr.h_name, namep);
420 		if(stat(namep, &Statb) < 0) {
421 			err("< %s > ?\n", Hdr.h_name);
422 			continue;
423 		}
424 		A_directory = (Statb.st_mode & Filetype) == S_IFDIR;
425 		A_special = ((Statb.st_mode & Filetype) == S_IFBLK)
426 			|| ((Statb.st_mode & Filetype) == S_IFCHR);
427 #ifdef RT
428 		if(MERT) {
429 			One_extent = (Statb.st_mode & Filetype) == S_IF1EXT;
430 			Multi_extent = (Statb.st_mode & Filetype) == S_IFEXT;
431 		}
432 #endif
433 		Hdr.h_magic = MAGIC;
434 		Hdr.h_namesize = strlen(Hdr.h_name) + 1;
435 		Hdr.h_uid = Statb.st_uid;
436 		Hdr.h_gid = Statb.st_gid;
437 		Hdr.h_dev = Statb.st_dev;
438 		Hdr.h_ino = Statb.st_ino;
439 		Hdr.h_mode = Statb.st_mode;
440 		MKSHORT(Hdr.h_mtime, Statb.st_mtime);
441 		Hdr.h_nlink = Statb.st_nlink;
442 		tlong = Hdr.h_mode & S_IFREG? Statb.st_size: 0L;
443 		MKSHORT(Hdr.h_filesize, tlong);
444 		Hdr.h_rdev = Statb.st_rdev;
445 		if(Cflag)
446 			bintochar(tlong);
447 		return 1;
448 	}
449 }
450 
451 bintochar(t)
452 long t;
453 {
454 	sprintf(Chdr,"%.6o%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.11lo%.6ho%.11lo%s",
455 		MAGIC,Statb.st_dev,Statb.st_ino,Statb.st_mode,Statb.st_uid,
456 		Statb.st_gid,Statb.st_nlink,Statb.st_rdev & 00000177777,
457 		Statb.st_mtime,(short)strlen(Hdr.h_name)+1,t,Hdr.h_name);
458 }
459 
460 chartobin()
461 {
462 	sscanf(Chdr,"%6ho%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6ho%11lo",
463 		&Hdr.h_magic,&Hdr.h_dev,&Hdr.h_ino,&Hdr.h_mode,&Hdr.h_uid,
464 		&Hdr.h_gid,&Hdr.h_nlink,&Hdr.h_rdev,&Longtime,&Hdr.h_namesize,
465 		&Longfile);
466 	MKSHORT(Hdr.h_filesize, Longfile);
467 	MKSHORT(Hdr.h_mtime, Longtime);
468 }
469 
470 gethdr()
471 {
472 
473 	if ( Cflag )  {
474 		readhdr(Chdr,CHARS);
475 		chartobin();
476 	}
477 	else
478 		bread(&Hdr, HDRSIZE);
479 
480 	if(Hdr.h_magic != MAGIC) {
481 		err("Out of phase--get help\n");
482 		exit(2);
483 	}
484 	if(!Cflag)
485 	     bread(Hdr.h_name, Hdr.h_namesize);
486 	else
487 	     readhdr(Hdr.h_name, Hdr.h_namesize);
488 	if(Swap)
489 		swap(Hdr.h_name, Hdr.h_namesize);
490 	if(EQ(Hdr.h_name, "TRAILER!!!"))
491 		return 0;
492 	A_directory = (Hdr.h_mode & Filetype) == S_IFDIR;
493 	A_special =((Hdr.h_mode & Filetype) == S_IFBLK)
494 		|| ((Hdr.h_mode & Filetype) == S_IFCHR);
495 #ifdef RT
496 	if( (MERT) && (((Hdr.h_mode & Filetype) == S_IF1EXT)
497 		|| ((Hdr.h_mode & Filetype) == S_IFEXT))) {
498 		One_extent = (Hdr.h_mode & Filetype) == S_IF1EXT;
499 		Multi_extent = (Hdr.h_mode & Filetype) == S_IFEXT;
500 		Actual_size[0] = Hdr.h_filesize[0];
501 		Actual_size[1] = Hdr.h_filesize[1];
502 		bread(&Hdr, HDRSIZE);
503 		if(Hdr.h_magic != MAGIC) {
504 			err("Out of phase--get MERT help\n");
505 			exit(2);
506 		}
507 		bread(Hdr.h_name, Hdr.h_namesize);
508 	}
509 #endif
510 	return 1;
511 }
512 
513 ckname(namep)
514 register char *namep;
515 {
516 	++Select;
517 	if(!nmatch(namep, Pattern)) {
518 		Select = 0;
519 		return 0;
520 	}
521 	if(Rename && !A_directory) {
522 		fprintf(Wtty, "Rename <%s>\n", namep);
523 		fflush(Wtty);
524 		fgets(namep, 128, Rtty);
525 		if(feof(Rtty))
526 			exit(2);
527 		namep[strlen(namep) - 1] = '\0';
528 		if(EQ(namep, "")) {
529 			printf("Skipped\n");
530 			return 0;
531 		}
532 	}
533 	return !Toc;
534 }
535 
536 openout(namep)
537 register char *namep;
538 {
539 	register f;
540 	register char *np;
541 
542 	if(!strncmp(namep, "./", 2))
543 		namep += 2;
544 	np = namep;
545 	if(Option == IN)
546 		Cd_name = namep = cd(namep);
547 	if(A_directory) {
548 		if(!Dir
549 		|| Rename
550 		|| EQ(namep, ".")
551 		|| EQ(namep, "..")
552 		|| stat(namep, &Xstatb) == 0)
553 			return 0;
554 
555 		if(!makdir(namep)) {
556 			missdir(namep);
557 		}
558 ret:
559 		chmod(namep, Hdr.h_mode);
560 		if(Uid == 0)
561 			chown(namep, Hdr.h_uid, Hdr.h_gid);
562 		set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
563 		return 0;
564 	}
565 	if(Hdr.h_nlink > 1)
566 		if(!postml(namep, np))
567 			return 0;
568 	if(A_special) {
569 s_again:
570 		if(mknod(namep, Hdr.h_mode, Hdr.h_rdev) < 0) {
571 			if(missdir(namep))
572 				goto s_again;
573 			err("Cannot mknod <%s>\n", namep);
574 			return 0;
575 		}
576 		goto ret;
577 	}
578 	if(stat(namep, &Xstatb) == 0) {
579 		if(Uncond && !(Xstatb.st_mode & S_IWRITE))
580 			unlink(namep);
581 		if(!Uncond && (mklong(Hdr.h_mtime) < Xstatb.st_mtime)) {
582 			err("current <%s> newer\n", namep);
583 			return 0;
584 		}
585 	}
586 	if(Option == PASS
587 	&& Hdr.h_ino == Xstatb.st_ino
588 	&& Hdr.h_dev == Xstatb.st_dev) {
589 		err("Attempt to pass file to self!\n");
590 		exit(2);
591 	}
592 #ifdef RT
593 one_again:
594 	if(One_extent || Multi_extent) {
595 		if((f = falloc(namep, Hdr.h_mode, Hdr.h_filesize[0].long_size)) < 0) {
596 			if(missdir(namep))
597 				goto one_again;
598 			err("Cannot create <%s> (errno:%d)\n", namep, errno);
599 			return 0;
600 		}
601 		if(filespace < Hdr.h_filesize[0].long_size){
602 			err("Cannot create contiguous file <%s> proper size\n", namep);
603 			err("    <%s> will be created as a regular file\n", namep);
604 			if(unlink(Fullname) != 0)
605 				err("<%s> not removed\n", namep);
606 			New_mode = Hdr.h_mode & Remove_mode;
607 			New_mode = New_mode | S_IFREG;
608 once_again:
609 			if((f = creat(namep, New_mode)) < 0){
610 				if(missdir(namep))
611 					goto once_again;
612 				err("Cannot create <%s> (errno:%d)\n", namep, errno);
613 				return (0);
614 			}
615 		}
616 	}
617 #endif
618 #ifdef RT
619 	if(MERT && (One_extent || Multi_extent))
620 		goto skip_c;
621 #endif
622 c_again:
623 	if((f = creat(namep, Hdr.h_mode)) < 0) {
624 		if(missdir(namep))
625 			goto c_again;
626 		err("Cannot create <%s> (errno:%d)\n", namep, errno);
627 		return 0;
628 	}
629 #ifdef RT
630 skip_c:
631 #endif
632 	if(Uid == 0)
633 		chown(namep, Hdr.h_uid, Hdr.h_gid);
634 	return f;
635 }
636 
637 bread(b, c)
638 register c;
639 register short *b;
640 {
641 	static nleft = 0;
642 	static short *ip;
643 	register short *p = ip;
644 
645 	c = (c+1)>>1;
646 	while(c--) {
647 		if(!nleft) {
648 again:
649 			if(read(Input, Dbuf, Bufsize)!=Bufsize) {
650 				Input = chgreel(0, Input);
651 				goto again;
652 			}
653 			nleft = Bufsize >> 1;
654 			p = Dbuf;
655 			++Blocks;
656 		}
657 		*b++ = *p++;
658 		--nleft;
659 	}
660 	ip = p;
661 }
662 
663 readhdr(b, c)
664 register c;
665 register char *b;
666 {
667 	static nleft = 0;
668 	static char *ip;
669 	register char *p = ip;
670 
671 	while(c--)  {
672 		if(!nleft)  {
673 again:
674 			if(read(Input, Cbuf, Bufsize) != Bufsize)  {
675 				Input = chgreel(0, Input);
676 				goto again;
677 			}
678 			nleft = Bufsize;
679 			p = Cbuf;
680 			++Blocks;
681 		}
682 		*b++ = *p++;
683 		--nleft;
684 	}
685 	ip = p;
686 }
687 
688 bwrite(rp, c)
689 register short *rp;
690 register c;
691 {
692 	register short *wp = Wp;
693 
694 	c = (c+1) >> 1;
695 	while(c--) {
696 		if(!Wct) {
697 again:
698 			if(write(Output, Dbuf, Bufsize)<0) {
699 				Output = chgreel(1, Output);
700 				goto again;
701 			}
702 			Wct = Bufsize >> 1;
703 			wp = Dbuf;
704 			++Blocks;
705 		}
706 		*wp++ = *rp++;
707 		--Wct;
708 	}
709 	Wp = wp;
710 }
711 writehdr(rp,c)
712 register char *rp;
713 register c;
714 {
715          register char *cp = Cp;
716 
717          while(c--)  {
718                  if(!Wc)  {
719 again:
720                         if(write(Output,Cbuf,Bufsize)<0)  {
721                                 Output = chgreel(1, Output);
722                                 goto again;
723                         }
724                         Wc = Bufsize;
725                         cp = Cbuf;
726                         ++Blocks;
727                  }
728                  *cp++ = *rp++;
729                  --Wc;
730          }
731          Cp = cp;
732 }
733 
734 
735 postml(namep, np)
736 register char *namep, *np;
737 {
738 	register i;
739 	static struct ml {
740 		short	m_dev,
741 			m_ino;
742 		char	m_name[2];
743 	} *ml[LINKS];
744 	static	mlinks = 0;
745 	char *mlp;
746 
747 	for(i = 0; i < mlinks; ++i) {
748 		if(mlinks == LINKS) break;
749 		if(ml[i]->m_ino==Hdr.h_ino &&
750 			ml[i]->m_dev==Hdr.h_dev) {
751 			if(Verbose)
752 			  printf("%s linked to %s\n", ml[i]->m_name,
753 				np);
754 			unlink(namep);
755 			if(Option == IN) {
756 				Fullname[Pathend] = '\0';
757 				strcat(Fullname, ml[i]->m_name);
758 				mlp = Fullname;
759 			} else
760 				mlp = ml[i]->m_name;
761 l_again:
762 			if(link(mlp, namep) < 0) {
763 				if(missdir(np))
764 					goto l_again;
765 				err("Cannot link <%s>&<%s>.\n",
766 					ml[i]->m_name, np);
767 			}
768 			set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
769 			return 0;
770 		}
771 	}
772 	if(mlinks == LINKS
773 	|| !(ml[mlinks] = (struct ml *)malloc(strlen(np) + 2 + sizeof(struct ml)))) {
774 		static int first=1;
775 
776 		if(first)
777 			if(mlinks == LINKS)
778 				err("Too many links\n");
779 			else
780 				err("No memory for links\n");
781 		mlinks = LINKS;
782 		first = 0;
783 		return 1;
784 	}
785 	ml[mlinks]->m_dev = Hdr.h_dev;
786 	ml[mlinks]->m_ino = Hdr.h_ino;
787 	strcpy(ml[mlinks]->m_name, np);
788 	++mlinks;
789 	return 1;
790 }
791 
792 pentry(namep)
793 register char *namep;
794 {
795 
796 	register i;
797 	static short lastid = -1;
798 #include <pwd.h>
799 	static struct passwd *pw;
800 	struct passwd *getpwuid();
801 	static char tbuf[32];
802 
803 	printf("%-7o", Hdr.h_mode & 0177777);
804 	if(lastid == Hdr.h_uid)
805 		printf("%-6s", pw->pw_name);
806 	else {
807 		setpwent();
808 		if(pw = getpwuid(Hdr.h_uid)) {
809 			printf("%-6s", pw->pw_name);
810 			lastid = Hdr.h_uid;
811 		} else {
812 			printf("%-6d", Hdr.h_uid);
813 			lastid = -1;
814 		}
815 	}
816 	printf("%7ld ", mklong(Hdr.h_filesize));
817 	U.l = mklong(Hdr.h_mtime);
818 	strcpy(tbuf, ctime(&U.l));
819 	tbuf[24] = '\0';
820 	printf(" %s  %s\n", &tbuf[4], namep);
821 }
822 
823 nmatch(s, pat)
824 char *s, **pat;
825 {
826 	if(EQ(*pat, "*"))
827 		return 1;
828 	while(*pat) {
829 		if((**pat == '!' && !gmatch(s, *pat+1))
830 		|| gmatch(s, *pat))
831 			return 1;
832 		++pat;
833 	}
834 	return 0;
835 }
836 gmatch(s, p)
837 register char *s, *p;
838 {
839 	register int c;
840 	register cc, ok, lc, scc;
841 
842 	scc = *s;
843 	lc = 077777;
844 	switch (c = *p) {
845 
846 	case '[':
847 		ok = 0;
848 		while (cc = *++p) {
849 			switch (cc) {
850 
851 			case ']':
852 				if (ok)
853 					return(gmatch(++s, ++p));
854 				else
855 					return(0);
856 
857 			case '-':
858 				ok |= (lc <= scc & scc <= (cc=p[1]));
859 			}
860 			if (scc==(lc=cc)) ok++;
861 		}
862 		return(0);
863 
864 	case '?':
865 	caseq:
866 		if(scc) return(gmatch(++s, ++p));
867 		return(0);
868 	case '*':
869 		return(umatch(s, ++p));
870 	case 0:
871 		return(!scc);
872 	}
873 	if (c==scc) goto caseq;
874 	return(0);
875 }
876 
877 umatch(s, p)
878 register char *s, *p;
879 {
880 	if(*p==0) return(1);
881 	while(*s)
882 		if (gmatch(s++,p)) return(1);
883 	return(0);
884 }
885 
886 makdir(namep)
887 register char *namep;
888 {
889 	static status;
890 	register pid;
891 
892 	if(pid = fork())
893 		while(wait(&status) != pid);
894 	else {
895 		close(2);
896 		execl("/bin/mkdir", "mkdir", namep, 0);
897 		exit(2);
898 	}
899 	return ((status>>8) & 0377)? 0: 1;
900 }
901 
902 swap(buf, ct)
903 register ct;
904 register union swp { short	shortw; char	charv[2]; } *buf;
905 {
906 	register char c;
907 
908 	ct = (ct + 1) >> 1;
909 
910 	while(ct--) {
911 		c = buf->charv[0];
912 		buf->charv[0] = buf->charv[1];
913 		buf->charv[1] = c;
914 		++buf;
915 	}
916 }
917 set_time(namep, atime, mtime)
918 register *namep;
919 long atime, mtime;
920 {
921 	static long timevec[2];
922 
923 	if(!Mod_time)
924 		return;
925 	timevec[0] = atime;
926 	timevec[1] = mtime;
927 	utime(namep, timevec);
928 }
929 chgreel(x, fl)
930 {
931 	register f;
932 	char str[22];
933 	FILE *devtty;
934 	struct stat statb;
935 
936 	err("errno: %d, ", errno);
937 	err("Can't %s\n", x? "write output": "read input");
938 	fstat(fl, &statb);
939 #ifdef RT
940 	if(!MERT){
941 		if((statb.st_mode&S_IFMT) != S_IFCHR)
942 			exit(2);
943 	}
944 	else if((statb.st_mode & (S_IFBLK|S_IFREC))==0)
945 		exit(2);
946 #endif
947 #ifndef RT
948 	if((statb.st_mode&S_IFMT) != S_IFCHR)
949 		exit(2);
950 #endif
951 again:
952 	err("If you want to go on, type device/file name when ready\n");
953 	devtty = fopen("/dev/tty", "r");
954 	fgets(str, 20, devtty);
955 	str[strlen(str) - 1] = '\0';
956 	if(!*str)
957 		exit(2);
958 	close(fl);
959 	if((f = open(str, x? 1: 0)) < 0) {
960 		err("That didn't work");
961 		fclose(devtty);
962 		goto again;
963 	}
964 	return f;
965 }
966 missdir(namep)
967 register char *namep;
968 {
969 	register char *np;
970 	register ct = 0;
971 
972 	if(!Dir)
973 		return 0;
974 	for(np = namep; *np; ++np)
975 		if(*np == '/') {
976 			*np = '\0';
977 			if(stat(namep, &Xstatb) == -1)
978 				makdir(namep), ++ct;
979 			*np = '/';
980 		}
981 	return ct;
982 }
983 err(a, b, c)
984 {
985 	fprintf(stderr, a, b, c);
986 }
987 pwd()
988 {
989 	FILE *dir;
990 
991 	dir = popen("pwd", "r");
992 	fgets(Fullname, 256, dir);
993 	if(pclose(dir))
994 		exit(2);
995 	Pathend = strlen(Fullname);
996 	Fullname[Pathend - 1] = '/';
997 }
998 char * cd(n)
999 register char *n;
1000 {
1001 	char *p_save = Name, *n_save = n, *p_end = 0;
1002 	register char *p = Name;
1003 	static char dotdot[]="../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../";
1004 	int slashes;
1005 
1006 	if(*n == '/') /* don't try to chdir on full pathnames */
1007 		return n;
1008 	for(; *p && *n == *p; ++p, ++n) { /* whatever part of strings == */
1009 		if(*p == '/')
1010 			p_save = p+1, n_save = n+1;
1011 	}
1012 
1013 	p = p_save;
1014 	*p++ = '\0';
1015 	for(slashes = 0; *p; ++p) { /* if prev is longer, chdir("..") */
1016 		if(*p == '/')
1017 			++slashes;
1018 	}
1019 	p = p_save;
1020 	if(slashes) {
1021 		slashes = slashes * 3 - 1;
1022 		dotdot[slashes] = '\0';
1023 		chdir(dotdot);
1024 		dotdot[slashes] = '/';
1025 	}
1026 
1027 	n = n_save;
1028 	for(; *n; ++n, ++p) {
1029 		*p = *n;
1030 		if(*n == '/')
1031 			p_end = p+1, n_save = n+1;
1032 	}
1033 	*p = '\0';
1034 
1035 	if(p_end) {
1036 		*p_end = '\0';
1037 		if(chdir(p_save) == -1) {
1038 			if(!missdir(p_save)) {
1039 cd_err:
1040 				err("Cannot chdir (no `d' option)\n");
1041 				exit(2);
1042 			} else if(chdir(p_save) == -1)
1043 				goto cd_err;
1044 		}
1045 	} else
1046 		*p_save = '\0';
1047 	return n_save;
1048 }
1049 #ifdef RT
1050 actsize()
1051 {
1052 }
1053 #endif
1054