xref: /csrg-svn/old/cpio/cpio.c (revision 33829)
133828Sbostic /*	Copyright (c) 1988 AT&T	*/
233828Sbostic /*	  All Rights Reserved  	*/
333828Sbostic 
433828Sbostic /*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
533828Sbostic /*	The copyright notice above does not evidence any   	*/
633828Sbostic /*	actual or intended publication of such source code.	*/
733828Sbostic 
833828Sbostic #ident	"@(#)cpio:cpio.c	1.30.1.11"
933828Sbostic /*	/sccs/src/cmd/s.cpio.c
1033828Sbostic 	cpio.c	1.30.1.11	1/11/86 13:46:48
1133828Sbostic 	Reworked cpio which uses getopt(3) to interpret flag arguments and
1233828Sbostic 	changes reels to the save file name.
1333828Sbostic 	Performance and size improvements.
1433828Sbostic */
1533828Sbostic 
1633828Sbostic /*	cpio	COMPILE:	cc -O cpio.c -s -i -o cpio -lgen -lerr
1733828Sbostic 	cpio -- copy file collections
1833828Sbostic 
1933828Sbostic */
2033828Sbostic #include <errno.h>
2133828Sbostic #include <fcntl.h>
2233828Sbostic #include <memory.h>
2333828Sbostic #include <stdio.h>
2433828Sbostic #include <string.h>
2533828Sbostic #include <signal.h>
2633828Sbostic #include <varargs.h>
27*33829Sbostic #include <sys/param.h>
28*33829Sbostic #include <sys/types.h>
2933828Sbostic #include <sys/stat.h>
3033828Sbostic 
31*33829Sbostic struct utimbuf {
32*33829Sbostic 	time_t	actime;
33*33829Sbostic 	time_t	modtime;
34*33829Sbostic };
35*33829Sbostic #ifndef S_IFIFO
36*33829Sbostic #define	S_IFIFO	010000
37*33829Sbostic #endif
38*33829Sbostic 
3933828Sbostic #define EQ(x,y)	(strcmp(x,y)==0)
4033828Sbostic 
4133828Sbostic 				/* MKSHORT:  for VAX, Interdata, ...	*/
4233828Sbostic 				/* Take a 4-byte long, lv, and turn it	*/
4333828Sbostic 				/* into an array of two 2-byte shorts, v*/
4433828Sbostic #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];}
4533828Sbostic 
4633828Sbostic #define MAGIC	070707		/* cpio magic number */
47*33829Sbostic #define BSMAGIC	0143561		/* byte-swapped cpio magic number */
4833828Sbostic #define IN	'i'		/* copy in */
4933828Sbostic #define OUT	'o'		/* copy out */
5033828Sbostic #define PASS	'p'		/* direct copy */
5133828Sbostic #define HDRSIZE	(Hdr.h_name - (char *)&Hdr)	/* header size minus filename field */
5233828Sbostic #define LINKS	500		/* no. of links allocated per bunch */
5333828Sbostic #define CHARS	76		/* ASCII header size minus filename field */
5433828Sbostic #define BUFSIZE 512		/* In u370, can't use BUFSIZ or BSIZE */
5533828Sbostic #define CPIOBSZ 4096		/* file read/write */
5633828Sbostic #define MK_USHORT(a)	(a & 00000177777)	/* Make unsigned shorts for portable  */
5733828Sbostic 						/* header.  Hardware may only know    */
5833828Sbostic 						/* integer operations and sign extend */
5933828Sbostic 						/* the large unsigned short resulting */
6033828Sbostic 						/* in 8 rather than 6 octal char in   */
6133828Sbostic 						/* the header.			      */
6233828Sbostic 
6333828Sbostic static struct	stat	Statb, Xstatb;
6433828Sbostic 
6533828Sbostic 	/* Cpio header format */
6633828Sbostic static struct header {
6733828Sbostic 	short	h_magic;
6833828Sbostic 	short	h_dev;
6933828Sbostic 	ushort	h_ino;
7033828Sbostic 	ushort	h_mode,
7133828Sbostic 		h_uid,
7233828Sbostic 		h_gid;
7333828Sbostic 	short	h_nlink;
7433828Sbostic 	short	h_rdev;
7533828Sbostic 	short	h_mtime[2],
7633828Sbostic 		h_namesize,
7733828Sbostic 		h_filesize[2];
7833828Sbostic 	char	h_name[256];
7933828Sbostic } Hdr;
8033828Sbostic 
81*33829Sbostic char	Symlbuf[MAXPATHLEN + 1];	/* target of symbolic link */
8233828Sbostic static unsigned	Bufsize = BUFSIZE;		/* default record size */
8333828Sbostic static char	Buf[CPIOBSZ], *Cbuf;
8433828Sbostic static char	*Cp;
8533828Sbostic 
8633828Sbostic 
8733828Sbostic static
8833828Sbostic short	Option,
8933828Sbostic 	Dir,
9033828Sbostic 	Uncond,
9133828Sbostic 	PassLink,
9233828Sbostic 	Rename,
9333828Sbostic 	Toc,
9433828Sbostic 	Verbose,
9533828Sbostic 	Mod_time,
9633828Sbostic 	Acc_time,
9733828Sbostic 	Cflag,
9833828Sbostic 	fflag,
9933828Sbostic 	Swap,
10033828Sbostic 	byteswap,
10133828Sbostic 	halfswap;
10233828Sbostic 
10333828Sbostic static
10433828Sbostic int	Ifile,
10533828Sbostic 	Ofile,
10633828Sbostic 	Input = 0,
10733828Sbostic 	Output = 1;
10833828Sbostic 			/* sBlocks: short Blocks.  Cumulative character   */
10933828Sbostic 			/* count for short reads in bread().  Encountered */
11033828Sbostic 			/* with communication lines and pipes as in:      */
11133828Sbostic 			/* split -100 cpio_archive; cat xa* | cpio -icd   */
11233828Sbostic static
11333828Sbostic long	sBlocks,
11433828Sbostic 	Blocks,
11533828Sbostic 	Longfile,
11633828Sbostic 	Longtime;
11733828Sbostic 
11833828Sbostic static
11933828Sbostic char	Fullname[256],
12033828Sbostic 	Name[256];
12133828Sbostic static
12233828Sbostic int	Pathend;
12333828Sbostic static
12433828Sbostic char	*swfile;
12533828Sbostic static
12633828Sbostic char	*eommsg = "Change to part %d and press RETURN key. [q] ";
12733828Sbostic 
12833828Sbostic static
12933828Sbostic FILE	*Rtty,
13033828Sbostic 	*Wtty;
13133828Sbostic static
13233828Sbostic char	ttyname[] = "/dev/tty";
13333828Sbostic 
13433828Sbostic static
13533828Sbostic char	**Pattern = 0;
13633828Sbostic static
13733828Sbostic char	Chdr[500];
13833828Sbostic static
13933828Sbostic short	Dev;
14033828Sbostic ushort	Uid,
14133828Sbostic 	A_directory,
14233828Sbostic 	A_special,
143*33829Sbostic 	A_symlink,
14433828Sbostic 	Filetype = S_IFMT;
14533828Sbostic 
14633828Sbostic extern	errno;
14733828Sbostic extern	void exit();
14833828Sbostic char	*malloc();
14933828Sbostic FILE 	*popen();
15033828Sbostic 
151*33829Sbostic static char *smemcpy();
152*33829Sbostic 
15333828Sbostic static
15433828Sbostic union {
15533828Sbostic 	long l;
15633828Sbostic 	short s[2];
15733828Sbostic 	char c[4];
15833828Sbostic } U;
15933828Sbostic 
16033828Sbostic /* for VAX, Interdata, ... */
16133828Sbostic static
16233828Sbostic long mklong(v)
16333828Sbostic short v[];
16433828Sbostic {
16533828Sbostic 	U.l = 1;
16633828Sbostic 	if(U.c[0])
16733828Sbostic 		U.s[0] = v[1], U.s[1] = v[0];
16833828Sbostic 	else
16933828Sbostic 		U.s[0] = v[0], U.s[1] = v[1];
17033828Sbostic 	return U.l;
17133828Sbostic }
17233828Sbostic 
17333828Sbostic main(argc, argv)
17433828Sbostic char **argv;
17533828Sbostic {
17633828Sbostic 	register ct;
17733828Sbostic 	long	filesz;
178*33829Sbostic 	int	symlsz;
17933828Sbostic 	register char *fullp;
18033828Sbostic 	register i;
18133828Sbostic 	int ans;
182*33829Sbostic 	register char *symlinkp;
18333828Sbostic 	short select;			/* set when files are selected */
18433828Sbostic 	extern char	*optarg;
18533828Sbostic 	extern int	optind;
18633828Sbostic 
187*33829Sbostic 	signal(SIGSYS, SIG_IGN);
188*33829Sbostic 	if(argc <= 1 || *argv[1] != '-')
18933828Sbostic 		usage();
19033828Sbostic 	Uid = getuid();
19133828Sbostic 
192*33829Sbostic 	while( (ans = getopt( argc, argv, "aBC:ifopcdlmrSsbtuvM:6eI:O:")) != EOF ) {
19333828Sbostic 
19433828Sbostic 		switch( ans ) {
19533828Sbostic 		case 'a':		/* reset access time */
19633828Sbostic 			Acc_time++;
19733828Sbostic 			break;
19833828Sbostic 		case 'B':		/* change record size to 5120 bytes */
19933828Sbostic 			Bufsize = 5120;
20033828Sbostic 			break;
20133828Sbostic 		case 'C':		/* reset buffer size to arbitrary valu
20233828Sbostic 					*/
20333828Sbostic 			Bufsize = atoi( optarg );
204*33829Sbostic 			if( Bufsize == 0 ) {
205*33829Sbostic 				fperr("Illegal argument to -%c, '%s'",
20633828Sbostic 					ans, optarg );
207*33829Sbostic 				exit(2);
208*33829Sbostic 			}
20933828Sbostic 			break;
21033828Sbostic 		case 'i':
21133828Sbostic 			Option = IN;
21233828Sbostic 			break;
21333828Sbostic 		case 'f':	/* copy files not matched by patterns */
21433828Sbostic 			fflag++;
21533828Sbostic 			break;
21633828Sbostic 		case 'o':
21733828Sbostic 			Option = OUT;
21833828Sbostic 			break;
21933828Sbostic 		case 'p':
22033828Sbostic 			Option = PASS;
22133828Sbostic 			break;
22233828Sbostic 		case 'c':		/* ASCII header */
22333828Sbostic 			Cflag++;
22433828Sbostic 			break;
22533828Sbostic 		case 'd':		/* create directories when needed */
22633828Sbostic 			Dir++;
22733828Sbostic 			break;
22833828Sbostic 		case 'l':		/* link files, when necessary */
22933828Sbostic 			PassLink++;
23033828Sbostic 			break;
23133828Sbostic 		case 'm':		/* retain mod time */
23233828Sbostic 			Mod_time++;
23333828Sbostic 			break;
23433828Sbostic 		case 'r':		/* rename files interactively */
23533828Sbostic 			Rename++;
23633828Sbostic 			Rtty = fopen(ttyname, "r");
23733828Sbostic 			Wtty = fopen(ttyname, "w");
23833828Sbostic 			if(Rtty==NULL || Wtty==NULL) {
239*33829Sbostic 				fperrno("Cannot rename (%s missing)",
24033828Sbostic 					ttyname );
241*33829Sbostic 				exit(2);
24233828Sbostic 			}
24333828Sbostic 			break;
24433828Sbostic 		case 'S':		/* swap halfwords */
24533828Sbostic 			halfswap++;
24633828Sbostic 			Swap++;
24733828Sbostic 			break;
24833828Sbostic 		case 's':		/* swap bytes */
24933828Sbostic 			byteswap++;
25033828Sbostic 			Swap++;
25133828Sbostic 			break;
25233828Sbostic 		case 'b':		/* swap both bytes and halfwords */
253*33829Sbostic 			halfswap++;
254*33829Sbostic 			byteswap++;
25533828Sbostic 			Swap++;
25633828Sbostic 			break;
25733828Sbostic 		case 't':		/* table of contents */
25833828Sbostic 			Toc++;
25933828Sbostic 			break;
26033828Sbostic 		case 'u':		/* copy unconditionally */
26133828Sbostic 			Uncond++;
26233828Sbostic 			break;
26333828Sbostic 		case 'v':		/* verbose - print out file names */
264*33829Sbostic 			Verbose++;
26533828Sbostic 			break;
26633828Sbostic 		case 'M':		/* alternate message for end-of-media */
26733828Sbostic 			eommsg = optarg;
26833828Sbostic 			break;
26933828Sbostic 		case '6':		/* for old, sixth-edition files */
27033828Sbostic 			Filetype = 060000;
27133828Sbostic 			break;
27233828Sbostic 		case 'I':
27333828Sbostic 			chkswfile( swfile, ans, Option );
274*33829Sbostic 			if( (i = open( optarg, O_RDONLY ) ) < 0) {
275*33829Sbostic 				fperrno("Cannot open <%s> for input", optarg);
276*33829Sbostic 				exit(2);
277*33829Sbostic 			}
278*33829Sbostic 			if( dup2(i, Input ) < 0 ) {
279*33829Sbostic 				fperrno("Cannot dup to standard input");
280*33829Sbostic 				exit(2);
281*33829Sbostic 			}
28233828Sbostic 			swfile = optarg;
28333828Sbostic 			break;
28433828Sbostic 		case 'O':
28533828Sbostic 			chkswfile( swfile, ans, Option );
286*33829Sbostic 			if( (i = open( optarg, O_WRONLY | O_CREAT | O_TRUNC,
287*33829Sbostic 			    0666 ) ) < 0) {
288*33829Sbostic 				fperrno("Cannot open <%s> for output", optarg);
289*33829Sbostic 				exit(2);
290*33829Sbostic 			}
291*33829Sbostic 			if( dup2(i, Output ) < 0 ) {
292*33829Sbostic 				fperrno("Cannot dup to standard output");
293*33829Sbostic 				exit(2);
294*33829Sbostic 			}
29533828Sbostic 			swfile = optarg;
29633828Sbostic 			break;
29733828Sbostic 		default:
29833828Sbostic 			usage();
29933828Sbostic 		}
30033828Sbostic 	}
30133828Sbostic 	if(!Option) {
302*33829Sbostic 		(void) fprintf(stderr,
303*33829Sbostic 		    "Options must include one of -o, -i, or -p\n");
304*33829Sbostic 		exit(2);
30533828Sbostic 	}
30633828Sbostic 
30733828Sbostic 	if(Option == PASS) {
30833828Sbostic 		if(Rename) {
309*33829Sbostic 			(void) fprintf(stderr,
310*33829Sbostic 			    "Pass and Rename cannot be used together\n");
311*33829Sbostic 			exit(2);
31233828Sbostic 		}
31333828Sbostic 		if( Bufsize != BUFSIZE ) {
31433828Sbostic 			fprintf( stderr, "`B' or `C' option is irrelevant with the '-p' option\n");
31533828Sbostic 			Bufsize = BUFSIZE;
31633828Sbostic 		}
31733828Sbostic 
31833828Sbostic 	}else  {
319*33829Sbostic 		Cp = Cbuf = (char *)malloc(Bufsize);
320*33829Sbostic 		if(Cp == NULL) {
321*33829Sbostic 			perror("cpio");
322*33829Sbostic 			exit(2);
323*33829Sbostic 		}
32433828Sbostic 	}
32533828Sbostic 	argc -= optind;
32633828Sbostic 	argv += optind;
32733828Sbostic 
32833828Sbostic 	switch(Option) {
32933828Sbostic 	case OUT:
33033828Sbostic 		if(argc != 0)
33133828Sbostic 			usage();
33233828Sbostic 		/* get filename, copy header and file out */
33333828Sbostic 		while(getname()) {
33433828Sbostic 			if( mklong(Hdr.h_filesize) == 0L) {
33533828Sbostic 				if( Cflag )
33633828Sbostic 					bwrite(Chdr,CHARS+Hdr.h_namesize);
33733828Sbostic 				else
33833828Sbostic 					bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
33933828Sbostic 				if(Verbose)
340*33829Sbostic 					(void) fprintf(stderr, "%s\n",
341*33829Sbostic 					    Hdr.h_name);
34233828Sbostic 				continue;
343*33829Sbostic 			} else if( A_symlink ) {
344*33829Sbostic 				symlsz = (int) mklong(Hdr.h_filesize);
345*33829Sbostic 				if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
346*33829Sbostic 					fperrno("Cannot read symbolic link <%s>",
347*33829Sbostic 					    Hdr.h_name);
348*33829Sbostic 					continue;
349*33829Sbostic 				}
350*33829Sbostic 				Symlbuf[symlsz] = '\0';
351*33829Sbostic 				bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
352*33829Sbostic 				bwrite(Symlbuf, symlsz);
353*33829Sbostic 				if(Verbose)
354*33829Sbostic 					(void) fprintf(stderr, "%s\n",
355*33829Sbostic 					    Hdr.h_name);
356*33829Sbostic 				continue;
35733828Sbostic 			}
35833828Sbostic 			if((Ifile = open(Hdr.h_name, 0)) < 0) {
359*33829Sbostic 				fperrno("Cannot open <%s>", Hdr.h_name);
36033828Sbostic 				continue;
36133828Sbostic 			}
36233828Sbostic 			if ( Cflag )
36333828Sbostic 				bwrite(Chdr,CHARS+Hdr.h_namesize);
36433828Sbostic 			else
36533828Sbostic 				bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
36633828Sbostic 			for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
36733828Sbostic 				ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
36833828Sbostic 				if(read(Ifile, Buf, ct) < 0) {
369*33829Sbostic  					fperrno("Cannot read %s", Hdr.h_name);
37033828Sbostic 					continue;
37133828Sbostic 				}
37233828Sbostic 				bwrite(Buf,ct);
37333828Sbostic 			}
37433828Sbostic 			close(Ifile);
375*33829Sbostic 			if(Acc_time) {
376*33829Sbostic 				struct utimbuf utb;
377*33829Sbostic 
378*33829Sbostic 				utb.actime = Statb.st_atime;
379*33829Sbostic 				utb.modtime = Statb.st_mtime;
380*33829Sbostic 				(void)utime(Hdr.h_name, &utb);
381*33829Sbostic 			}
38233828Sbostic 			if(Verbose)
383*33829Sbostic 				(void) fprintf(stderr, "%s\n", Hdr.h_name);
38433828Sbostic 		}
38533828Sbostic 
38633828Sbostic 	/* copy trailer, after all files have been copied */
38733828Sbostic 		strcpy(Hdr.h_name, "TRAILER!!!");
38833828Sbostic 		Hdr.h_magic = MAGIC;
38933828Sbostic 		MKSHORT(Hdr.h_filesize, 0L);
39033828Sbostic 		Hdr.h_namesize = strlen("TRAILER!!!") + 1;
39133828Sbostic 		if ( Cflag )  {
39233828Sbostic 			bintochar(0L);
39333828Sbostic 			bwrite(Chdr, CHARS+Hdr.h_namesize);
39433828Sbostic 		}
39533828Sbostic 		else
39633828Sbostic 			bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
39733828Sbostic 		bwrite(Cbuf, Bufsize);
39833828Sbostic 		break;
39933828Sbostic 
40033828Sbostic 	case IN:
40133828Sbostic 		if(argc > 0 ) {	/* save patterns, if any */
40233828Sbostic 			Pattern = argv;
40333828Sbostic 		}
40433828Sbostic 		pwd();
40533828Sbostic 		chkhdr();
40633828Sbostic 		while(gethdr()) {
407*33829Sbostic 			if (A_symlink) {
408*33829Sbostic 				symlsz = (int) mklong(Hdr.h_filesize);
409*33829Sbostic 				bread(Symlbuf, symlsz);
410*33829Sbostic 				Symlbuf[symlsz] = '\0';
411*33829Sbostic 				if((void) ckname(Hdr.h_name)  &&  !Toc)
412*33829Sbostic 					(void)openout(Hdr.h_name, Symlbuf);
413*33829Sbostic 			} else {
414*33829Sbostic 				if( (select = ckname(Hdr.h_name))  &&  !Toc )
415*33829Sbostic 					Ofile = openout(Hdr.h_name, (char *)0);
416*33829Sbostic 				else
417*33829Sbostic 					Ofile = 0;
418*33829Sbostic 				for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
419*33829Sbostic 					ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
420*33829Sbostic 					bread(Buf, ct);
421*33829Sbostic 					if(Ofile) {
422*33829Sbostic 						if(Swap)
423*33829Sbostic 						       swap(Buf,ct,byteswap,halfswap);
424*33829Sbostic 						if(write(Ofile, Buf, ct) < 0) {
425*33829Sbostic 						 fperrno("Cannot write %s", Hdr.h_name);
426*33829Sbostic 						 continue;
427*33829Sbostic 						}
42833828Sbostic 					}
42933828Sbostic 				}
430*33829Sbostic 				if( Ofile ) {
431*33829Sbostic 					(void) close(Ofile);
432*33829Sbostic 					if(chmod(Hdr.h_name, Hdr.h_mode) < 0)
433*33829Sbostic 						fperrno("Cannot change mode of <%s>",
434*33829Sbostic 						    Hdr.h_name);
435*33829Sbostic 					set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
436*33829Sbostic 				}
43733828Sbostic 			}
43833828Sbostic 			if(select) {
43933828Sbostic 				if(Verbose)
44033828Sbostic 					if(Toc)
44133828Sbostic 						pentry(Hdr.h_name);
44233828Sbostic 					else
443*33829Sbostic 						puts(Hdr.h_name);
44433828Sbostic 				else if(Toc)
44533828Sbostic 					puts(Hdr.h_name);
44633828Sbostic 			}
44733828Sbostic 		}
44833828Sbostic 		break;
44933828Sbostic 
45033828Sbostic 	case PASS:		/* move files around */
45133828Sbostic 		if(argc != 1)
45233828Sbostic 			usage();
45333828Sbostic 		if(access(argv[0], 2) == -1) {
454*33829Sbostic 			(void) fperrno("Cannot write in <%s>", argv[0]);
455*33829Sbostic 			exit(2);
45633828Sbostic 		}
45733828Sbostic 		strcpy(Fullname, argv[0]);	/* destination directory */
458*33829Sbostic 		if(stat(Fullname, &Xstatb) < 0) {
459*33829Sbostic 			fperrno("Cannot stat <%s>", Fullname);
460*33829Sbostic 			exit(2);
461*33829Sbostic 		}
462*33829Sbostic 		if((Xstatb.st_mode&S_IFMT) != S_IFDIR) {
463*33829Sbostic 			(void) fprintf(stderr, "<%s> is not a directory",
464*33829Sbostic 			    Fullname);
465*33829Sbostic 			exit(2);
466*33829Sbostic 		}
46733828Sbostic 		Dev = Xstatb.st_dev;
46833828Sbostic 		if( Fullname[ strlen(Fullname) - 1 ] != '/' )
46933828Sbostic 			strcat(Fullname, "/");
47033828Sbostic 		fullp = Fullname + strlen(Fullname);
47133828Sbostic 
47233828Sbostic 		while(getname()) {
47333828Sbostic 			if (A_directory && !Dir)
474*33829Sbostic 				fperr("Use `-d' option to copy <%s>",
47533828Sbostic 					Hdr.h_name);
47633828Sbostic 			if(!ckname(Hdr.h_name))
47733828Sbostic 				continue;
47833828Sbostic 			i = 0;
47933828Sbostic 			while(Hdr.h_name[i] == '/')
48033828Sbostic 				i++;
48133828Sbostic 			strcpy(fullp, &(Hdr.h_name[i]));
48233828Sbostic 
48333828Sbostic 			if( PassLink  &&  !A_directory  &&  Dev == Statb.st_dev ) {
48433828Sbostic 				if(link(Hdr.h_name, Fullname) < 0) {
48533828Sbostic 					switch(errno) {
48633828Sbostic 						case ENOENT:
48733828Sbostic 							if(missdir(Fullname) != 0) {
488*33829Sbostic 								fperrno("Cannot create directory for <%s>",
489*33829Sbostic 									Fullname);
49033828Sbostic 								continue;
49133828Sbostic 							}
49233828Sbostic 							break;
49333828Sbostic 						case EEXIST:
49433828Sbostic 							if(unlink(Fullname) < 0) {
495*33829Sbostic 								fperrno("Cannot unlink <%s>",
496*33829Sbostic 									Fullname);
49733828Sbostic 								continue;
49833828Sbostic 							}
49933828Sbostic 							break;
50033828Sbostic 						default:
501*33829Sbostic 							fperrno("Cannot link <%s> to <%s>",
502*33829Sbostic 								Hdr.h_name, Fullname);
50333828Sbostic 							continue;
50433828Sbostic 						}
50533828Sbostic 					if(link(Hdr.h_name, Fullname) < 0) {
506*33829Sbostic 						fperrno("Cannot link <%s> to <%s>",
507*33829Sbostic 							Hdr.h_name, Fullname);
50833828Sbostic 						continue;
50933828Sbostic 					}
51033828Sbostic 				}
51133828Sbostic 
51233828Sbostic 				goto ckverbose;
51333828Sbostic 			}
514*33829Sbostic 			if( A_symlink ) {
515*33829Sbostic 			   symlsz = (int) mklong(Hdr.h_filesize);
516*33829Sbostic 			   if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
517*33829Sbostic 				fperrno("Cannot read symbolic link <%s>",
518*33829Sbostic 				    Hdr.h_name);
51933828Sbostic 				continue;
520*33829Sbostic 			   }
521*33829Sbostic 			   Symlbuf[symlsz] = '\0';
522*33829Sbostic 			   if(!openout(Fullname, Symlbuf))
523*33829Sbostic 				continue;
524*33829Sbostic 			   Blocks += ((symlsz + (BUFSIZE - 1)) / BUFSIZE);
525*33829Sbostic 			   if(Verbose)
526*33829Sbostic 				puts(Fullname);
527*33829Sbostic 			   continue;
528*33829Sbostic 			}
529*33829Sbostic 			if(!(Ofile = openout(Fullname, (char *)0)))
530*33829Sbostic 				continue;
531*33829Sbostic 			if((Ifile = open(Hdr.h_name, 0)) < 0) {
532*33829Sbostic 				fperrno("Cannot open <%s>", Hdr.h_name);
53333828Sbostic 				close(Ofile);
53433828Sbostic 				continue;
53533828Sbostic 			}
53633828Sbostic 			filesz = Statb.st_size;
53733828Sbostic 			for(; filesz > 0; filesz -= CPIOBSZ) {
53833828Sbostic 				ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
53933828Sbostic 				if(read(Ifile, Buf, ct) < 0) {
540*33829Sbostic 					fperrno("Cannot read %s", Hdr.h_name);
54133828Sbostic 					break;
54233828Sbostic 				}
543*33829Sbostic 				if(write(Ofile, Buf, ct) < 0) {
544*33829Sbostic 				 fperrno("Cannot write %s", Hdr.h_name);
545*33829Sbostic 				 break;
546*33829Sbostic 				}
547*33829Sbostic 				/* Removed u370 ifdef which caused cpio */
548*33829Sbostic 				/* to report blocks in terms of 4096 bytes. */
54933828Sbostic 
55033828Sbostic 				Blocks += ((ct + (BUFSIZE - 1)) / BUFSIZE);
55133828Sbostic 			}
55233828Sbostic 			close(Ifile);
553*33829Sbostic 			if(Acc_time) {
554*33829Sbostic 				struct utimbuf utb;
555*33829Sbostic 
556*33829Sbostic 				utb.actime = Statb.st_atime;
557*33829Sbostic 				utb.modtime = Statb.st_mtime;
558*33829Sbostic 				(void)utime(Hdr.h_name, &utb);
559*33829Sbostic 			}
56033828Sbostic 			if(Ofile) {
56133828Sbostic 				close(Ofile);
562*33829Sbostic 				if(chmod(Fullname, Hdr.h_mode) < 0)
563*33829Sbostic 					fperrno("Cannot change mode of <%s>",
564*33829Sbostic 					    Fullname);
56533828Sbostic 				set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime));
56633828Sbostic ckverbose:
56733828Sbostic 				if(Verbose)
568*33829Sbostic 					puts(Fullname);
56933828Sbostic 			}
57033828Sbostic 		}
57133828Sbostic 	}
57233828Sbostic 	/* print number of blocks actually copied */
57333828Sbostic 	Blocks += ((sBlocks + (BUFSIZE - 1)) / BUFSIZE);
574*33829Sbostic 	(void) fprintf(stderr, "%ld blocks\n", Blocks * (Bufsize>>9));
57533828Sbostic 	exit(0);
57633828Sbostic }
57733828Sbostic 
57833828Sbostic static
57933828Sbostic usage()
58033828Sbostic {
581*33829Sbostic 	(void) fprintf("Usage: %s\n     %s\n     %s\n     %s\n       %s\n",
582*33829Sbostic 	    "cpio -o[acvB] <name-list >collection",
583*33829Sbostic 	    "cpio -o[acvB] -Ocollection <name-list",
584*33829Sbostic 	    "cpio -i[cdmrstuvfB6] [ pattern ... ] <collection",
585*33829Sbostic 	    "cpio -i[cdmrstuvfB6] -Icollection [ pattern ... ]",
586*33829Sbostic 	    "cpio -p[adlmruv] directory <name-list");
58733828Sbostic }
58833828Sbostic 
58933828Sbostic static
59033828Sbostic chkswfile( sp, c, option )
59133828Sbostic char	*sp;
59233828Sbostic char	c;
59333828Sbostic short	option;
59433828Sbostic {
595*33829Sbostic 	if( !option ) {
596*33829Sbostic 		fperr( "-%c must be specified before -%c option",
59733828Sbostic 			c == 'I' ? 'i' : 'o', c );
598*33829Sbostic 		exit(2);
599*33829Sbostic 	}
600*33829Sbostic 	if( (c == 'I'  &&  option != IN)  ||  (c == 'O'  &&  option != OUT) ) {
601*33829Sbostic 		fperr( "-%c option not permitted with -%c option", c,
60233828Sbostic 			option );
603*33829Sbostic 		exit(2);
604*33829Sbostic 	}
60533828Sbostic 	if( !sp )
60633828Sbostic 		return;
607*33829Sbostic 	fperr("No more than one -I or -O flag permitted");
608*33829Sbostic 	exit(2);
60933828Sbostic }
61033828Sbostic 
61133828Sbostic static
61233828Sbostic getname()		/* get file name, get info for header */
61333828Sbostic {
61433828Sbostic 	register char *namep = Name;
61533828Sbostic 	register ushort ftype;
616*33829Sbostic 	struct stat Lstatb;
61733828Sbostic 	long tlong;
61833828Sbostic 
61933828Sbostic 	for(;;) {
62033828Sbostic 		if(gets(namep) == NULL)
62133828Sbostic 			return 0;
62233828Sbostic 		while(*namep == '.' && namep[1] == '/') {
62333828Sbostic 			namep++;
62433828Sbostic 			while(*namep == '/') namep++;
62533828Sbostic 		}
62633828Sbostic 		strcpy(Hdr.h_name, namep);
627*33829Sbostic 		if(lstat(namep, &Statb) < 0) {
628*33829Sbostic 			fperrno("Cannot stat <%s>", Hdr.h_name);
62933828Sbostic 			continue;
63033828Sbostic 		}
63133828Sbostic 		ftype = Statb.st_mode & Filetype;
63233828Sbostic 		A_directory = (ftype == S_IFDIR);
63333828Sbostic 		A_special = (ftype == S_IFBLK)
63433828Sbostic 			|| (ftype == S_IFCHR)
63533828Sbostic 			|| (ftype == S_IFIFO);
636*33829Sbostic 		A_symlink = (ftype == S_IFLNK);
63733828Sbostic 		Hdr.h_magic = MAGIC;
63833828Sbostic 		Hdr.h_namesize = strlen(Hdr.h_name) + 1;
63933828Sbostic 		Hdr.h_uid = Statb.st_uid;
64033828Sbostic 		Hdr.h_gid = Statb.st_gid;
64133828Sbostic 		Hdr.h_dev = Statb.st_dev;
64233828Sbostic 		Hdr.h_ino = Statb.st_ino;
64333828Sbostic 		Hdr.h_mode = Statb.st_mode;
64433828Sbostic 		MKSHORT(Hdr.h_mtime, Statb.st_mtime);
64533828Sbostic 		Hdr.h_nlink = Statb.st_nlink;
646*33829Sbostic 		tlong = ((Hdr.h_mode&S_IFMT) == S_IFREG ||
647*33829Sbostic 			(Hdr.h_mode&S_IFMT) == S_IFLNK)? Statb.st_size: 0L;
64833828Sbostic 		MKSHORT(Hdr.h_filesize, tlong);
64933828Sbostic 		Hdr.h_rdev = Statb.st_rdev;
65033828Sbostic 		if( Cflag )
65133828Sbostic 			bintochar(tlong);
65233828Sbostic 		return 1;
65333828Sbostic 	}
65433828Sbostic }
65533828Sbostic 
65633828Sbostic static
65733828Sbostic bintochar(t)		/* ASCII header write */
65833828Sbostic long t;
65933828Sbostic {
66033828Sbostic 	sprintf(Chdr,"%.6o%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.11lo%.6ho%.11lo%s",
66133828Sbostic 		MAGIC, MK_USHORT(Statb.st_dev), MK_USHORT(Statb.st_ino), Statb.st_mode, Statb.st_uid,
66233828Sbostic 		Statb.st_gid, Statb.st_nlink, MK_USHORT(Statb.st_rdev),
66333828Sbostic 		Statb.st_mtime, (short)strlen(Hdr.h_name)+1, t, Hdr.h_name);
66433828Sbostic }
66533828Sbostic 
66633828Sbostic static
66733828Sbostic chartobin()		/* ASCII header read */
66833828Sbostic {
66933828Sbostic 	sscanf(Chdr, "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6ho%11lo",
67033828Sbostic 		&Hdr.h_magic, &Hdr.h_dev, &Hdr.h_ino, &Hdr.h_mode, &Hdr.h_uid,
67133828Sbostic 		&Hdr.h_gid, &Hdr.h_nlink, &Hdr.h_rdev, &Longtime,
67233828Sbostic 		&Hdr.h_namesize, &Longfile);
67333828Sbostic 	MKSHORT(Hdr.h_filesize, Longfile);
67433828Sbostic 	MKSHORT(Hdr.h_mtime, Longtime);
67533828Sbostic }
67633828Sbostic 
67733828Sbostic 
67833828Sbostic /*	Check the header for the magic number.  Switch modes automatically to
67933828Sbostic 	match the type of header found.
68033828Sbostic */
68133828Sbostic static
68233828Sbostic chkhdr()
68333828Sbostic {
68433828Sbostic 	bread(Chdr, CHARS);
68533828Sbostic 	chartobin();
68633828Sbostic 	if( Hdr.h_magic == MAGIC )
68733828Sbostic 		Cflag = 1;
68833828Sbostic 	else {
68933828Sbostic 		breread(&Hdr.h_magic, sizeof Hdr.h_magic);
690*33829Sbostic 		if( Hdr.h_magic == MAGIC || Hdr.h_magic == (short)BSMAGIC )
69133828Sbostic 			Cflag = 0;
692*33829Sbostic 		else {
693*33829Sbostic 			fperr("This is not a cpio file.  Bad magic number.");
694*33829Sbostic 			exit(2);
695*33829Sbostic 		}
69633828Sbostic 	}
69733828Sbostic 	breread(Chdr, 0);
69833828Sbostic }
69933828Sbostic 
70033828Sbostic 
70133828Sbostic static
70233828Sbostic gethdr()		/* get file headers */
70333828Sbostic {
70433828Sbostic 	register ushort ftype;
70533828Sbostic 
70633828Sbostic 	if (Cflag)  {
70733828Sbostic 		bread(Chdr, CHARS);
70833828Sbostic 		chartobin();
70933828Sbostic 	}
71033828Sbostic 	else
71133828Sbostic 		bread(&Hdr, HDRSIZE);
71233828Sbostic 
713*33829Sbostic 	if(Hdr.h_magic == (short)BSMAGIC)
714*33829Sbostic 		swap((char *)&Hdr, HDRSIZE, 1, 0);
715*33829Sbostic 	else if( Hdr.h_magic != MAGIC ) {
716*33829Sbostic 		fperr("Out of phase--get help");
717*33829Sbostic 		exit(2);
71833828Sbostic 	}
71933828Sbostic 	bread(Hdr.h_name, Hdr.h_namesize);
72033828Sbostic 	if(EQ(Hdr.h_name, "TRAILER!!!"))
72133828Sbostic 		return 0;
72233828Sbostic 	ftype = Hdr.h_mode & Filetype;
72333828Sbostic 	A_directory = (ftype == S_IFDIR);
72433828Sbostic 	A_special = (ftype == S_IFBLK)
72533828Sbostic 		||  (ftype == S_IFCHR)
72633828Sbostic 		||  (ftype == S_IFIFO);
727*33829Sbostic 	A_symlink = (ftype == S_IFLNK);
72833828Sbostic 	return 1;
72933828Sbostic }
73033828Sbostic 
73133828Sbostic static
73233828Sbostic ckname(namep)	/* check filenames with patterns given on cmd line */
73333828Sbostic register char *namep;
73433828Sbostic {
73533828Sbostic 	char	buf[sizeof Hdr.h_name];
73633828Sbostic 
73733828Sbostic 	if(fflag ^ !nmatch(namep, Pattern)) {
73833828Sbostic 		return 0;
73933828Sbostic 	}
74033828Sbostic 	if(Rename && !A_directory) {	/* rename interactively */
74133828Sbostic 		fprintf(Wtty, "Rename <%s>\n", namep);
74233828Sbostic 		fflush(Wtty);
74333828Sbostic 		fgets(buf, sizeof buf, Rtty);
74433828Sbostic 		if(feof(Rtty))
74533828Sbostic 			exit(2);
74633828Sbostic 		buf[strlen(buf) - 1] = '\0';
74733828Sbostic 		if(EQ(buf, "")) {
74833828Sbostic 			strcpy(namep,buf);
74933828Sbostic 			printf("Skipped\n");
75033828Sbostic 			return 0;
75133828Sbostic 		}
75233828Sbostic 		else if(EQ(buf, "."))
75333828Sbostic 			printf("Same name\n");
75433828Sbostic 		else
75533828Sbostic 			strcpy(namep,buf);
75633828Sbostic 	}
75733828Sbostic 	return  1;
75833828Sbostic }
75933828Sbostic 
76033828Sbostic static
761*33829Sbostic openout(namep, symlname)	/* open files for writing, set all necessary info */
76233828Sbostic register char *namep;
763*33829Sbostic char *symlname;
76433828Sbostic {
76533828Sbostic 	register f;
76633828Sbostic 	register char *np;
76733828Sbostic 	int ans;
76833828Sbostic 
76933828Sbostic 	if(!strncmp(namep, "./", 2))
77033828Sbostic 		namep += 2;
77133828Sbostic 	np = namep;
77233828Sbostic 	if(A_directory) {
77333828Sbostic 		if( !Dir  ||  Rename  ||  EQ(namep, ".")  ||  EQ(namep, "..") )
77433828Sbostic 			/* do not consider . or .. files */
77533828Sbostic 			return 0;
77633828Sbostic 		if(stat(namep, &Xstatb) == -1) {
77733828Sbostic 
77833828Sbostic /* try creating (only twice) */
77933828Sbostic 			ans = 0;
78033828Sbostic 			do {
781*33829Sbostic 				if(mkdir(namep, Hdr.h_mode) != 0) {
78233828Sbostic 					ans += 1;
78333828Sbostic 				}else {
78433828Sbostic 					ans = 0;
78533828Sbostic 					break;
78633828Sbostic 				}
78733828Sbostic 			}while(ans < 2 && missdir(namep) == 0);
78833828Sbostic 			if(ans == 1) {
78933828Sbostic 				fperrno("Cannot create directory for <%s>",
79033828Sbostic 					namep);
79133828Sbostic 				return(0);
79233828Sbostic 			}else if(ans == 2) {
79333828Sbostic 				fperrno("Cannot create directory <%s>", namep);
79433828Sbostic 				return(0);
79533828Sbostic 			}
79633828Sbostic 		}
79733828Sbostic 
79833828Sbostic ret:
799*33829Sbostic 		if(chmod(namep, Hdr.h_mode) < 0)
800*33829Sbostic 			fperrno("Cannot change mode of <%s>", namep);
80133828Sbostic 		if(Uid == 0)
802*33829Sbostic 			if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
803*33829Sbostic 				fperrno("Cannot change ownership of <%s>",
804*33829Sbostic 				    namep);
80533828Sbostic 		set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
80633828Sbostic 		return 0;
80733828Sbostic 	}
80833828Sbostic 	if(Hdr.h_nlink > 1)
80933828Sbostic 		if(!postml(namep, np))
81033828Sbostic 			return 0;
811*33829Sbostic 	if(lstat(namep, &Xstatb) == 0) {
81233828Sbostic 		if(Uncond && !((!(Xstatb.st_mode & S_IWRITE) || A_special) && (Uid != 0))) {
81333828Sbostic 			if(unlink(namep) < 0) {
81433828Sbostic 				fperrno("cannot unlink current <%s>", namep);
81533828Sbostic 			}
81633828Sbostic 		}
81733828Sbostic 		if(!Uncond && (mklong(Hdr.h_mtime) <= Xstatb.st_mtime)) {
81833828Sbostic 		/* There's a newer or same aged version of file on destination */
819*33829Sbostic 			fperr("current <%s> newer or same age", np);
82033828Sbostic 			return 0;
82133828Sbostic 		}
82233828Sbostic 	}
82333828Sbostic 	if( Option == PASS
82433828Sbostic 		&& Hdr.h_ino == Xstatb.st_ino
82533828Sbostic 		&& Hdr.h_dev == Xstatb.st_dev) {
826*33829Sbostic 		fperr("Attempt to pass file to self!");
827*33829Sbostic 		exit(2);
82833828Sbostic 	}
829*33829Sbostic 	if(A_symlink) {
830*33829Sbostic /* try symlinking (only twice) */
831*33829Sbostic 		ans = 0;
832*33829Sbostic 		do {
833*33829Sbostic 			if(symlink(
834*33829Sbostic symlname, namep) < 0) {
835*33829Sbostic 				ans += 1;
836*33829Sbostic 			}else {
837*33829Sbostic 				ans = 0;
838*33829Sbostic 				break;
839*33829Sbostic 			}
840*33829Sbostic 		}while(ans < 2 && missdir(np) == 0);
841*33829Sbostic 		if(ans == 1) {
842*33829Sbostic 			fperrno("Cannot create directory for <%s>", namep);
843*33829Sbostic 			return(0);
844*33829Sbostic 		}else if(ans == 2) {
845*33829Sbostic 			fperrno("Cannot symlink <%s> and <%s>", namep, symlname);
846*33829Sbostic 			return(0);
847*33829Sbostic 		}
848*33829Sbostic 
849*33829Sbostic 		return 0;
850*33829Sbostic 	}
85133828Sbostic 	if(A_special) {
85233828Sbostic 		if((Hdr.h_mode & Filetype) == S_IFIFO)
85333828Sbostic 			Hdr.h_rdev = 0;
85433828Sbostic 
85533828Sbostic /* try creating (only twice) */
85633828Sbostic 		ans = 0;
85733828Sbostic 		do {
85833828Sbostic 			if(mknod(namep, Hdr.h_mode, Hdr.h_rdev) < 0) {
85933828Sbostic 				ans += 1;
86033828Sbostic 			}else {
86133828Sbostic 				ans = 0;
86233828Sbostic 				break;
86333828Sbostic 			}
86433828Sbostic 		}while(ans < 2 && missdir(np) == 0);
86533828Sbostic 		if(ans == 1) {
86633828Sbostic 			fperrno("Cannot create directory for <%s>", namep);
86733828Sbostic 			return(0);
86833828Sbostic 		}else if(ans == 2) {
86933828Sbostic 			fperrno("Cannot mknod <%s>", namep);
87033828Sbostic 			return(0);
87133828Sbostic 		}
87233828Sbostic 
87333828Sbostic 		goto ret;
87433828Sbostic 	}
87533828Sbostic 
87633828Sbostic /* try creating (only twice) */
87733828Sbostic 	ans = 0;
87833828Sbostic 	do {
87933828Sbostic 		if((f = creat(namep, Hdr.h_mode)) < 0) {
88033828Sbostic 			ans += 1;
88133828Sbostic 		}else {
88233828Sbostic 			ans = 0;
88333828Sbostic 			break;
88433828Sbostic 		}
88533828Sbostic 	}while(ans < 2 && missdir(np) == 0);
88633828Sbostic 	if(ans == 1) {
88733828Sbostic 		fperrno("Cannot create directory for <%s>", namep);
88833828Sbostic 		return(0);
88933828Sbostic 	}else if(ans == 2) {
89033828Sbostic 		fperrno("Cannot create <%s>", namep);
89133828Sbostic 		return(0);
89233828Sbostic 	}
89333828Sbostic 
89433828Sbostic 	if(Uid == 0)
895*33829Sbostic 		if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
896*33829Sbostic 			fperrno("Cannot change ownership of <%s>", namep);
89733828Sbostic 	return f;
89833828Sbostic }
89933828Sbostic 
90033828Sbostic 
90133828Sbostic /*	Shared by bread() and breread()
90233828Sbostic */
90333828Sbostic static int	nleft = 0;	/* unread chars left in Cbuf */
90433828Sbostic static char	*ip;		/* pointer to next char to be read from Cbuf */
90533828Sbostic 
90633828Sbostic /*	Reread the current buffer Cbuf.
90733828Sbostic 	A character count, c, of 0 simply resets the pointer so next bread gets
90833828Sbostic 	the same data again.
90933828Sbostic */
91033828Sbostic static
91133828Sbostic breread(b, c)
91233828Sbostic char	*b;
91333828Sbostic int	c;
91433828Sbostic {
91533828Sbostic 	ip = Cbuf;
91633828Sbostic 	if( nleft )
91733828Sbostic 		nleft = Bufsize;
91833828Sbostic 	if( !c )
91933828Sbostic 		return;
92033828Sbostic 	bread(b, c);
92133828Sbostic }
92233828Sbostic 
92333828Sbostic static
92433828Sbostic bread(b, c)
92533828Sbostic register char	*b;
92633828Sbostic register int	c;
92733828Sbostic {
92833828Sbostic 	register int	rv;
92933828Sbostic 	register char	*p = ip;
93033828Sbostic 
93133828Sbostic 	if( !Cflag ) {
93233828Sbostic 		/* round c up to an even number */
93333828Sbostic 		c = (c+1)/2;
93433828Sbostic 		c *= 2;
93533828Sbostic 	}
93633828Sbostic 	while( c )  {
93733828Sbostic 		if( nleft == 0 ) {
93833828Sbostic 			while( (rv = read(Input, Cbuf, Bufsize)) == 0 ) {
93933828Sbostic 				Input = chgreel(0, Input, rv);
94033828Sbostic 			}
94133828Sbostic 			if( rv == Bufsize ) {
94233828Sbostic 				nleft = Bufsize;
94333828Sbostic 				p = Cbuf;
94433828Sbostic 				++Blocks;
94533828Sbostic 			}
946*33829Sbostic 			else if( rv == -1 ) {
947*33829Sbostic 				fperrno("Read error on archive");
948*33829Sbostic 				exit(2);
949*33829Sbostic 			}
95033828Sbostic 			else if( rv < Bufsize ) {	/* short read */
95133828Sbostic 				smemcpy( &Cbuf[ Bufsize - rv ], Cbuf, rv );
95233828Sbostic 				nleft = rv;
95333828Sbostic 				p = &Cbuf[ Bufsize - rv ];
95433828Sbostic 				sBlocks += rv;
95533828Sbostic 			}
95633828Sbostic 		}
95733828Sbostic 		if( nleft <= c ) {
95833828Sbostic 			memcpy( b, p, nleft );
95933828Sbostic 			c -= nleft;
96033828Sbostic 			b += nleft;
96133828Sbostic 			p += nleft;
96233828Sbostic 			nleft = 0;
96333828Sbostic 		}
96433828Sbostic 		else {
96533828Sbostic 			memcpy( b, p, c );
96633828Sbostic 			nleft -= c;
96733828Sbostic 			b += c;
96833828Sbostic 			p += c;
96933828Sbostic 			c = 0;
97033828Sbostic 		}
97133828Sbostic 	}
97233828Sbostic 	ip = p;
97333828Sbostic }
97433828Sbostic 
97533828Sbostic 
97633828Sbostic static
97733828Sbostic bwrite(rp, c)
97833828Sbostic register char *rp;
97933828Sbostic register c;
98033828Sbostic {
98133828Sbostic 	register char	*cp = Cp;
98233828Sbostic 	static unsigned	Ccnt = 0;
98333828Sbostic 	register unsigned Cleft;
98433828Sbostic 	register int	rv;
98533828Sbostic 
98633828Sbostic 	if( !Cflag ) {
98733828Sbostic 		/* round c up to an even number */
98833828Sbostic 		c = (c+1)/2;
98933828Sbostic 		c *= 2;
99033828Sbostic 	}
99133828Sbostic 	while( c )  {
99233828Sbostic 		if( (Cleft = Bufsize - Ccnt) <= c ) {
99333828Sbostic 			memcpy( cp, rp, Cleft );
99433828Sbostic 			rv = write(Output, Cbuf, Bufsize);
99533828Sbostic 			if( rv == 0  ||  ( rv == -1  &&  errno == ENXIO ) ) {
99633828Sbostic 				rv = eomchgreel();
99733828Sbostic 			}
99833828Sbostic 			if( rv == Bufsize ) {
99933828Sbostic 				Ccnt = 0;
100033828Sbostic 				cp = Cbuf;
100133828Sbostic 			}
1002*33829Sbostic 			else if( rv == -1 ) {
1003*33829Sbostic 				fperrno("Write error on archive");
1004*33829Sbostic 				exit(2);
1005*33829Sbostic 			}
100633828Sbostic 			else if( rv < Bufsize ) {
100733828Sbostic 				Output = chgreel(1, Output, 0);
100833828Sbostic 				smemcpy( Cbuf, &Cbuf[ Bufsize - rv ], rv );
100933828Sbostic 				Ccnt = Bufsize - rv;
101033828Sbostic 				cp = &Cbuf[ rv ];
101133828Sbostic 			}
101233828Sbostic 			++Blocks;
101333828Sbostic 			rp += Cleft;
101433828Sbostic 			c -= Cleft;
101533828Sbostic 		}
101633828Sbostic 		else {
101733828Sbostic 			memcpy( cp, rp, c );
101833828Sbostic 			Ccnt += c;
101933828Sbostic 			cp += c;
102033828Sbostic 			rp += c;
102133828Sbostic 			c = 0;
102233828Sbostic 		}
102333828Sbostic 	}
102433828Sbostic 	Cp = cp;
102533828Sbostic }
102633828Sbostic 
102733828Sbostic 
102833828Sbostic static int	reelcount = 1;	/* used below and in chgreel() */
102933828Sbostic 
103033828Sbostic /*	Change reel due to reaching end-of-media.
103133828Sbostic 	Keep trying to get a successful write before considering the
103233828Sbostic 	change-of-reel as successful.
103333828Sbostic */
103433828Sbostic static
103533828Sbostic int
103633828Sbostic eomchgreel()
103733828Sbostic {
103833828Sbostic 	int	rv;
103933828Sbostic 
104033828Sbostic 	while( 1 ) {
104133828Sbostic 		Output = chgreel(1, Output, 0);
104233828Sbostic 		rv = write(Output, Cbuf, Bufsize);
104333828Sbostic 		if( rv == Bufsize )
104433828Sbostic 			return  rv;
1045*33829Sbostic 		if( rv == -1 )
1046*33829Sbostic 			fperrno( "Unable to write this medium" );
1047*33829Sbostic 		else
1048*33829Sbostic 			fperr( "Unable to write this medium: Premature EOF" );
1049*33829Sbostic 		(void) fprintf(stderr, "Try again.\n");
105033828Sbostic 		reelcount--;
105133828Sbostic 	}
105233828Sbostic 	/*NOTREACHED*/
105333828Sbostic }
105433828Sbostic 
105533828Sbostic 
105633828Sbostic static
105733828Sbostic postml(namep, np)		/* linking funtion:  Postml() is called after */
105833828Sbostic register char *namep, *np;	/* namep is created.  Postml() checks to see  */
105933828Sbostic {				/* if namep should be linked to np.  If so,   */
106033828Sbostic 				/* postml() removes the independent instance  */
106133828Sbostic 	register i;		/* of namep and links namep to np.	      */
106233828Sbostic 	static struct ml {
106333828Sbostic 		short	m_dev;
106433828Sbostic 		ushort	m_ino;
106533828Sbostic 		char	m_name[2];
106633828Sbostic 	} **ml = 0;
106733828Sbostic 	register struct ml	*mlp;
106833828Sbostic 	static unsigned	mlsize = 0;
106933828Sbostic 	static unsigned	mlinks = 0;
107033828Sbostic 	char		*lnamep;
107133828Sbostic 	int		ans;
107233828Sbostic 
107333828Sbostic 	if( !ml ) {
107433828Sbostic 		mlsize = LINKS;
1075*33829Sbostic 		ml = (struct ml **) malloc(mlsize * sizeof(struct ml));
107633828Sbostic 	}
107733828Sbostic 	else if( mlinks == mlsize ) {
107833828Sbostic 		mlsize += LINKS;
1079*33829Sbostic 		ml = (struct ml **) realloc((char *) ml,
1080*33829Sbostic 		    mlsize * sizeof(struct ml));
108133828Sbostic 	}
1082*33829Sbostic 	if (ml == NULL) {
1083*33829Sbostic 		fperr("Out of memory for links");
1084*33829Sbostic 		exit(2);
1085*33829Sbostic 	}
108633828Sbostic 	for(i = 0; i < mlinks; ++i) {
108733828Sbostic 		mlp = ml[i];
108833828Sbostic 		if(mlp->m_ino==Hdr.h_ino  &&  mlp->m_dev==Hdr.h_dev) {
108933828Sbostic 			if(Verbose)
1090*33829Sbostic 			  printf("%s linked to %s\n", ml[i]->m_name,
1091*33829Sbostic 				np);
109233828Sbostic 			unlink(namep);
109333828Sbostic 			if(Option == IN && *(mlp->m_name) != '/') {
109433828Sbostic 				Fullname[Pathend] = '\0';
109533828Sbostic 				strcat(Fullname, mlp->m_name);
109633828Sbostic 				lnamep = Fullname;
109733828Sbostic 			}
109833828Sbostic 			lnamep = mlp->m_name;
109933828Sbostic 
110033828Sbostic /* try linking (only twice) */
110133828Sbostic 			ans = 0;
110233828Sbostic 			do {
110333828Sbostic 				if(link(lnamep, namep) < 0) {
110433828Sbostic 					ans += 1;
110533828Sbostic 				}else {
110633828Sbostic 					ans = 0;
110733828Sbostic 					break;
110833828Sbostic 				}
110933828Sbostic 			}while(ans < 2 && missdir(np) == 0);
111033828Sbostic 			if(ans == 1) {
111133828Sbostic 				fperrno("Cannot create directory for <%s>", np);
111233828Sbostic 				return(0);
111333828Sbostic 			}else if(ans == 2) {
111433828Sbostic 				fperrno("Cannot link <%s> & <%s>", lnamep, np);
111533828Sbostic 				return(0);
111633828Sbostic 			}
111733828Sbostic 
111833828Sbostic 			set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
111933828Sbostic 			return 0;
112033828Sbostic 		}
112133828Sbostic 	}
1122*33829Sbostic 	if( !(ml[mlinks] = (struct ml *)malloc(strlen(np) + 2 + sizeof(struct ml)))) {
112333828Sbostic 		static int first=1;
112433828Sbostic 
112533828Sbostic 		if(first)
1126*33829Sbostic 			fperr("Out of memory for links");
112733828Sbostic 		first = 0;
112833828Sbostic 		return 1;
112933828Sbostic 	}
113033828Sbostic 	ml[mlinks]->m_dev = Hdr.h_dev;
113133828Sbostic 	ml[mlinks]->m_ino = Hdr.h_ino;
113233828Sbostic 	strcpy(ml[mlinks]->m_name, np);
113333828Sbostic 	++mlinks;
113433828Sbostic 	return 1;
113533828Sbostic }
113633828Sbostic 
113733828Sbostic static
113833828Sbostic pentry(namep)		/* print verbose table of contents */
113933828Sbostic register char *namep;
114033828Sbostic {
114133828Sbostic 
114233828Sbostic 	static short lastid = -1;
114333828Sbostic #include <pwd.h>
114433828Sbostic 	static struct passwd *pw;
114533828Sbostic 	struct passwd *getpwuid();
114633828Sbostic 	static char tbuf[32];
114733828Sbostic 	char *ctime();
114833828Sbostic 
114933828Sbostic 	printf("%-7o", MK_USHORT(Hdr.h_mode));
115033828Sbostic 	if(lastid == Hdr.h_uid)
115133828Sbostic 		printf("%-6s", pw->pw_name);
115233828Sbostic 	else {
115333828Sbostic 		setpwent();
115433828Sbostic 		if(pw = getpwuid((int)Hdr.h_uid)) {
115533828Sbostic 			printf("%-6s", pw->pw_name);
115633828Sbostic 			lastid = Hdr.h_uid;
115733828Sbostic 		} else {
115833828Sbostic 			printf("%-6d", Hdr.h_uid);
115933828Sbostic 			lastid = -1;
116033828Sbostic 		}
116133828Sbostic 	}
116233828Sbostic 	printf("%7ld ", mklong(Hdr.h_filesize));
116333828Sbostic 	U.l = mklong(Hdr.h_mtime);
116433828Sbostic 	strcpy(tbuf, ctime((long *)&U.l));
116533828Sbostic 	tbuf[24] = '\0';
1166*33829Sbostic 	printf(" %s  %s", &tbuf[4], namep);
1167*33829Sbostic 	if (A_symlink)
1168*33829Sbostic 		printf(" -> %s", Symlbuf);
1169*33829Sbostic 	putchar('\n');
117033828Sbostic }
117133828Sbostic 
117233828Sbostic 		/* pattern matching functions */
117333828Sbostic static
117433828Sbostic nmatch(s, pat)
117533828Sbostic char *s, **pat;
117633828Sbostic {
117733828Sbostic 	if( !pat )
117833828Sbostic 		return 1;
117933828Sbostic 	while(*pat) {
118033828Sbostic 		if((**pat == '!' && !gmatch(s, *pat+1))
118133828Sbostic 		|| gmatch(s, *pat))
118233828Sbostic 			return 1;
118333828Sbostic 		++pat;
118433828Sbostic 	}
118533828Sbostic 	return 0;
118633828Sbostic }
118733828Sbostic 
118833828Sbostic 
118933828Sbostic static
119033828Sbostic gmatch(s, p)
119133828Sbostic register char *s, *p;
119233828Sbostic {
119333828Sbostic 	register int c;
119433828Sbostic 	register cc, ok, lc, scc;
119533828Sbostic 
119633828Sbostic 	scc = *s;
119733828Sbostic 	lc = 077777;
119833828Sbostic 	switch (c = *p) {
119933828Sbostic 
120033828Sbostic 	case '[':
120133828Sbostic 		ok = 0;
120233828Sbostic 		while (cc = *++p) {
120333828Sbostic 			switch (cc) {
120433828Sbostic 
120533828Sbostic 			case ']':
120633828Sbostic 				if (ok)
120733828Sbostic 					return(gmatch(++s, ++p));
120833828Sbostic 				else
120933828Sbostic 					return(0);
121033828Sbostic 
121133828Sbostic 			case '-':
121233828Sbostic 				ok |= ((lc <= scc) && (scc <= (cc=p[1])));
121333828Sbostic 			}
121433828Sbostic 			if (scc==(lc=cc)) ok++;
121533828Sbostic 		}
121633828Sbostic 		return(0);
121733828Sbostic 
121833828Sbostic 	case '?':
121933828Sbostic 	caseq:
122033828Sbostic 		if(scc) return(gmatch(++s, ++p));
122133828Sbostic 		return(0);
122233828Sbostic 	case '*':
122333828Sbostic 		return(umatch(s, ++p));
122433828Sbostic 	case 0:
122533828Sbostic 		return(!scc);
122633828Sbostic 	}
122733828Sbostic 	if (c==scc) goto caseq;
122833828Sbostic 	return(0);
122933828Sbostic }
123033828Sbostic 
123133828Sbostic 
123233828Sbostic 
123333828Sbostic static
123433828Sbostic umatch(s, p)
123533828Sbostic register char *s, *p;
123633828Sbostic {
123733828Sbostic 	if(*p==0) return(1);
123833828Sbostic 	while(*s)
123933828Sbostic 		if (gmatch(s++,p)) return(1);
124033828Sbostic 	return(0);
124133828Sbostic }
124233828Sbostic 
1243*33829Sbostic swap(buf, bytecount, bytes, halfwords)	/* swap halfwords, bytes or both */
1244*33829Sbostic char *buf;
1245*33829Sbostic int bytecount;
1246*33829Sbostic int bytes, halfwords;
124733828Sbostic {
1248*33829Sbostic 	register int count;
1249*33829Sbostic 	int n, i;
125033828Sbostic 
1251*33829Sbostic 	if(bytes) {
1252*33829Sbostic 		register union swpbytes {
1253*33829Sbostic 			short	shortw;
1254*33829Sbostic 			char	charv[2];
1255*33829Sbostic 		} *pbuf;
1256*33829Sbostic 		register char c;
125733828Sbostic 
1258*33829Sbostic 		count = bytecount;
1259*33829Sbostic 		pbuf = (union swpbytes *)buf;
1260*33829Sbostic 		if (count % sizeof(union swpbytes))
1261*33829Sbostic 			pbuf->charv[count] = 0;
1262*33829Sbostic 		count = (count + (sizeof(union swpbytes) - 1)) / sizeof(union swpbytes);
1263*33829Sbostic 		while (count--) {
1264*33829Sbostic 			c = pbuf->charv[0];
1265*33829Sbostic 			pbuf->charv[0] = pbuf->charv[1];
1266*33829Sbostic 			pbuf->charv[1] = c;
1267*33829Sbostic 			++pbuf;
126833828Sbostic 		}
126933828Sbostic 	}
1270*33829Sbostic 	if (halfwords) {
1271*33829Sbostic 		register union swphalf {
1272*33829Sbostic 			long	longw;
1273*33829Sbostic 			short	shortv[2];
1274*33829Sbostic 			char	charv[4];
1275*33829Sbostic 		} *pbuf;
1276*33829Sbostic 		register short cc;
1277*33829Sbostic 
1278*33829Sbostic 		count = bytecount;
1279*33829Sbostic 		pbuf = (union swphalf *)buf;
1280*33829Sbostic 		if (n = count % sizeof(union swphalf))
1281*33829Sbostic 			if(bytes && n % 2)
1282*33829Sbostic 				for(i = count + 1; i <= count + (sizeof(union swphalf) - n); i++)
1283*33829Sbostic 					pbuf->charv[i] = 0;
1284*33829Sbostic 			else
1285*33829Sbostic 				for (i = count; i < count + (sizeof(union swphalf) - n); i++)
1286*33829Sbostic 					pbuf->charv[i] = 0;
1287*33829Sbostic 		count = (count + (sizeof(union swphalf) - 1)) / sizeof(union swphalf);
1288*33829Sbostic 		while (count--) {
128933828Sbostic 			cc = pbuf->shortv[0];
129033828Sbostic 			pbuf->shortv[0] = pbuf->shortv[1];
129133828Sbostic 			pbuf->shortv[1] = cc;
129233828Sbostic 			++pbuf;
129333828Sbostic 		}
129433828Sbostic 	}
129533828Sbostic }
129633828Sbostic 
129733828Sbostic 
129833828Sbostic static
129933828Sbostic set_time(namep, atime, mtime)	/* set access and modification times */
130033828Sbostic register char *namep;
130133828Sbostic time_t atime, mtime;
130233828Sbostic {
1303*33829Sbostic 	static struct utimbuf timevec;
130433828Sbostic 
130533828Sbostic 	if(!Mod_time)
130633828Sbostic 		return;
1307*33829Sbostic 	timevec.actime = atime;
1308*33829Sbostic 	timevec.modtime = mtime;
1309*33829Sbostic 	(void)utime(namep, &timevec);
131033828Sbostic }
131133828Sbostic 
131233828Sbostic 
131333828Sbostic 
131433828Sbostic static
131533828Sbostic chgreel(x, fl, rv)
131633828Sbostic {
131733828Sbostic 	register f;
131833828Sbostic 	char str[BUFSIZ];
131933828Sbostic 	struct stat statb;
132033828Sbostic 
132133828Sbostic 	fstat(fl, &statb);
132233828Sbostic 	if((statb.st_mode&S_IFMT) != S_IFCHR) {
132333828Sbostic 		fperrno("Can't %s: ", x? "write output": "read input");
132433828Sbostic 		exit(2);
132533828Sbostic 	}
132633828Sbostic 	if( rv == 0  ||
132733828Sbostic 		( rv == -1  &&  ( errno == ENOSPC  ||  errno == ENXIO ) ) )
1328*33829Sbostic 		fperr( "\007Reached end of medium on %s",
132933828Sbostic 			x? "output":"input" );
133033828Sbostic 	else {
133133828Sbostic 		fperrno( "\007Encountered an error on %s",
133233828Sbostic 			x? "output":"input" );
133333828Sbostic 		exit(2);
133433828Sbostic 	}
1335*33829Sbostic 	if( Rtty == NULL ) {
1336*33829Sbostic 		Rtty = fopen(ttyname, "r");
1337*33829Sbostic 		if( Rtty == NULL ) {
1338*33829Sbostic 			fperrno("Cannot prompt (can't open %s)", ttyname);
1339*33829Sbostic 			exit(2);
1340*33829Sbostic 		}
1341*33829Sbostic 	}
134233828Sbostic 	close(fl);
134333828Sbostic 	reelcount++;
134433828Sbostic again:
134533828Sbostic 	if( swfile ) {
134633828Sbostic 	    askagain:
134733828Sbostic 		fperr( eommsg, reelcount );
134833828Sbostic 		fgets(str, sizeof str, Rtty);
134933828Sbostic 		switch( *str ) {
135033828Sbostic 		case '\n':
135133828Sbostic 			strcpy( str, swfile );
135233828Sbostic 			break;
135333828Sbostic 		case 'q':
135433828Sbostic 			exit(2);
135533828Sbostic 		default:
135633828Sbostic 			goto askagain;
135733828Sbostic 		}
135833828Sbostic 	}
135933828Sbostic 	else {
1360*33829Sbostic 		fperr("If you want to go on, type device/file name when ready.");
136133828Sbostic 		fgets(str, sizeof str, Rtty);
136233828Sbostic 		str[strlen(str) - 1] = '\0';
136333828Sbostic 		if(!*str)
136433828Sbostic 			exit(2);
136533828Sbostic 	}
136633828Sbostic 	if((f = open(str, x? 1: 0)) < 0) {
1367*33829Sbostic 		fperrno("Can't open <%s>", str);
136833828Sbostic 		goto again;
136933828Sbostic 	}
137033828Sbostic 	return f;
137133828Sbostic }
137233828Sbostic 
137333828Sbostic 
137433828Sbostic 
137533828Sbostic static
137633828Sbostic missdir(namep)
137733828Sbostic register char *namep;
137833828Sbostic {
137933828Sbostic 	register char *np;
138033828Sbostic 	register ct = 2;
138133828Sbostic 
138233828Sbostic 	for(np = namep; *np; ++np)
138333828Sbostic 		if(*np == '/') {
138433828Sbostic 			if(np == namep) continue;	/* skip over 'root slash' */
138533828Sbostic 			*np = '\0';
138633828Sbostic 			if(stat(namep, &Xstatb) == -1) {
138733828Sbostic 				if(Dir) {
1388*33829Sbostic 					if((ct = mkdir(namep, 0777)) != 0) {
138933828Sbostic 						*np = '/';
139033828Sbostic 						return(ct);
139133828Sbostic 					}
139233828Sbostic 				}else {
1393*33829Sbostic 					fperr("missing 'd' option");
139433828Sbostic 					return(-1);
139533828Sbostic 				}
139633828Sbostic 			}
139733828Sbostic 			*np = '/';
139833828Sbostic 		}
139933828Sbostic 	if (ct == 2) ct = 0;		/* the file already exists */
140033828Sbostic 	return ct;
140133828Sbostic }
140233828Sbostic 
140333828Sbostic 
140433828Sbostic 
140533828Sbostic static
140633828Sbostic pwd()		/* get working directory */
140733828Sbostic {
1408*33829Sbostic 	if (getwd(Fullname) == 0) {
1409*33829Sbostic 		(void)fprintf(stderr, "cpio: %s\n",
1410*33829Sbostic 		    Fullname);
141133828Sbostic 		exit(2);
1412*33829Sbostic 	}
141333828Sbostic 	Pathend = strlen(Fullname);
1414*33829Sbostic 	Fullname[Pathend++] = '/';
1415*33829Sbostic 	Fullname[Pathend] = '\0';
141633828Sbostic }
141733828Sbostic 
141833828Sbostic 
141933828Sbostic /*
142033828Sbostic 	print message on the stderr
142133828Sbostic */
142233828Sbostic static
142333828Sbostic fperr( va_alist )
142433828Sbostic va_dcl
142533828Sbostic {
142633828Sbostic 	va_list	args;
142733828Sbostic 	char	*fmt;
142833828Sbostic 
142933828Sbostic 	va_start( args );
1430*33829Sbostic 	fprintf( stderr, "cpio: ");
143133828Sbostic 	fmt = va_arg( args, char * );
143233828Sbostic 	vfprintf( stderr, fmt, args );
1433*33829Sbostic 	putc( '\n', stderr);
143433828Sbostic 	fflush( stderr );
143533828Sbostic }
143633828Sbostic 
143733828Sbostic /*
143833828Sbostic 	print message on the stderr followed by error number and meaning.
143933828Sbostic */
144033828Sbostic static
144133828Sbostic fperrno( va_alist )
144233828Sbostic va_dcl
144333828Sbostic {
144433828Sbostic 	va_list	args;
144533828Sbostic 	char	*fmt;
144633828Sbostic 
144733828Sbostic 	va_start( args );
1448*33829Sbostic 	fprintf( stderr, "cpio: ");
144933828Sbostic 	fmt = va_arg( args, char * );
145033828Sbostic 	vfprintf( stderr, fmt, args );
1451*33829Sbostic 	fprintf( stderr, ": " );
145233828Sbostic 	fflush( stderr );
145333828Sbostic 	perror("");
145433828Sbostic }
145533828Sbostic 
145633828Sbostic 
1457*33829Sbostic /*	Safe memory copy.
1458*33829Sbostic 	Fast if the to and from strings do not overlap,
1459*33829Sbostic 	slower but safe if they do.
1460*33829Sbostic */
1461*33829Sbostic 
1462*33829Sbostic static char *
1463*33829Sbostic smemcpy( to, from, count )
1464*33829Sbostic register char		*to, *from;
1465*33829Sbostic register unsigned	count;
146633828Sbostic {
1467*33829Sbostic 	char	*savedto;
1468*33829Sbostic 
1469*33829Sbostic 	if( &to[ count ] <= from  ||  &from[ count ] <= to )
1470*33829Sbostic 		return  memcpy( to, from, count );
1471*33829Sbostic 
1472*33829Sbostic 	if( to == from )
1473*33829Sbostic 		return  to;
1474*33829Sbostic 
1475*33829Sbostic 	savedto = to;
1476*33829Sbostic 	if( to < from )
1477*33829Sbostic 		while( count-- )
1478*33829Sbostic 			*(to++) = *(from++);
1479*33829Sbostic 	else {
1480*33829Sbostic 		to += count;
1481*33829Sbostic 		from += count;
1482*33829Sbostic 		while( count-- )
1483*33829Sbostic 			*(--to) = *(--from);
148433828Sbostic 	}
148533828Sbostic 
1486*33829Sbostic 	return  savedto;
148733828Sbostic }
1488