xref: /csrg-svn/old/cpio/cpio.c (revision 46224)
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>
21*46224Storek #include <stdio.h>
2233828Sbostic #include <fcntl.h>
2333828Sbostic #include <memory.h>
24*46224Storek #include <pwd.h>
2533828Sbostic #include <string.h>
2633828Sbostic #include <signal.h>
2733828Sbostic #include <varargs.h>
2833829Sbostic #include <sys/param.h>
2933829Sbostic #include <sys/types.h>
3033828Sbostic #include <sys/stat.h>
3137871Sbostic #include <paths.h>
3233828Sbostic 
3333829Sbostic struct utimbuf {
3433829Sbostic 	time_t	actime;
3533829Sbostic 	time_t	modtime;
3633829Sbostic };
3733829Sbostic #ifndef S_IFIFO
3833829Sbostic #define	S_IFIFO	010000
3933829Sbostic #endif
4033829Sbostic 
4133828Sbostic #define EQ(x,y)	(strcmp(x,y)==0)
4233828Sbostic 
4333828Sbostic 				/* MKSHORT:  for VAX, Interdata, ...	*/
4433828Sbostic 				/* Take a 4-byte long, lv, and turn it	*/
4533828Sbostic 				/* into an array of two 2-byte shorts, v*/
4633828Sbostic #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];}
4733828Sbostic 
4833828Sbostic #define MAGIC	070707		/* cpio magic number */
4933829Sbostic #define BSMAGIC	0143561		/* byte-swapped cpio magic number */
5033828Sbostic #define IN	'i'		/* copy in */
5133828Sbostic #define OUT	'o'		/* copy out */
5233828Sbostic #define PASS	'p'		/* direct copy */
5333828Sbostic #define HDRSIZE	(Hdr.h_name - (char *)&Hdr)	/* header size minus filename field */
5433828Sbostic #define LINKS	500		/* no. of links allocated per bunch */
5533828Sbostic #define CHARS	76		/* ASCII header size minus filename field */
5633828Sbostic #define BUFSIZE 512		/* In u370, can't use BUFSIZ or BSIZE */
5733828Sbostic #define CPIOBSZ 4096		/* file read/write */
5833828Sbostic #define MK_USHORT(a)	(a & 00000177777)	/* Make unsigned shorts for portable  */
5933828Sbostic 						/* header.  Hardware may only know    */
6033828Sbostic 						/* integer operations and sign extend */
6133828Sbostic 						/* the large unsigned short resulting */
6233828Sbostic 						/* in 8 rather than 6 octal char in   */
6333828Sbostic 						/* the header.			      */
6433828Sbostic 
6533828Sbostic static struct	stat	Statb, Xstatb;
6633828Sbostic 
6733828Sbostic 	/* Cpio header format */
6833828Sbostic static struct header {
6933828Sbostic 	short	h_magic;
7033828Sbostic 	short	h_dev;
7133828Sbostic 	ushort	h_ino;
7233828Sbostic 	ushort	h_mode,
7333828Sbostic 		h_uid,
7433828Sbostic 		h_gid;
7533828Sbostic 	short	h_nlink;
7633828Sbostic 	short	h_rdev;
7733828Sbostic 	short	h_mtime[2],
7833828Sbostic 		h_namesize,
7933828Sbostic 		h_filesize[2];
8033828Sbostic 	char	h_name[256];
8133828Sbostic } Hdr;
8233828Sbostic 
8333829Sbostic char	Symlbuf[MAXPATHLEN + 1];	/* target of symbolic link */
8433828Sbostic static unsigned	Bufsize = BUFSIZE;		/* default record size */
8533828Sbostic static char	Buf[CPIOBSZ], *Cbuf;
8633828Sbostic static char	*Cp;
8733828Sbostic 
8833828Sbostic 
8933828Sbostic static
9033828Sbostic short	Option,
9133828Sbostic 	Dir,
9233828Sbostic 	Uncond,
9333828Sbostic 	PassLink,
9433828Sbostic 	Rename,
9533828Sbostic 	Toc,
9633828Sbostic 	Verbose,
9733828Sbostic 	Mod_time,
9833828Sbostic 	Acc_time,
9933828Sbostic 	Cflag,
10033828Sbostic 	fflag,
10133828Sbostic 	Swap,
10233828Sbostic 	byteswap,
10333828Sbostic 	halfswap;
10433828Sbostic 
10533828Sbostic static
10633828Sbostic int	Ifile,
10733828Sbostic 	Ofile,
10833828Sbostic 	Input = 0,
10933828Sbostic 	Output = 1;
11033828Sbostic 			/* sBlocks: short Blocks.  Cumulative character   */
11133828Sbostic 			/* count for short reads in bread().  Encountered */
11233828Sbostic 			/* with communication lines and pipes as in:      */
11333828Sbostic 			/* split -100 cpio_archive; cat xa* | cpio -icd   */
11433828Sbostic static
11533828Sbostic long	sBlocks,
11633828Sbostic 	Blocks,
11733828Sbostic 	Longfile,
11833828Sbostic 	Longtime;
11933828Sbostic 
12033828Sbostic static
12133828Sbostic char	Fullname[256],
12233828Sbostic 	Name[256];
12333828Sbostic static
12433828Sbostic int	Pathend;
12533828Sbostic static
12633828Sbostic char	*swfile;
12733828Sbostic static
12833828Sbostic char	*eommsg = "Change to part %d and press RETURN key. [q] ";
12933828Sbostic 
13033828Sbostic static
13133828Sbostic FILE	*Rtty,
13233828Sbostic 	*Wtty;
13333828Sbostic static
13437871Sbostic char	ttyname[] = _PATH_TTY;
13533828Sbostic 
13633828Sbostic static
13733828Sbostic char	**Pattern = 0;
13833828Sbostic static
13933828Sbostic char	Chdr[500];
14033828Sbostic static
14133828Sbostic short	Dev;
14233828Sbostic ushort	Uid,
14333828Sbostic 	A_directory,
14433828Sbostic 	A_special,
14533829Sbostic 	A_symlink,
14633828Sbostic 	Filetype = S_IFMT;
14733828Sbostic 
14833828Sbostic extern	errno;
14933828Sbostic extern	void exit();
15033828Sbostic char	*malloc();
15133828Sbostic FILE 	*popen();
15233828Sbostic 
15333829Sbostic static char *smemcpy();
15433829Sbostic 
15533828Sbostic static
15633828Sbostic union {
15733828Sbostic 	long l;
15833828Sbostic 	short s[2];
15933828Sbostic 	char c[4];
16033828Sbostic } U;
16133828Sbostic 
16233828Sbostic /* for VAX, Interdata, ... */
16333828Sbostic static
mklong(v)16433828Sbostic long mklong(v)
16533828Sbostic short v[];
16633828Sbostic {
16733828Sbostic 	U.l = 1;
16833828Sbostic 	if(U.c[0])
16933828Sbostic 		U.s[0] = v[1], U.s[1] = v[0];
17033828Sbostic 	else
17133828Sbostic 		U.s[0] = v[0], U.s[1] = v[1];
17233828Sbostic 	return U.l;
17333828Sbostic }
17433828Sbostic 
175*46224Storek static	usage(), chkswfile(), getname(), bintochar(), chkhdr(), gethdr();
176*46224Storek static	ckname(), openout(), breread(), bread(), bwrite(), eomchgreel();
177*46224Storek static	postml(), pentry(), nmatch(), gmatch(), umatch(), set_time();
178*46224Storek static	chgreel(), missdir(), pwd(), fperr(), fperrno();
179*46224Storek 
main(argc,argv)18033828Sbostic main(argc, argv)
181*46224Storek int argc;
18233828Sbostic char **argv;
18333828Sbostic {
18433828Sbostic 	register ct;
18533828Sbostic 	long	filesz;
18633829Sbostic 	int	symlsz;
18733828Sbostic 	register char *fullp;
18833828Sbostic 	register i;
18933828Sbostic 	int ans;
19033829Sbostic 	register char *symlinkp;
19133828Sbostic 	short select;			/* set when files are selected */
19233828Sbostic 	extern char	*optarg;
19333828Sbostic 	extern int	optind;
19433828Sbostic 
19533829Sbostic 	signal(SIGSYS, SIG_IGN);
19633829Sbostic 	if(argc <= 1 || *argv[1] != '-')
19733828Sbostic 		usage();
19833828Sbostic 	Uid = getuid();
19933828Sbostic 
20033829Sbostic 	while( (ans = getopt( argc, argv, "aBC:ifopcdlmrSsbtuvM:6eI:O:")) != EOF ) {
20133828Sbostic 
20233828Sbostic 		switch( ans ) {
20333828Sbostic 		case 'a':		/* reset access time */
20433828Sbostic 			Acc_time++;
20533828Sbostic 			break;
20633828Sbostic 		case 'B':		/* change record size to 5120 bytes */
20733828Sbostic 			Bufsize = 5120;
20833828Sbostic 			break;
20933828Sbostic 		case 'C':		/* reset buffer size to arbitrary valu
21033828Sbostic 					*/
21133828Sbostic 			Bufsize = atoi( optarg );
21233829Sbostic 			if( Bufsize == 0 ) {
21333829Sbostic 				fperr("Illegal argument to -%c, '%s'",
21433828Sbostic 					ans, optarg );
21533829Sbostic 				exit(2);
21633829Sbostic 			}
21733828Sbostic 			break;
21833828Sbostic 		case 'i':
21933828Sbostic 			Option = IN;
22033828Sbostic 			break;
22133828Sbostic 		case 'f':	/* copy files not matched by patterns */
22233828Sbostic 			fflag++;
22333828Sbostic 			break;
22433828Sbostic 		case 'o':
22533828Sbostic 			Option = OUT;
22633828Sbostic 			break;
22733828Sbostic 		case 'p':
22833828Sbostic 			Option = PASS;
22933828Sbostic 			break;
23033828Sbostic 		case 'c':		/* ASCII header */
23133828Sbostic 			Cflag++;
23233828Sbostic 			break;
23333828Sbostic 		case 'd':		/* create directories when needed */
23433828Sbostic 			Dir++;
23533828Sbostic 			break;
23633828Sbostic 		case 'l':		/* link files, when necessary */
23733828Sbostic 			PassLink++;
23833828Sbostic 			break;
23933828Sbostic 		case 'm':		/* retain mod time */
24033828Sbostic 			Mod_time++;
24133828Sbostic 			break;
24233828Sbostic 		case 'r':		/* rename files interactively */
24333828Sbostic 			Rename++;
24433828Sbostic 			Rtty = fopen(ttyname, "r");
24533828Sbostic 			Wtty = fopen(ttyname, "w");
24633828Sbostic 			if(Rtty==NULL || Wtty==NULL) {
24733829Sbostic 				fperrno("Cannot rename (%s missing)",
24833828Sbostic 					ttyname );
24933829Sbostic 				exit(2);
25033828Sbostic 			}
25133828Sbostic 			break;
25233828Sbostic 		case 'S':		/* swap halfwords */
25333828Sbostic 			halfswap++;
25433828Sbostic 			Swap++;
25533828Sbostic 			break;
25633828Sbostic 		case 's':		/* swap bytes */
25733828Sbostic 			byteswap++;
25833828Sbostic 			Swap++;
25933828Sbostic 			break;
26033828Sbostic 		case 'b':		/* swap both bytes and halfwords */
26133829Sbostic 			halfswap++;
26233829Sbostic 			byteswap++;
26333828Sbostic 			Swap++;
26433828Sbostic 			break;
26533828Sbostic 		case 't':		/* table of contents */
26633828Sbostic 			Toc++;
26733828Sbostic 			break;
26833828Sbostic 		case 'u':		/* copy unconditionally */
26933828Sbostic 			Uncond++;
27033828Sbostic 			break;
27133828Sbostic 		case 'v':		/* verbose - print out file names */
27233829Sbostic 			Verbose++;
27333828Sbostic 			break;
27433828Sbostic 		case 'M':		/* alternate message for end-of-media */
27533828Sbostic 			eommsg = optarg;
27633828Sbostic 			break;
27733828Sbostic 		case '6':		/* for old, sixth-edition files */
27833828Sbostic 			Filetype = 060000;
27933828Sbostic 			break;
28033828Sbostic 		case 'I':
28133828Sbostic 			chkswfile( swfile, ans, Option );
28233829Sbostic 			if( (i = open( optarg, O_RDONLY ) ) < 0) {
28333829Sbostic 				fperrno("Cannot open <%s> for input", optarg);
28433829Sbostic 				exit(2);
28533829Sbostic 			}
28633829Sbostic 			if( dup2(i, Input ) < 0 ) {
28733829Sbostic 				fperrno("Cannot dup to standard input");
28833829Sbostic 				exit(2);
28933829Sbostic 			}
29033828Sbostic 			swfile = optarg;
29133828Sbostic 			break;
29233828Sbostic 		case 'O':
29333828Sbostic 			chkswfile( swfile, ans, Option );
29433829Sbostic 			if( (i = open( optarg, O_WRONLY | O_CREAT | O_TRUNC,
29533829Sbostic 			    0666 ) ) < 0) {
29633829Sbostic 				fperrno("Cannot open <%s> for output", optarg);
29733829Sbostic 				exit(2);
29833829Sbostic 			}
29933829Sbostic 			if( dup2(i, Output ) < 0 ) {
30033829Sbostic 				fperrno("Cannot dup to standard output");
30133829Sbostic 				exit(2);
30233829Sbostic 			}
30333828Sbostic 			swfile = optarg;
30433828Sbostic 			break;
30533828Sbostic 		default:
30633828Sbostic 			usage();
30733828Sbostic 		}
30833828Sbostic 	}
30933828Sbostic 	if(!Option) {
31033829Sbostic 		(void) fprintf(stderr,
31133829Sbostic 		    "Options must include one of -o, -i, or -p\n");
31233829Sbostic 		exit(2);
31333828Sbostic 	}
31433828Sbostic 
31533828Sbostic 	if(Option == PASS) {
31633828Sbostic 		if(Rename) {
31733829Sbostic 			(void) fprintf(stderr,
31833829Sbostic 			    "Pass and Rename cannot be used together\n");
31933829Sbostic 			exit(2);
32033828Sbostic 		}
32133828Sbostic 		if( Bufsize != BUFSIZE ) {
32233828Sbostic 			fprintf( stderr, "`B' or `C' option is irrelevant with the '-p' option\n");
32333828Sbostic 			Bufsize = BUFSIZE;
32433828Sbostic 		}
32533828Sbostic 
32633828Sbostic 	}else  {
32733829Sbostic 		Cp = Cbuf = (char *)malloc(Bufsize);
32833829Sbostic 		if(Cp == NULL) {
32933829Sbostic 			perror("cpio");
33033829Sbostic 			exit(2);
33133829Sbostic 		}
33233828Sbostic 	}
33333828Sbostic 	argc -= optind;
33433828Sbostic 	argv += optind;
33533828Sbostic 
33633828Sbostic 	switch(Option) {
33733828Sbostic 	case OUT:
33833828Sbostic 		if(argc != 0)
33933828Sbostic 			usage();
34033828Sbostic 		/* get filename, copy header and file out */
34133828Sbostic 		while(getname()) {
34233828Sbostic 			if( mklong(Hdr.h_filesize) == 0L) {
34333828Sbostic 				if( Cflag )
34433828Sbostic 					bwrite(Chdr,CHARS+Hdr.h_namesize);
34533828Sbostic 				else
34633828Sbostic 					bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
34733828Sbostic 				if(Verbose)
34833829Sbostic 					(void) fprintf(stderr, "%s\n",
34933829Sbostic 					    Hdr.h_name);
35033828Sbostic 				continue;
35133829Sbostic 			} else if( A_symlink ) {
35233829Sbostic 				symlsz = (int) mklong(Hdr.h_filesize);
35333829Sbostic 				if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
35433829Sbostic 					fperrno("Cannot read symbolic link <%s>",
35533829Sbostic 					    Hdr.h_name);
35633829Sbostic 					continue;
35733829Sbostic 				}
35833829Sbostic 				Symlbuf[symlsz] = '\0';
35933829Sbostic 				bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
36033829Sbostic 				bwrite(Symlbuf, symlsz);
36133829Sbostic 				if(Verbose)
36233829Sbostic 					(void) fprintf(stderr, "%s\n",
36333829Sbostic 					    Hdr.h_name);
36433829Sbostic 				continue;
36533828Sbostic 			}
36633828Sbostic 			if((Ifile = open(Hdr.h_name, 0)) < 0) {
36733829Sbostic 				fperrno("Cannot open <%s>", Hdr.h_name);
36833828Sbostic 				continue;
36933828Sbostic 			}
37033828Sbostic 			if ( Cflag )
37133828Sbostic 				bwrite(Chdr,CHARS+Hdr.h_namesize);
37233828Sbostic 			else
37333828Sbostic 				bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
37433828Sbostic 			for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
37533828Sbostic 				ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
37633828Sbostic 				if(read(Ifile, Buf, ct) < 0) {
37733829Sbostic  					fperrno("Cannot read %s", Hdr.h_name);
37833828Sbostic 					continue;
37933828Sbostic 				}
38033828Sbostic 				bwrite(Buf,ct);
38133828Sbostic 			}
38233828Sbostic 			close(Ifile);
38333829Sbostic 			if(Acc_time) {
38433829Sbostic 				struct utimbuf utb;
38533829Sbostic 
38633829Sbostic 				utb.actime = Statb.st_atime;
38733829Sbostic 				utb.modtime = Statb.st_mtime;
38833829Sbostic 				(void)utime(Hdr.h_name, &utb);
38933829Sbostic 			}
39033828Sbostic 			if(Verbose)
39133829Sbostic 				(void) fprintf(stderr, "%s\n", Hdr.h_name);
39233828Sbostic 		}
39333828Sbostic 
39433828Sbostic 	/* copy trailer, after all files have been copied */
39533828Sbostic 		strcpy(Hdr.h_name, "TRAILER!!!");
39633828Sbostic 		Hdr.h_magic = MAGIC;
39733828Sbostic 		MKSHORT(Hdr.h_filesize, 0L);
39833828Sbostic 		Hdr.h_namesize = strlen("TRAILER!!!") + 1;
39933828Sbostic 		if ( Cflag )  {
40033828Sbostic 			bintochar(0L);
40133828Sbostic 			bwrite(Chdr, CHARS+Hdr.h_namesize);
40233828Sbostic 		}
40333828Sbostic 		else
40433828Sbostic 			bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
40533828Sbostic 		bwrite(Cbuf, Bufsize);
40633828Sbostic 		break;
40733828Sbostic 
40833828Sbostic 	case IN:
40933828Sbostic 		if(argc > 0 ) {	/* save patterns, if any */
41033828Sbostic 			Pattern = argv;
41133828Sbostic 		}
41233828Sbostic 		pwd();
41333828Sbostic 		chkhdr();
41433828Sbostic 		while(gethdr()) {
41533829Sbostic 			if (A_symlink) {
41633829Sbostic 				symlsz = (int) mklong(Hdr.h_filesize);
41733829Sbostic 				bread(Symlbuf, symlsz);
41833829Sbostic 				Symlbuf[symlsz] = '\0';
41933830Sbostic 				if( ckname(Hdr.h_name)  &&  !Toc)
42033829Sbostic 					(void)openout(Hdr.h_name, Symlbuf);
42133829Sbostic 			} else {
42233829Sbostic 				if( (select = ckname(Hdr.h_name))  &&  !Toc )
42333829Sbostic 					Ofile = openout(Hdr.h_name, (char *)0);
42433829Sbostic 				else
42533829Sbostic 					Ofile = 0;
42633829Sbostic 				for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
42733829Sbostic 					ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
42833829Sbostic 					bread(Buf, ct);
42933829Sbostic 					if(Ofile) {
43033829Sbostic 						if(Swap)
43133829Sbostic 						       swap(Buf,ct,byteswap,halfswap);
43233829Sbostic 						if(write(Ofile, Buf, ct) < 0) {
43333829Sbostic 						 fperrno("Cannot write %s", Hdr.h_name);
43433829Sbostic 						 continue;
43533829Sbostic 						}
43633828Sbostic 					}
43733828Sbostic 				}
43833829Sbostic 				if( Ofile ) {
43933829Sbostic 					(void) close(Ofile);
44033829Sbostic 					if(chmod(Hdr.h_name, Hdr.h_mode) < 0)
44133829Sbostic 						fperrno("Cannot change mode of <%s>",
44233829Sbostic 						    Hdr.h_name);
44333829Sbostic 					set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
44433829Sbostic 				}
44533828Sbostic 			}
44633828Sbostic 			if(select) {
44733828Sbostic 				if(Verbose)
44833828Sbostic 					if(Toc)
44933828Sbostic 						pentry(Hdr.h_name);
45033828Sbostic 					else
45133829Sbostic 						puts(Hdr.h_name);
45233828Sbostic 				else if(Toc)
45333828Sbostic 					puts(Hdr.h_name);
45433828Sbostic 			}
45533828Sbostic 		}
45633828Sbostic 		break;
45733828Sbostic 
45833828Sbostic 	case PASS:		/* move files around */
45933828Sbostic 		if(argc != 1)
46033828Sbostic 			usage();
46133828Sbostic 		if(access(argv[0], 2) == -1) {
46233829Sbostic 			(void) fperrno("Cannot write in <%s>", argv[0]);
46333829Sbostic 			exit(2);
46433828Sbostic 		}
46533828Sbostic 		strcpy(Fullname, argv[0]);	/* destination directory */
46633829Sbostic 		if(stat(Fullname, &Xstatb) < 0) {
46733829Sbostic 			fperrno("Cannot stat <%s>", Fullname);
46833829Sbostic 			exit(2);
46933829Sbostic 		}
47033829Sbostic 		if((Xstatb.st_mode&S_IFMT) != S_IFDIR) {
47133829Sbostic 			(void) fprintf(stderr, "<%s> is not a directory",
47233829Sbostic 			    Fullname);
47333829Sbostic 			exit(2);
47433829Sbostic 		}
47533828Sbostic 		Dev = Xstatb.st_dev;
47633828Sbostic 		if( Fullname[ strlen(Fullname) - 1 ] != '/' )
47733828Sbostic 			strcat(Fullname, "/");
47833828Sbostic 		fullp = Fullname + strlen(Fullname);
47933828Sbostic 
48033828Sbostic 		while(getname()) {
48133828Sbostic 			if (A_directory && !Dir)
48233829Sbostic 				fperr("Use `-d' option to copy <%s>",
48333828Sbostic 					Hdr.h_name);
48433828Sbostic 			if(!ckname(Hdr.h_name))
48533828Sbostic 				continue;
48633828Sbostic 			i = 0;
48733828Sbostic 			while(Hdr.h_name[i] == '/')
48833828Sbostic 				i++;
48933828Sbostic 			strcpy(fullp, &(Hdr.h_name[i]));
49033828Sbostic 
49133828Sbostic 			if( PassLink  &&  !A_directory  &&  Dev == Statb.st_dev ) {
49233828Sbostic 				if(link(Hdr.h_name, Fullname) < 0) {
49333828Sbostic 					switch(errno) {
49433828Sbostic 						case ENOENT:
49533828Sbostic 							if(missdir(Fullname) != 0) {
49633829Sbostic 								fperrno("Cannot create directory for <%s>",
49733829Sbostic 									Fullname);
49833828Sbostic 								continue;
49933828Sbostic 							}
50033828Sbostic 							break;
50133828Sbostic 						case EEXIST:
50233828Sbostic 							if(unlink(Fullname) < 0) {
50333829Sbostic 								fperrno("Cannot unlink <%s>",
50433829Sbostic 									Fullname);
50533828Sbostic 								continue;
50633828Sbostic 							}
50733828Sbostic 							break;
50833828Sbostic 						default:
50933829Sbostic 							fperrno("Cannot link <%s> to <%s>",
51033829Sbostic 								Hdr.h_name, Fullname);
51133828Sbostic 							continue;
51233828Sbostic 						}
51333828Sbostic 					if(link(Hdr.h_name, Fullname) < 0) {
51433829Sbostic 						fperrno("Cannot link <%s> to <%s>",
51533829Sbostic 							Hdr.h_name, Fullname);
51633828Sbostic 						continue;
51733828Sbostic 					}
51833828Sbostic 				}
51933828Sbostic 
52033828Sbostic 				goto ckverbose;
52133828Sbostic 			}
52233829Sbostic 			if( A_symlink ) {
52333829Sbostic 			   symlsz = (int) mklong(Hdr.h_filesize);
52433829Sbostic 			   if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
52533829Sbostic 				fperrno("Cannot read symbolic link <%s>",
52633829Sbostic 				    Hdr.h_name);
52733828Sbostic 				continue;
52833829Sbostic 			   }
52933829Sbostic 			   Symlbuf[symlsz] = '\0';
53033829Sbostic 			   if(!openout(Fullname, Symlbuf))
53133829Sbostic 				continue;
53233829Sbostic 			   Blocks += ((symlsz + (BUFSIZE - 1)) / BUFSIZE);
53333829Sbostic 			   if(Verbose)
53433829Sbostic 				puts(Fullname);
53533829Sbostic 			   continue;
53633829Sbostic 			}
53733829Sbostic 			if(!(Ofile = openout(Fullname, (char *)0)))
53833829Sbostic 				continue;
53933829Sbostic 			if((Ifile = open(Hdr.h_name, 0)) < 0) {
54033829Sbostic 				fperrno("Cannot open <%s>", Hdr.h_name);
54133828Sbostic 				close(Ofile);
54233828Sbostic 				continue;
54333828Sbostic 			}
54433828Sbostic 			filesz = Statb.st_size;
54533828Sbostic 			for(; filesz > 0; filesz -= CPIOBSZ) {
54633828Sbostic 				ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
54733828Sbostic 				if(read(Ifile, Buf, ct) < 0) {
54833829Sbostic 					fperrno("Cannot read %s", Hdr.h_name);
54933828Sbostic 					break;
55033828Sbostic 				}
55133829Sbostic 				if(write(Ofile, Buf, ct) < 0) {
55233829Sbostic 				 fperrno("Cannot write %s", Hdr.h_name);
55333829Sbostic 				 break;
55433829Sbostic 				}
55533829Sbostic 				/* Removed u370 ifdef which caused cpio */
55633829Sbostic 				/* to report blocks in terms of 4096 bytes. */
55733828Sbostic 
55833828Sbostic 				Blocks += ((ct + (BUFSIZE - 1)) / BUFSIZE);
55933828Sbostic 			}
56033828Sbostic 			close(Ifile);
56133829Sbostic 			if(Acc_time) {
56233829Sbostic 				struct utimbuf utb;
56333829Sbostic 
56433829Sbostic 				utb.actime = Statb.st_atime;
56533829Sbostic 				utb.modtime = Statb.st_mtime;
56633829Sbostic 				(void)utime(Hdr.h_name, &utb);
56733829Sbostic 			}
56833828Sbostic 			if(Ofile) {
56933828Sbostic 				close(Ofile);
57033829Sbostic 				if(chmod(Fullname, Hdr.h_mode) < 0)
57133829Sbostic 					fperrno("Cannot change mode of <%s>",
57233829Sbostic 					    Fullname);
57333828Sbostic 				set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime));
57433828Sbostic ckverbose:
57533828Sbostic 				if(Verbose)
57633829Sbostic 					puts(Fullname);
57733828Sbostic 			}
57833828Sbostic 		}
57933828Sbostic 	}
58033828Sbostic 	/* print number of blocks actually copied */
58133828Sbostic 	Blocks += ((sBlocks + (BUFSIZE - 1)) / BUFSIZE);
58233829Sbostic 	(void) fprintf(stderr, "%ld blocks\n", Blocks * (Bufsize>>9));
58333828Sbostic 	exit(0);
58433828Sbostic }
58533828Sbostic 
58633828Sbostic static
usage()58733828Sbostic usage()
58833828Sbostic {
589*46224Storek 	(void) fprintf(stderr,
590*46224Storek 	    "Usage: %s\n     %s\n     %s\n     %s\n       %s\n",
59133829Sbostic 	    "cpio -o[acvB] <name-list >collection",
59233829Sbostic 	    "cpio -o[acvB] -Ocollection <name-list",
59333829Sbostic 	    "cpio -i[cdmrstuvfB6] [ pattern ... ] <collection",
59433829Sbostic 	    "cpio -i[cdmrstuvfB6] -Icollection [ pattern ... ]",
59533829Sbostic 	    "cpio -p[adlmruv] directory <name-list");
59633828Sbostic }
59733828Sbostic 
59833828Sbostic static
chkswfile(sp,c,option)59933828Sbostic chkswfile( sp, c, option )
60033828Sbostic char	*sp;
60133828Sbostic char	c;
60233828Sbostic short	option;
60333828Sbostic {
60433829Sbostic 	if( !option ) {
60533829Sbostic 		fperr( "-%c must be specified before -%c option",
60633828Sbostic 			c == 'I' ? 'i' : 'o', c );
60733829Sbostic 		exit(2);
60833829Sbostic 	}
60933829Sbostic 	if( (c == 'I'  &&  option != IN)  ||  (c == 'O'  &&  option != OUT) ) {
61033829Sbostic 		fperr( "-%c option not permitted with -%c option", c,
61133828Sbostic 			option );
61233829Sbostic 		exit(2);
61333829Sbostic 	}
61433828Sbostic 	if( !sp )
61533828Sbostic 		return;
61633829Sbostic 	fperr("No more than one -I or -O flag permitted");
61733829Sbostic 	exit(2);
61833828Sbostic }
61933828Sbostic 
62033828Sbostic static
getname()62133828Sbostic getname()		/* get file name, get info for header */
62233828Sbostic {
62333828Sbostic 	register char *namep = Name;
62433828Sbostic 	register ushort ftype;
62533829Sbostic 	struct stat Lstatb;
62633828Sbostic 	long tlong;
62733828Sbostic 
62833828Sbostic 	for(;;) {
62933828Sbostic 		if(gets(namep) == NULL)
63033828Sbostic 			return 0;
63133828Sbostic 		while(*namep == '.' && namep[1] == '/') {
63233828Sbostic 			namep++;
63333828Sbostic 			while(*namep == '/') namep++;
63433828Sbostic 		}
63533828Sbostic 		strcpy(Hdr.h_name, namep);
63633829Sbostic 		if(lstat(namep, &Statb) < 0) {
63733829Sbostic 			fperrno("Cannot stat <%s>", Hdr.h_name);
63833828Sbostic 			continue;
63933828Sbostic 		}
64033828Sbostic 		ftype = Statb.st_mode & Filetype;
64133828Sbostic 		A_directory = (ftype == S_IFDIR);
64233828Sbostic 		A_special = (ftype == S_IFBLK)
64333828Sbostic 			|| (ftype == S_IFCHR)
64433828Sbostic 			|| (ftype == S_IFIFO);
64533829Sbostic 		A_symlink = (ftype == S_IFLNK);
64633828Sbostic 		Hdr.h_magic = MAGIC;
64733828Sbostic 		Hdr.h_namesize = strlen(Hdr.h_name) + 1;
64833828Sbostic 		Hdr.h_uid = Statb.st_uid;
64933828Sbostic 		Hdr.h_gid = Statb.st_gid;
65033828Sbostic 		Hdr.h_dev = Statb.st_dev;
65133828Sbostic 		Hdr.h_ino = Statb.st_ino;
65233828Sbostic 		Hdr.h_mode = Statb.st_mode;
65333828Sbostic 		MKSHORT(Hdr.h_mtime, Statb.st_mtime);
65433828Sbostic 		Hdr.h_nlink = Statb.st_nlink;
65533829Sbostic 		tlong = ((Hdr.h_mode&S_IFMT) == S_IFREG ||
65633829Sbostic 			(Hdr.h_mode&S_IFMT) == S_IFLNK)? Statb.st_size: 0L;
65733828Sbostic 		MKSHORT(Hdr.h_filesize, tlong);
65833828Sbostic 		Hdr.h_rdev = Statb.st_rdev;
65933828Sbostic 		if( Cflag )
66033828Sbostic 			bintochar(tlong);
66133828Sbostic 		return 1;
66233828Sbostic 	}
66333828Sbostic }
66433828Sbostic 
66533828Sbostic static
bintochar(t)66633828Sbostic bintochar(t)		/* ASCII header write */
66733828Sbostic long t;
66833828Sbostic {
66933828Sbostic 	sprintf(Chdr,"%.6o%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.11lo%.6ho%.11lo%s",
67033828Sbostic 		MAGIC, MK_USHORT(Statb.st_dev), MK_USHORT(Statb.st_ino), Statb.st_mode, Statb.st_uid,
67133828Sbostic 		Statb.st_gid, Statb.st_nlink, MK_USHORT(Statb.st_rdev),
67233828Sbostic 		Statb.st_mtime, (short)strlen(Hdr.h_name)+1, t, Hdr.h_name);
67333828Sbostic }
67433828Sbostic 
67533828Sbostic static
chartobin()67633828Sbostic chartobin()		/* ASCII header read */
67733828Sbostic {
67833828Sbostic 	sscanf(Chdr, "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6ho%11lo",
67933828Sbostic 		&Hdr.h_magic, &Hdr.h_dev, &Hdr.h_ino, &Hdr.h_mode, &Hdr.h_uid,
68033828Sbostic 		&Hdr.h_gid, &Hdr.h_nlink, &Hdr.h_rdev, &Longtime,
68133828Sbostic 		&Hdr.h_namesize, &Longfile);
68233828Sbostic 	MKSHORT(Hdr.h_filesize, Longfile);
68333828Sbostic 	MKSHORT(Hdr.h_mtime, Longtime);
68433828Sbostic }
68533828Sbostic 
68633828Sbostic 
68733828Sbostic /*	Check the header for the magic number.  Switch modes automatically to
68833828Sbostic 	match the type of header found.
68933828Sbostic */
69033828Sbostic static
chkhdr()69133828Sbostic chkhdr()
69233828Sbostic {
69333828Sbostic 	bread(Chdr, CHARS);
69433828Sbostic 	chartobin();
69533828Sbostic 	if( Hdr.h_magic == MAGIC )
69633828Sbostic 		Cflag = 1;
69733828Sbostic 	else {
69833828Sbostic 		breread(&Hdr.h_magic, sizeof Hdr.h_magic);
69933829Sbostic 		if( Hdr.h_magic == MAGIC || Hdr.h_magic == (short)BSMAGIC )
70033828Sbostic 			Cflag = 0;
70133829Sbostic 		else {
70233829Sbostic 			fperr("This is not a cpio file.  Bad magic number.");
70333829Sbostic 			exit(2);
70433829Sbostic 		}
70533828Sbostic 	}
70633828Sbostic 	breread(Chdr, 0);
70733828Sbostic }
70833828Sbostic 
70933828Sbostic 
71033828Sbostic static
gethdr()71133828Sbostic gethdr()		/* get file headers */
71233828Sbostic {
71333828Sbostic 	register ushort ftype;
71433828Sbostic 
71533828Sbostic 	if (Cflag)  {
71633828Sbostic 		bread(Chdr, CHARS);
71733828Sbostic 		chartobin();
71833828Sbostic 	}
71933828Sbostic 	else
72033828Sbostic 		bread(&Hdr, HDRSIZE);
72133828Sbostic 
72233829Sbostic 	if(Hdr.h_magic == (short)BSMAGIC)
72333829Sbostic 		swap((char *)&Hdr, HDRSIZE, 1, 0);
72433829Sbostic 	else if( Hdr.h_magic != MAGIC ) {
72533829Sbostic 		fperr("Out of phase--get help");
72633829Sbostic 		exit(2);
72733828Sbostic 	}
72833828Sbostic 	bread(Hdr.h_name, Hdr.h_namesize);
72933828Sbostic 	if(EQ(Hdr.h_name, "TRAILER!!!"))
73033828Sbostic 		return 0;
73133828Sbostic 	ftype = Hdr.h_mode & Filetype;
73233828Sbostic 	A_directory = (ftype == S_IFDIR);
73333828Sbostic 	A_special = (ftype == S_IFBLK)
73433828Sbostic 		||  (ftype == S_IFCHR)
73533828Sbostic 		||  (ftype == S_IFIFO);
73633829Sbostic 	A_symlink = (ftype == S_IFLNK);
73733828Sbostic 	return 1;
73833828Sbostic }
73933828Sbostic 
74033828Sbostic static
ckname(namep)74133828Sbostic ckname(namep)	/* check filenames with patterns given on cmd line */
74233828Sbostic register char *namep;
74333828Sbostic {
74433828Sbostic 	char	buf[sizeof Hdr.h_name];
74533828Sbostic 
74633828Sbostic 	if(fflag ^ !nmatch(namep, Pattern)) {
74733828Sbostic 		return 0;
74833828Sbostic 	}
74933828Sbostic 	if(Rename && !A_directory) {	/* rename interactively */
75033828Sbostic 		fprintf(Wtty, "Rename <%s>\n", namep);
75133828Sbostic 		fflush(Wtty);
75233828Sbostic 		fgets(buf, sizeof buf, Rtty);
75333828Sbostic 		if(feof(Rtty))
75433828Sbostic 			exit(2);
75533828Sbostic 		buf[strlen(buf) - 1] = '\0';
75633828Sbostic 		if(EQ(buf, "")) {
75733828Sbostic 			strcpy(namep,buf);
75833828Sbostic 			printf("Skipped\n");
75933828Sbostic 			return 0;
76033828Sbostic 		}
76133828Sbostic 		else if(EQ(buf, "."))
76233828Sbostic 			printf("Same name\n");
76333828Sbostic 		else
76433828Sbostic 			strcpy(namep,buf);
76533828Sbostic 	}
76633828Sbostic 	return  1;
76733828Sbostic }
76833828Sbostic 
76933828Sbostic static
openout(namep,symlname)77033829Sbostic openout(namep, symlname)	/* open files for writing, set all necessary info */
77133828Sbostic register char *namep;
77233829Sbostic char *symlname;
77333828Sbostic {
77433828Sbostic 	register f;
77533828Sbostic 	register char *np;
77633828Sbostic 	int ans;
77733828Sbostic 
77833828Sbostic 	if(!strncmp(namep, "./", 2))
77933828Sbostic 		namep += 2;
78033828Sbostic 	np = namep;
78133828Sbostic 	if(A_directory) {
78233828Sbostic 		if( !Dir  ||  Rename  ||  EQ(namep, ".")  ||  EQ(namep, "..") )
78333828Sbostic 			/* do not consider . or .. files */
78433828Sbostic 			return 0;
78533828Sbostic 		if(stat(namep, &Xstatb) == -1) {
78633828Sbostic 
78733828Sbostic /* try creating (only twice) */
78833828Sbostic 			ans = 0;
78933828Sbostic 			do {
79033829Sbostic 				if(mkdir(namep, Hdr.h_mode) != 0) {
79133828Sbostic 					ans += 1;
79233828Sbostic 				}else {
79333828Sbostic 					ans = 0;
79433828Sbostic 					break;
79533828Sbostic 				}
79633828Sbostic 			}while(ans < 2 && missdir(namep) == 0);
79733828Sbostic 			if(ans == 1) {
79833828Sbostic 				fperrno("Cannot create directory for <%s>",
79933828Sbostic 					namep);
80033828Sbostic 				return(0);
80133828Sbostic 			}else if(ans == 2) {
80233828Sbostic 				fperrno("Cannot create directory <%s>", namep);
80333828Sbostic 				return(0);
80433828Sbostic 			}
80533828Sbostic 		}
80633828Sbostic 
80733828Sbostic ret:
80833829Sbostic 		if(chmod(namep, Hdr.h_mode) < 0)
80933829Sbostic 			fperrno("Cannot change mode of <%s>", namep);
81033828Sbostic 		if(Uid == 0)
81133829Sbostic 			if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
81233829Sbostic 				fperrno("Cannot change ownership of <%s>",
81333829Sbostic 				    namep);
81433828Sbostic 		set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
81533828Sbostic 		return 0;
81633828Sbostic 	}
81733828Sbostic 	if(Hdr.h_nlink > 1)
81833828Sbostic 		if(!postml(namep, np))
81933828Sbostic 			return 0;
82033829Sbostic 	if(lstat(namep, &Xstatb) == 0) {
82133828Sbostic 		if(Uncond && !((!(Xstatb.st_mode & S_IWRITE) || A_special) && (Uid != 0))) {
82233828Sbostic 			if(unlink(namep) < 0) {
82333828Sbostic 				fperrno("cannot unlink current <%s>", namep);
82433828Sbostic 			}
82533828Sbostic 		}
82633828Sbostic 		if(!Uncond && (mklong(Hdr.h_mtime) <= Xstatb.st_mtime)) {
82733828Sbostic 		/* There's a newer or same aged version of file on destination */
82833829Sbostic 			fperr("current <%s> newer or same age", np);
82933828Sbostic 			return 0;
83033828Sbostic 		}
83133828Sbostic 	}
83233828Sbostic 	if( Option == PASS
83333828Sbostic 		&& Hdr.h_ino == Xstatb.st_ino
83433828Sbostic 		&& Hdr.h_dev == Xstatb.st_dev) {
83533829Sbostic 		fperr("Attempt to pass file to self!");
83633829Sbostic 		exit(2);
83733828Sbostic 	}
83833829Sbostic 	if(A_symlink) {
83933829Sbostic /* try symlinking (only twice) */
84033829Sbostic 		ans = 0;
84133829Sbostic 		do {
84233829Sbostic 			if(symlink(
84333829Sbostic symlname, namep) < 0) {
84433829Sbostic 				ans += 1;
84533829Sbostic 			}else {
84633829Sbostic 				ans = 0;
84733829Sbostic 				break;
84833829Sbostic 			}
84933829Sbostic 		}while(ans < 2 && missdir(np) == 0);
85033829Sbostic 		if(ans == 1) {
85133829Sbostic 			fperrno("Cannot create directory for <%s>", namep);
85233829Sbostic 			return(0);
85333829Sbostic 		}else if(ans == 2) {
85433829Sbostic 			fperrno("Cannot symlink <%s> and <%s>", namep, symlname);
85533829Sbostic 			return(0);
85633829Sbostic 		}
85733829Sbostic 
85833829Sbostic 		return 0;
85933829Sbostic 	}
86033828Sbostic 	if(A_special) {
86133828Sbostic 		if((Hdr.h_mode & Filetype) == S_IFIFO)
86233828Sbostic 			Hdr.h_rdev = 0;
86333828Sbostic 
86433828Sbostic /* try creating (only twice) */
86533828Sbostic 		ans = 0;
86633828Sbostic 		do {
86733828Sbostic 			if(mknod(namep, Hdr.h_mode, Hdr.h_rdev) < 0) {
86833828Sbostic 				ans += 1;
86933828Sbostic 			}else {
87033828Sbostic 				ans = 0;
87133828Sbostic 				break;
87233828Sbostic 			}
87333828Sbostic 		}while(ans < 2 && missdir(np) == 0);
87433828Sbostic 		if(ans == 1) {
87533828Sbostic 			fperrno("Cannot create directory for <%s>", namep);
87633828Sbostic 			return(0);
87733828Sbostic 		}else if(ans == 2) {
87833828Sbostic 			fperrno("Cannot mknod <%s>", namep);
87933828Sbostic 			return(0);
88033828Sbostic 		}
88133828Sbostic 
88233828Sbostic 		goto ret;
88333828Sbostic 	}
88433828Sbostic 
88533828Sbostic /* try creating (only twice) */
88633828Sbostic 	ans = 0;
88733828Sbostic 	do {
88833828Sbostic 		if((f = creat(namep, Hdr.h_mode)) < 0) {
88933828Sbostic 			ans += 1;
89033828Sbostic 		}else {
89133828Sbostic 			ans = 0;
89233828Sbostic 			break;
89333828Sbostic 		}
89433828Sbostic 	}while(ans < 2 && missdir(np) == 0);
89533828Sbostic 	if(ans == 1) {
89633828Sbostic 		fperrno("Cannot create directory for <%s>", namep);
89733828Sbostic 		return(0);
89833828Sbostic 	}else if(ans == 2) {
89933828Sbostic 		fperrno("Cannot create <%s>", namep);
90033828Sbostic 		return(0);
90133828Sbostic 	}
90233828Sbostic 
90333828Sbostic 	if(Uid == 0)
90433829Sbostic 		if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
90533829Sbostic 			fperrno("Cannot change ownership of <%s>", namep);
90633828Sbostic 	return f;
90733828Sbostic }
90833828Sbostic 
90933828Sbostic 
91033828Sbostic /*	Shared by bread() and breread()
91133828Sbostic */
91233828Sbostic static int	nleft = 0;	/* unread chars left in Cbuf */
91333828Sbostic static char	*ip;		/* pointer to next char to be read from Cbuf */
91433828Sbostic 
91533828Sbostic /*	Reread the current buffer Cbuf.
91633828Sbostic 	A character count, c, of 0 simply resets the pointer so next bread gets
91733828Sbostic 	the same data again.
91833828Sbostic */
91933828Sbostic static
breread(b,c)92033828Sbostic breread(b, c)
92133828Sbostic char	*b;
92233828Sbostic int	c;
92333828Sbostic {
92433828Sbostic 	ip = Cbuf;
92533828Sbostic 	if( nleft )
92633828Sbostic 		nleft = Bufsize;
92733828Sbostic 	if( !c )
92833828Sbostic 		return;
92933828Sbostic 	bread(b, c);
93033828Sbostic }
93133828Sbostic 
93233828Sbostic static
bread(b,c)93333828Sbostic bread(b, c)
93433828Sbostic register char	*b;
93533828Sbostic register int	c;
93633828Sbostic {
93733828Sbostic 	register int	rv;
93833828Sbostic 	register char	*p = ip;
93933828Sbostic 
94033828Sbostic 	if( !Cflag ) {
94133828Sbostic 		/* round c up to an even number */
94233828Sbostic 		c = (c+1)/2;
94333828Sbostic 		c *= 2;
94433828Sbostic 	}
94533828Sbostic 	while( c )  {
94633828Sbostic 		if( nleft == 0 ) {
94733828Sbostic 			while( (rv = read(Input, Cbuf, Bufsize)) == 0 ) {
94833828Sbostic 				Input = chgreel(0, Input, rv);
94933828Sbostic 			}
95033828Sbostic 			if( rv == Bufsize ) {
95133828Sbostic 				nleft = Bufsize;
95233828Sbostic 				p = Cbuf;
95333828Sbostic 				++Blocks;
95433828Sbostic 			}
95533829Sbostic 			else if( rv == -1 ) {
95633829Sbostic 				fperrno("Read error on archive");
95733829Sbostic 				exit(2);
95833829Sbostic 			}
95933828Sbostic 			else if( rv < Bufsize ) {	/* short read */
96033828Sbostic 				smemcpy( &Cbuf[ Bufsize - rv ], Cbuf, rv );
96133828Sbostic 				nleft = rv;
96233828Sbostic 				p = &Cbuf[ Bufsize - rv ];
96333828Sbostic 				sBlocks += rv;
96433828Sbostic 			}
96533828Sbostic 		}
96633828Sbostic 		if( nleft <= c ) {
96733828Sbostic 			memcpy( b, p, nleft );
96833828Sbostic 			c -= nleft;
96933828Sbostic 			b += nleft;
97033828Sbostic 			p += nleft;
97133828Sbostic 			nleft = 0;
97233828Sbostic 		}
97333828Sbostic 		else {
97433828Sbostic 			memcpy( b, p, c );
97533828Sbostic 			nleft -= c;
97633828Sbostic 			b += c;
97733828Sbostic 			p += c;
97833828Sbostic 			c = 0;
97933828Sbostic 		}
98033828Sbostic 	}
98133828Sbostic 	ip = p;
98233828Sbostic }
98333828Sbostic 
98433828Sbostic 
98533828Sbostic static
bwrite(rp,c)98633828Sbostic bwrite(rp, c)
98733828Sbostic register char *rp;
98833828Sbostic register c;
98933828Sbostic {
99033828Sbostic 	register char	*cp = Cp;
99133828Sbostic 	static unsigned	Ccnt = 0;
99233828Sbostic 	register unsigned Cleft;
99333828Sbostic 	register int	rv;
99433828Sbostic 
99533828Sbostic 	if( !Cflag ) {
99633828Sbostic 		/* round c up to an even number */
99733828Sbostic 		c = (c+1)/2;
99833828Sbostic 		c *= 2;
99933828Sbostic 	}
100033828Sbostic 	while( c )  {
100133828Sbostic 		if( (Cleft = Bufsize - Ccnt) <= c ) {
100233828Sbostic 			memcpy( cp, rp, Cleft );
100333828Sbostic 			rv = write(Output, Cbuf, Bufsize);
100433828Sbostic 			if( rv == 0  ||  ( rv == -1  &&  errno == ENXIO ) ) {
100533828Sbostic 				rv = eomchgreel();
100633828Sbostic 			}
100733828Sbostic 			if( rv == Bufsize ) {
100833828Sbostic 				Ccnt = 0;
100933828Sbostic 				cp = Cbuf;
101033828Sbostic 			}
101133829Sbostic 			else if( rv == -1 ) {
101233829Sbostic 				fperrno("Write error on archive");
101333829Sbostic 				exit(2);
101433829Sbostic 			}
101533828Sbostic 			else if( rv < Bufsize ) {
101633828Sbostic 				Output = chgreel(1, Output, 0);
101733828Sbostic 				smemcpy( Cbuf, &Cbuf[ Bufsize - rv ], rv );
101833828Sbostic 				Ccnt = Bufsize - rv;
101933828Sbostic 				cp = &Cbuf[ rv ];
102033828Sbostic 			}
102133828Sbostic 			++Blocks;
102233828Sbostic 			rp += Cleft;
102333828Sbostic 			c -= Cleft;
102433828Sbostic 		}
102533828Sbostic 		else {
102633828Sbostic 			memcpy( cp, rp, c );
102733828Sbostic 			Ccnt += c;
102833828Sbostic 			cp += c;
102933828Sbostic 			rp += c;
103033828Sbostic 			c = 0;
103133828Sbostic 		}
103233828Sbostic 	}
103333828Sbostic 	Cp = cp;
103433828Sbostic }
103533828Sbostic 
103633828Sbostic 
103733828Sbostic static int	reelcount = 1;	/* used below and in chgreel() */
103833828Sbostic 
103933828Sbostic /*	Change reel due to reaching end-of-media.
104033828Sbostic 	Keep trying to get a successful write before considering the
104133828Sbostic 	change-of-reel as successful.
104233828Sbostic */
104333828Sbostic static
104433828Sbostic int
eomchgreel()104533828Sbostic eomchgreel()
104633828Sbostic {
104733828Sbostic 	int	rv;
104833828Sbostic 
104933828Sbostic 	while( 1 ) {
105033828Sbostic 		Output = chgreel(1, Output, 0);
105133828Sbostic 		rv = write(Output, Cbuf, Bufsize);
105233828Sbostic 		if( rv == Bufsize )
105333828Sbostic 			return  rv;
105433829Sbostic 		if( rv == -1 )
105533829Sbostic 			fperrno( "Unable to write this medium" );
105633829Sbostic 		else
105733829Sbostic 			fperr( "Unable to write this medium: Premature EOF" );
105833829Sbostic 		(void) fprintf(stderr, "Try again.\n");
105933828Sbostic 		reelcount--;
106033828Sbostic 	}
106133828Sbostic 	/*NOTREACHED*/
106233828Sbostic }
106333828Sbostic 
106433828Sbostic 
106533828Sbostic static
postml(namep,np)106633828Sbostic postml(namep, np)		/* linking funtion:  Postml() is called after */
106733828Sbostic register char *namep, *np;	/* namep is created.  Postml() checks to see  */
106833828Sbostic {				/* if namep should be linked to np.  If so,   */
106933828Sbostic 				/* postml() removes the independent instance  */
107033828Sbostic 	register i;		/* of namep and links namep to np.	      */
107133828Sbostic 	static struct ml {
107233828Sbostic 		short	m_dev;
107333828Sbostic 		ushort	m_ino;
107433828Sbostic 		char	m_name[2];
107533828Sbostic 	} **ml = 0;
107633828Sbostic 	register struct ml	*mlp;
107733828Sbostic 	static unsigned	mlsize = 0;
107833828Sbostic 	static unsigned	mlinks = 0;
107933828Sbostic 	char		*lnamep;
108033828Sbostic 	int		ans;
108133828Sbostic 
108233828Sbostic 	if( !ml ) {
108333828Sbostic 		mlsize = LINKS;
108433829Sbostic 		ml = (struct ml **) malloc(mlsize * sizeof(struct ml));
108533828Sbostic 	}
108633828Sbostic 	else if( mlinks == mlsize ) {
108733828Sbostic 		mlsize += LINKS;
108833829Sbostic 		ml = (struct ml **) realloc((char *) ml,
108933829Sbostic 		    mlsize * sizeof(struct ml));
109033828Sbostic 	}
109133829Sbostic 	if (ml == NULL) {
109233829Sbostic 		fperr("Out of memory for links");
109333829Sbostic 		exit(2);
109433829Sbostic 	}
109533828Sbostic 	for(i = 0; i < mlinks; ++i) {
109633828Sbostic 		mlp = ml[i];
109733828Sbostic 		if(mlp->m_ino==Hdr.h_ino  &&  mlp->m_dev==Hdr.h_dev) {
109833828Sbostic 			if(Verbose)
109933829Sbostic 			  printf("%s linked to %s\n", ml[i]->m_name,
110033829Sbostic 				np);
110133828Sbostic 			unlink(namep);
110233828Sbostic 			if(Option == IN && *(mlp->m_name) != '/') {
110333828Sbostic 				Fullname[Pathend] = '\0';
110433828Sbostic 				strcat(Fullname, mlp->m_name);
110533828Sbostic 				lnamep = Fullname;
110633828Sbostic 			}
110733828Sbostic 			lnamep = mlp->m_name;
110833828Sbostic 
110933828Sbostic /* try linking (only twice) */
111033828Sbostic 			ans = 0;
111133828Sbostic 			do {
111233828Sbostic 				if(link(lnamep, namep) < 0) {
111333828Sbostic 					ans += 1;
111433828Sbostic 				}else {
111533828Sbostic 					ans = 0;
111633828Sbostic 					break;
111733828Sbostic 				}
111833828Sbostic 			}while(ans < 2 && missdir(np) == 0);
111933828Sbostic 			if(ans == 1) {
112033828Sbostic 				fperrno("Cannot create directory for <%s>", np);
112133828Sbostic 				return(0);
112233828Sbostic 			}else if(ans == 2) {
112333828Sbostic 				fperrno("Cannot link <%s> & <%s>", lnamep, np);
112433828Sbostic 				return(0);
112533828Sbostic 			}
112633828Sbostic 
112733828Sbostic 			set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
112833828Sbostic 			return 0;
112933828Sbostic 		}
113033828Sbostic 	}
113133829Sbostic 	if( !(ml[mlinks] = (struct ml *)malloc(strlen(np) + 2 + sizeof(struct ml)))) {
113233828Sbostic 		static int first=1;
113333828Sbostic 
113433828Sbostic 		if(first)
113533829Sbostic 			fperr("Out of memory for links");
113633828Sbostic 		first = 0;
113733828Sbostic 		return 1;
113833828Sbostic 	}
113933828Sbostic 	ml[mlinks]->m_dev = Hdr.h_dev;
114033828Sbostic 	ml[mlinks]->m_ino = Hdr.h_ino;
114133828Sbostic 	strcpy(ml[mlinks]->m_name, np);
114233828Sbostic 	++mlinks;
114333828Sbostic 	return 1;
114433828Sbostic }
114533828Sbostic 
114633828Sbostic static
pentry(namep)114733828Sbostic pentry(namep)		/* print verbose table of contents */
114833828Sbostic register char *namep;
114933828Sbostic {
115033828Sbostic 	static short lastid = -1;
115133828Sbostic 	static struct passwd *pw;
115233828Sbostic 	static char tbuf[32];
115333828Sbostic 	char *ctime();
115433828Sbostic 
115533828Sbostic 	printf("%-7o", MK_USHORT(Hdr.h_mode));
115633828Sbostic 	if(lastid == Hdr.h_uid)
115733828Sbostic 		printf("%-6s", pw->pw_name);
115833828Sbostic 	else {
115933828Sbostic 		setpwent();
116033828Sbostic 		if(pw = getpwuid((int)Hdr.h_uid)) {
116133828Sbostic 			printf("%-6s", pw->pw_name);
116233828Sbostic 			lastid = Hdr.h_uid;
116333828Sbostic 		} else {
116433828Sbostic 			printf("%-6d", Hdr.h_uid);
116533828Sbostic 			lastid = -1;
116633828Sbostic 		}
116733828Sbostic 	}
116833828Sbostic 	printf("%7ld ", mklong(Hdr.h_filesize));
116933828Sbostic 	U.l = mklong(Hdr.h_mtime);
117033828Sbostic 	strcpy(tbuf, ctime((long *)&U.l));
117133828Sbostic 	tbuf[24] = '\0';
117233829Sbostic 	printf(" %s  %s", &tbuf[4], namep);
117333829Sbostic 	if (A_symlink)
117433829Sbostic 		printf(" -> %s", Symlbuf);
117533829Sbostic 	putchar('\n');
117633828Sbostic }
117733828Sbostic 
117833828Sbostic 		/* pattern matching functions */
117933828Sbostic static
nmatch(s,pat)118033828Sbostic nmatch(s, pat)
118133828Sbostic char *s, **pat;
118233828Sbostic {
118333828Sbostic 	if( !pat )
118433828Sbostic 		return 1;
118533828Sbostic 	while(*pat) {
118633828Sbostic 		if((**pat == '!' && !gmatch(s, *pat+1))
118733828Sbostic 		|| gmatch(s, *pat))
118833828Sbostic 			return 1;
118933828Sbostic 		++pat;
119033828Sbostic 	}
119133828Sbostic 	return 0;
119233828Sbostic }
119333828Sbostic 
119433828Sbostic 
119533828Sbostic static
gmatch(s,p)119633828Sbostic gmatch(s, p)
119733828Sbostic register char *s, *p;
119833828Sbostic {
119933828Sbostic 	register int c;
120033828Sbostic 	register cc, ok, lc, scc;
120133828Sbostic 
120233828Sbostic 	scc = *s;
120333828Sbostic 	lc = 077777;
120433828Sbostic 	switch (c = *p) {
120533828Sbostic 
120633828Sbostic 	case '[':
120733828Sbostic 		ok = 0;
120833828Sbostic 		while (cc = *++p) {
120933828Sbostic 			switch (cc) {
121033828Sbostic 
121133828Sbostic 			case ']':
121233828Sbostic 				if (ok)
121333828Sbostic 					return(gmatch(++s, ++p));
121433828Sbostic 				else
121533828Sbostic 					return(0);
121633828Sbostic 
121733828Sbostic 			case '-':
121833828Sbostic 				ok |= ((lc <= scc) && (scc <= (cc=p[1])));
121933828Sbostic 			}
122033828Sbostic 			if (scc==(lc=cc)) ok++;
122133828Sbostic 		}
122233828Sbostic 		return(0);
122333828Sbostic 
122433828Sbostic 	case '?':
122533828Sbostic 	caseq:
122633828Sbostic 		if(scc) return(gmatch(++s, ++p));
122733828Sbostic 		return(0);
122833828Sbostic 	case '*':
122933828Sbostic 		return(umatch(s, ++p));
123033828Sbostic 	case 0:
123133828Sbostic 		return(!scc);
123233828Sbostic 	}
123333828Sbostic 	if (c==scc) goto caseq;
123433828Sbostic 	return(0);
123533828Sbostic }
123633828Sbostic 
123733828Sbostic 
123833828Sbostic 
123933828Sbostic static
umatch(s,p)124033828Sbostic umatch(s, p)
124133828Sbostic register char *s, *p;
124233828Sbostic {
124333828Sbostic 	if(*p==0) return(1);
124433828Sbostic 	while(*s)
124533828Sbostic 		if (gmatch(s++,p)) return(1);
124633828Sbostic 	return(0);
124733828Sbostic }
124833828Sbostic 
swap(buf,bytecount,bytes,halfwords)124933829Sbostic swap(buf, bytecount, bytes, halfwords)	/* swap halfwords, bytes or both */
125033829Sbostic char *buf;
125133829Sbostic int bytecount;
125233829Sbostic int bytes, halfwords;
125333828Sbostic {
125433829Sbostic 	register int count;
125533829Sbostic 	int n, i;
125633828Sbostic 
125733829Sbostic 	if(bytes) {
125833829Sbostic 		register union swpbytes {
125933829Sbostic 			short	shortw;
126033829Sbostic 			char	charv[2];
126133829Sbostic 		} *pbuf;
126233829Sbostic 		register char c;
126333828Sbostic 
126433829Sbostic 		count = bytecount;
126533829Sbostic 		pbuf = (union swpbytes *)buf;
126633829Sbostic 		if (count % sizeof(union swpbytes))
126733829Sbostic 			pbuf->charv[count] = 0;
126833829Sbostic 		count = (count + (sizeof(union swpbytes) - 1)) / sizeof(union swpbytes);
126933829Sbostic 		while (count--) {
127033829Sbostic 			c = pbuf->charv[0];
127133829Sbostic 			pbuf->charv[0] = pbuf->charv[1];
127233829Sbostic 			pbuf->charv[1] = c;
127333829Sbostic 			++pbuf;
127433828Sbostic 		}
127533828Sbostic 	}
127633829Sbostic 	if (halfwords) {
127733829Sbostic 		register union swphalf {
127833829Sbostic 			long	longw;
127933829Sbostic 			short	shortv[2];
128033829Sbostic 			char	charv[4];
128133829Sbostic 		} *pbuf;
128233829Sbostic 		register short cc;
128333829Sbostic 
128433829Sbostic 		count = bytecount;
128533829Sbostic 		pbuf = (union swphalf *)buf;
128633829Sbostic 		if (n = count % sizeof(union swphalf))
128733829Sbostic 			if(bytes && n % 2)
128833829Sbostic 				for(i = count + 1; i <= count + (sizeof(union swphalf) - n); i++)
128933829Sbostic 					pbuf->charv[i] = 0;
129033829Sbostic 			else
129133829Sbostic 				for (i = count; i < count + (sizeof(union swphalf) - n); i++)
129233829Sbostic 					pbuf->charv[i] = 0;
129333829Sbostic 		count = (count + (sizeof(union swphalf) - 1)) / sizeof(union swphalf);
129433829Sbostic 		while (count--) {
129533828Sbostic 			cc = pbuf->shortv[0];
129633828Sbostic 			pbuf->shortv[0] = pbuf->shortv[1];
129733828Sbostic 			pbuf->shortv[1] = cc;
129833828Sbostic 			++pbuf;
129933828Sbostic 		}
130033828Sbostic 	}
130133828Sbostic }
130233828Sbostic 
130333828Sbostic 
130433828Sbostic static
set_time(namep,atime,mtime)130533828Sbostic set_time(namep, atime, mtime)	/* set access and modification times */
130633828Sbostic register char *namep;
130733828Sbostic time_t atime, mtime;
130833828Sbostic {
130933829Sbostic 	static struct utimbuf timevec;
131033828Sbostic 
131133828Sbostic 	if(!Mod_time)
131233828Sbostic 		return;
131333829Sbostic 	timevec.actime = atime;
131433829Sbostic 	timevec.modtime = mtime;
131533829Sbostic 	(void)utime(namep, &timevec);
131633828Sbostic }
131733828Sbostic 
131833828Sbostic 
131933828Sbostic 
132033828Sbostic static
chgreel(x,fl,rv)132133828Sbostic chgreel(x, fl, rv)
1322*46224Storek 	int x, fl, rv;
132333828Sbostic {
132433828Sbostic 	register f;
132533828Sbostic 	char str[BUFSIZ];
132633828Sbostic 	struct stat statb;
132733828Sbostic 
132833828Sbostic 	fstat(fl, &statb);
132933828Sbostic 	if((statb.st_mode&S_IFMT) != S_IFCHR) {
133033828Sbostic 		fperrno("Can't %s: ", x? "write output": "read input");
133133828Sbostic 		exit(2);
133233828Sbostic 	}
133333828Sbostic 	if( rv == 0  ||
133433828Sbostic 		( rv == -1  &&  ( errno == ENOSPC  ||  errno == ENXIO ) ) )
133533829Sbostic 		fperr( "\007Reached end of medium on %s",
133633828Sbostic 			x? "output":"input" );
133733828Sbostic 	else {
133833828Sbostic 		fperrno( "\007Encountered an error on %s",
133933828Sbostic 			x? "output":"input" );
134033828Sbostic 		exit(2);
134133828Sbostic 	}
134233829Sbostic 	if( Rtty == NULL ) {
134333829Sbostic 		Rtty = fopen(ttyname, "r");
134433829Sbostic 		if( Rtty == NULL ) {
134533829Sbostic 			fperrno("Cannot prompt (can't open %s)", ttyname);
134633829Sbostic 			exit(2);
134733829Sbostic 		}
134833829Sbostic 	}
134933828Sbostic 	close(fl);
135033828Sbostic 	reelcount++;
135133828Sbostic again:
135233828Sbostic 	if( swfile ) {
135333828Sbostic 	    askagain:
135433828Sbostic 		fperr( eommsg, reelcount );
135533828Sbostic 		fgets(str, sizeof str, Rtty);
135633828Sbostic 		switch( *str ) {
135733828Sbostic 		case '\n':
135833828Sbostic 			strcpy( str, swfile );
135933828Sbostic 			break;
136033828Sbostic 		case 'q':
136133828Sbostic 			exit(2);
136233828Sbostic 		default:
136333828Sbostic 			goto askagain;
136433828Sbostic 		}
136533828Sbostic 	}
136633828Sbostic 	else {
136733829Sbostic 		fperr("If you want to go on, type device/file name when ready.");
136833828Sbostic 		fgets(str, sizeof str, Rtty);
136933828Sbostic 		str[strlen(str) - 1] = '\0';
137033828Sbostic 		if(!*str)
137133828Sbostic 			exit(2);
137233828Sbostic 	}
137333828Sbostic 	if((f = open(str, x? 1: 0)) < 0) {
137433829Sbostic 		fperrno("Can't open <%s>", str);
137533828Sbostic 		goto again;
137633828Sbostic 	}
137733828Sbostic 	return f;
137833828Sbostic }
137933828Sbostic 
138033828Sbostic 
138133828Sbostic 
138233828Sbostic static
missdir(namep)138333828Sbostic missdir(namep)
138433828Sbostic register char *namep;
138533828Sbostic {
138633828Sbostic 	register char *np;
138733828Sbostic 	register ct = 2;
138833828Sbostic 
138933828Sbostic 	for(np = namep; *np; ++np)
139033828Sbostic 		if(*np == '/') {
139133828Sbostic 			if(np == namep) continue;	/* skip over 'root slash' */
139233828Sbostic 			*np = '\0';
139333828Sbostic 			if(stat(namep, &Xstatb) == -1) {
139433828Sbostic 				if(Dir) {
139533829Sbostic 					if((ct = mkdir(namep, 0777)) != 0) {
139633828Sbostic 						*np = '/';
139733828Sbostic 						return(ct);
139833828Sbostic 					}
139933828Sbostic 				}else {
140033829Sbostic 					fperr("missing 'd' option");
140133828Sbostic 					return(-1);
140233828Sbostic 				}
140333828Sbostic 			}
140433828Sbostic 			*np = '/';
140533828Sbostic 		}
140633828Sbostic 	if (ct == 2) ct = 0;		/* the file already exists */
140733828Sbostic 	return ct;
140833828Sbostic }
140933828Sbostic 
141033828Sbostic 
141133828Sbostic 
141233828Sbostic static
pwd()141333828Sbostic pwd()		/* get working directory */
141433828Sbostic {
141533829Sbostic 	if (getwd(Fullname) == 0) {
141633829Sbostic 		(void)fprintf(stderr, "cpio: %s\n",
141733829Sbostic 		    Fullname);
141833828Sbostic 		exit(2);
141933829Sbostic 	}
142033828Sbostic 	Pathend = strlen(Fullname);
142133829Sbostic 	Fullname[Pathend++] = '/';
142233829Sbostic 	Fullname[Pathend] = '\0';
142333828Sbostic }
142433828Sbostic 
142533828Sbostic 
142633828Sbostic /*
142733828Sbostic 	print message on the stderr
142833828Sbostic */
142933828Sbostic static
fperr(va_alist)143033828Sbostic fperr( va_alist )
143133828Sbostic va_dcl
143233828Sbostic {
143333828Sbostic 	va_list	args;
143433828Sbostic 	char	*fmt;
143533828Sbostic 
143633828Sbostic 	va_start( args );
143733829Sbostic 	fprintf( stderr, "cpio: ");
143833828Sbostic 	fmt = va_arg( args, char * );
143933828Sbostic 	vfprintf( stderr, fmt, args );
144033829Sbostic 	putc( '\n', stderr);
144133828Sbostic 	fflush( stderr );
144233828Sbostic }
144333828Sbostic 
144433828Sbostic /*
144533828Sbostic 	print message on the stderr followed by error number and meaning.
144633828Sbostic */
144733828Sbostic static
fperrno(va_alist)144833828Sbostic fperrno( va_alist )
144933828Sbostic va_dcl
145033828Sbostic {
145133828Sbostic 	va_list	args;
145233828Sbostic 	char	*fmt;
145333828Sbostic 
145433828Sbostic 	va_start( args );
145533829Sbostic 	fprintf( stderr, "cpio: ");
145633828Sbostic 	fmt = va_arg( args, char * );
145733828Sbostic 	vfprintf( stderr, fmt, args );
145833829Sbostic 	fprintf( stderr, ": " );
145933828Sbostic 	fflush( stderr );
146033828Sbostic 	perror("");
146133828Sbostic }
146233828Sbostic 
146333828Sbostic 
146433829Sbostic /*	Safe memory copy.
146533829Sbostic 	Fast if the to and from strings do not overlap,
146633829Sbostic 	slower but safe if they do.
146733829Sbostic */
146833829Sbostic 
146933829Sbostic static char *
smemcpy(to,from,count)147033829Sbostic smemcpy( to, from, count )
147133829Sbostic register char		*to, *from;
147233829Sbostic register unsigned	count;
147333828Sbostic {
147433829Sbostic 	char	*savedto;
147533829Sbostic 
147633829Sbostic 	if( &to[ count ] <= from  ||  &from[ count ] <= to )
147733829Sbostic 		return  memcpy( to, from, count );
147833829Sbostic 
147933829Sbostic 	if( to == from )
148033829Sbostic 		return  to;
148133829Sbostic 
148233829Sbostic 	savedto = to;
148333829Sbostic 	if( to < from )
148433829Sbostic 		while( count-- )
148533829Sbostic 			*(to++) = *(from++);
148633829Sbostic 	else {
148733829Sbostic 		to += count;
148833829Sbostic 		from += count;
148933829Sbostic 		while( count-- )
149033829Sbostic 			*(--to) = *(--from);
149133828Sbostic 	}
149233828Sbostic 
149333829Sbostic 	return  savedto;
149433828Sbostic }
1495