BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.bin / cpio / cpio.c
CommitLineData
76bbb78b
KB
1/* Copyright (c) 1988 AT&T */
2/* All Rights Reserved */
3
4/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
5/* The copyright notice above does not evidence any */
6/* actual or intended publication of such source code. */
7
8#ident "@(#)cpio:cpio.c 1.30.1.11"
9/* /sccs/src/cmd/s.cpio.c
10 cpio.c 1.30.1.11 1/11/86 13:46:48
11 Reworked cpio which uses getopt(3) to interpret flag arguments and
12 changes reels to the save file name.
13 Performance and size improvements.
14*/
15
16/* cpio COMPILE: cc -O cpio.c -s -i -o cpio -lgen -lerr
17 cpio -- copy file collections
18
19*/
76bbb78b 20#include <errno.h>
e4897c30 21#include <stdio.h>
76bbb78b
KB
22#include <fcntl.h>
23#include <memory.h>
e4897c30 24#include <pwd.h>
76bbb78b
KB
25#include <string.h>
26#include <signal.h>
27#include <varargs.h>
fd2d2fec
KB
28#include <sys/param.h>
29#include <sys/types.h>
76bbb78b 30#include <sys/stat.h>
435e8dff 31#include <paths.h>
76bbb78b 32
fd2d2fec
KB
33struct utimbuf {
34 time_t actime;
35 time_t modtime;
36};
37#ifndef S_IFIFO
38#define S_IFIFO 010000
39#endif
40
76bbb78b
KB
41#define EQ(x,y) (strcmp(x,y)==0)
42
43 /* MKSHORT: for VAX, Interdata, ... */
44 /* Take a 4-byte long, lv, and turn it */
45 /* into an array of two 2-byte shorts, v*/
46#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];}
47
48#define MAGIC 070707 /* cpio magic number */
fd2d2fec 49#define BSMAGIC 0143561 /* byte-swapped cpio magic number */
76bbb78b
KB
50#define IN 'i' /* copy in */
51#define OUT 'o' /* copy out */
52#define PASS 'p' /* direct copy */
53#define HDRSIZE (Hdr.h_name - (char *)&Hdr) /* header size minus filename field */
54#define LINKS 500 /* no. of links allocated per bunch */
55#define CHARS 76 /* ASCII header size minus filename field */
56#define BUFSIZE 512 /* In u370, can't use BUFSIZ or BSIZE */
57#define CPIOBSZ 4096 /* file read/write */
58#define MK_USHORT(a) (a & 00000177777) /* Make unsigned shorts for portable */
59 /* header. Hardware may only know */
60 /* integer operations and sign extend */
61 /* the large unsigned short resulting */
62 /* in 8 rather than 6 octal char in */
63 /* the header. */
64
65static struct stat Statb, Xstatb;
66
67 /* Cpio header format */
68static struct header {
69 short h_magic;
70 short h_dev;
71 ushort h_ino;
72 ushort h_mode,
73 h_uid,
74 h_gid;
75 short h_nlink;
76 short h_rdev;
77 short h_mtime[2],
78 h_namesize,
79 h_filesize[2];
80 char h_name[256];
81} Hdr;
82
fd2d2fec 83char Symlbuf[MAXPATHLEN + 1]; /* target of symbolic link */
76bbb78b
KB
84static unsigned Bufsize = BUFSIZE; /* default record size */
85static char Buf[CPIOBSZ], *Cbuf;
86static char *Cp;
87
88
89static
90short Option,
91 Dir,
92 Uncond,
93 PassLink,
94 Rename,
95 Toc,
96 Verbose,
97 Mod_time,
98 Acc_time,
99 Cflag,
100 fflag,
101 Swap,
102 byteswap,
76bbb78b
KB
103 halfswap;
104
105static
106int Ifile,
107 Ofile,
108 Input = 0,
109 Output = 1;
110 /* sBlocks: short Blocks. Cumulative character */
111 /* count for short reads in bread(). Encountered */
112 /* with communication lines and pipes as in: */
113 /* split -100 cpio_archive; cat xa* | cpio -icd */
114static
115long sBlocks,
116 Blocks,
117 Longfile,
118 Longtime;
119
120static
121char Fullname[256],
122 Name[256];
123static
124int Pathend;
125static
126char *swfile;
127static
128char *eommsg = "Change to part %d and press RETURN key. [q] ";
129
130static
131FILE *Rtty,
132 *Wtty;
133static
435e8dff 134char ttyname[] = _PATH_TTY;
76bbb78b
KB
135
136static
137char **Pattern = 0;
138static
139char Chdr[500];
140static
141short Dev;
142ushort Uid,
143 A_directory,
144 A_special,
fd2d2fec 145 A_symlink,
76bbb78b
KB
146 Filetype = S_IFMT;
147
148extern errno;
149extern void exit();
76bbb78b
KB
150char *malloc();
151FILE *popen();
152
fd2d2fec
KB
153static char *smemcpy();
154
76bbb78b
KB
155static
156union {
157 long l;
158 short s[2];
159 char c[4];
160} U;
161
162/* for VAX, Interdata, ... */
163static
164long mklong(v)
165short v[];
166{
167 U.l = 1;
168 if(U.c[0])
169 U.s[0] = v[1], U.s[1] = v[0];
170 else
171 U.s[0] = v[0], U.s[1] = v[1];
172 return U.l;
173}
174
e4897c30
CT
175static usage(), chkswfile(), getname(), bintochar(), chkhdr(), gethdr();
176static ckname(), openout(), breread(), bread(), bwrite(), eomchgreel();
177static postml(), pentry(), nmatch(), gmatch(), umatch(), set_time();
178static chgreel(), missdir(), pwd(), fperr(), fperrno();
179
76bbb78b 180main(argc, argv)
e4897c30 181int argc;
76bbb78b
KB
182char **argv;
183{
184 register ct;
185 long filesz;
fd2d2fec 186 int symlsz;
76bbb78b
KB
187 register char *fullp;
188 register i;
189 int ans;
fd2d2fec 190 register char *symlinkp;
76bbb78b
KB
191 short select; /* set when files are selected */
192 extern char *optarg;
193 extern int optind;
194
fd2d2fec
KB
195 signal(SIGSYS, SIG_IGN);
196 if(argc <= 1 || *argv[1] != '-')
76bbb78b
KB
197 usage();
198 Uid = getuid();
76bbb78b 199
fd2d2fec 200 while( (ans = getopt( argc, argv, "aBC:ifopcdlmrSsbtuvM:6eI:O:")) != EOF ) {
76bbb78b
KB
201
202 switch( ans ) {
203 case 'a': /* reset access time */
204 Acc_time++;
205 break;
206 case 'B': /* change record size to 5120 bytes */
207 Bufsize = 5120;
208 break;
209 case 'C': /* reset buffer size to arbitrary valu
210 */
211 Bufsize = atoi( optarg );
fd2d2fec
KB
212 if( Bufsize == 0 ) {
213 fperr("Illegal argument to -%c, '%s'",
76bbb78b 214 ans, optarg );
fd2d2fec
KB
215 exit(2);
216 }
76bbb78b
KB
217 break;
218 case 'i':
219 Option = IN;
220 break;
221 case 'f': /* copy files not matched by patterns */
222 fflag++;
223 break;
224 case 'o':
225 Option = OUT;
226 break;
227 case 'p':
228 Option = PASS;
229 break;
230 case 'c': /* ASCII header */
231 Cflag++;
232 break;
233 case 'd': /* create directories when needed */
234 Dir++;
235 break;
236 case 'l': /* link files, when necessary */
237 PassLink++;
238 break;
239 case 'm': /* retain mod time */
240 Mod_time++;
241 break;
242 case 'r': /* rename files interactively */
243 Rename++;
244 Rtty = fopen(ttyname, "r");
245 Wtty = fopen(ttyname, "w");
246 if(Rtty==NULL || Wtty==NULL) {
fd2d2fec 247 fperrno("Cannot rename (%s missing)",
76bbb78b 248 ttyname );
fd2d2fec 249 exit(2);
76bbb78b
KB
250 }
251 break;
252 case 'S': /* swap halfwords */
253 halfswap++;
254 Swap++;
255 break;
256 case 's': /* swap bytes */
257 byteswap++;
258 Swap++;
259 break;
260 case 'b': /* swap both bytes and halfwords */
fd2d2fec
KB
261 halfswap++;
262 byteswap++;
76bbb78b
KB
263 Swap++;
264 break;
265 case 't': /* table of contents */
266 Toc++;
267 break;
268 case 'u': /* copy unconditionally */
269 Uncond++;
270 break;
271 case 'v': /* verbose - print out file names */
fd2d2fec 272 Verbose++;
76bbb78b
KB
273 break;
274 case 'M': /* alternate message for end-of-media */
275 eommsg = optarg;
276 break;
277 case '6': /* for old, sixth-edition files */
278 Filetype = 060000;
279 break;
280 case 'I':
281 chkswfile( swfile, ans, Option );
fd2d2fec
KB
282 if( (i = open( optarg, O_RDONLY ) ) < 0) {
283 fperrno("Cannot open <%s> for input", optarg);
284 exit(2);
285 }
286 if( dup2(i, Input ) < 0 ) {
287 fperrno("Cannot dup to standard input");
288 exit(2);
289 }
76bbb78b
KB
290 swfile = optarg;
291 break;
292 case 'O':
293 chkswfile( swfile, ans, Option );
fd2d2fec
KB
294 if( (i = open( optarg, O_WRONLY | O_CREAT | O_TRUNC,
295 0666 ) ) < 0) {
296 fperrno("Cannot open <%s> for output", optarg);
297 exit(2);
298 }
299 if( dup2(i, Output ) < 0 ) {
300 fperrno("Cannot dup to standard output");
301 exit(2);
302 }
76bbb78b
KB
303 swfile = optarg;
304 break;
305 default:
306 usage();
307 }
308 }
309 if(!Option) {
fd2d2fec
KB
310 (void) fprintf(stderr,
311 "Options must include one of -o, -i, or -p\n");
312 exit(2);
76bbb78b
KB
313 }
314
315 if(Option == PASS) {
316 if(Rename) {
fd2d2fec
KB
317 (void) fprintf(stderr,
318 "Pass and Rename cannot be used together\n");
319 exit(2);
76bbb78b
KB
320 }
321 if( Bufsize != BUFSIZE ) {
322 fprintf( stderr, "`B' or `C' option is irrelevant with the '-p' option\n");
323 Bufsize = BUFSIZE;
324 }
325
326 }else {
fd2d2fec
KB
327 Cp = Cbuf = (char *)malloc(Bufsize);
328 if(Cp == NULL) {
329 perror("cpio");
330 exit(2);
331 }
76bbb78b
KB
332 }
333 argc -= optind;
334 argv += optind;
335
336 switch(Option) {
337 case OUT:
338 if(argc != 0)
339 usage();
340 /* get filename, copy header and file out */
341 while(getname()) {
342 if( mklong(Hdr.h_filesize) == 0L) {
343 if( Cflag )
344 bwrite(Chdr,CHARS+Hdr.h_namesize);
345 else
346 bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
347 if(Verbose)
fd2d2fec
KB
348 (void) fprintf(stderr, "%s\n",
349 Hdr.h_name);
350 continue;
351 } else if( A_symlink ) {
352 symlsz = (int) mklong(Hdr.h_filesize);
353 if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
354 fperrno("Cannot read symbolic link <%s>",
355 Hdr.h_name);
356 continue;
357 }
358 Symlbuf[symlsz] = '\0';
359 bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
360 bwrite(Symlbuf, symlsz);
361 if(Verbose)
362 (void) fprintf(stderr, "%s\n",
363 Hdr.h_name);
76bbb78b
KB
364 continue;
365 }
366 if((Ifile = open(Hdr.h_name, 0)) < 0) {
fd2d2fec 367 fperrno("Cannot open <%s>", Hdr.h_name);
76bbb78b
KB
368 continue;
369 }
370 if ( Cflag )
371 bwrite(Chdr,CHARS+Hdr.h_namesize);
372 else
373 bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
374 for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
375 ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
376 if(read(Ifile, Buf, ct) < 0) {
fd2d2fec 377 fperrno("Cannot read %s", Hdr.h_name);
76bbb78b
KB
378 continue;
379 }
380 bwrite(Buf,ct);
381 }
382 close(Ifile);
fd2d2fec
KB
383 if(Acc_time) {
384 struct utimbuf utb;
385
386 utb.actime = Statb.st_atime;
387 utb.modtime = Statb.st_mtime;
388 (void)utime(Hdr.h_name, &utb);
389 }
76bbb78b 390 if(Verbose)
fd2d2fec 391 (void) fprintf(stderr, "%s\n", Hdr.h_name);
76bbb78b
KB
392 }
393
394 /* copy trailer, after all files have been copied */
395 strcpy(Hdr.h_name, "TRAILER!!!");
396 Hdr.h_magic = MAGIC;
397 MKSHORT(Hdr.h_filesize, 0L);
398 Hdr.h_namesize = strlen("TRAILER!!!") + 1;
399 if ( Cflag ) {
400 bintochar(0L);
401 bwrite(Chdr, CHARS+Hdr.h_namesize);
402 }
403 else
404 bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
405 bwrite(Cbuf, Bufsize);
406 break;
407
408 case IN:
409 if(argc > 0 ) { /* save patterns, if any */
410 Pattern = argv;
411 }
412 pwd();
413 chkhdr();
414 while(gethdr()) {
fd2d2fec
KB
415 if (A_symlink) {
416 symlsz = (int) mklong(Hdr.h_filesize);
417 bread(Symlbuf, symlsz);
418 Symlbuf[symlsz] = '\0';
4dc7a4c9 419 if( ckname(Hdr.h_name) && !Toc)
fd2d2fec
KB
420 (void)openout(Hdr.h_name, Symlbuf);
421 } else {
422 if( (select = ckname(Hdr.h_name)) && !Toc )
423 Ofile = openout(Hdr.h_name, (char *)0);
424 else
425 Ofile = 0;
426 for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
427 ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
428 bread(Buf, ct);
429 if(Ofile) {
430 if(Swap)
431 swap(Buf,ct,byteswap,halfswap);
432 if(write(Ofile, Buf, ct) < 0) {
433 fperrno("Cannot write %s", Hdr.h_name);
434 continue;
435 }
76bbb78b
KB
436 }
437 }
fd2d2fec
KB
438 if( Ofile ) {
439 (void) close(Ofile);
440 if(chmod(Hdr.h_name, Hdr.h_mode) < 0)
441 fperrno("Cannot change mode of <%s>",
442 Hdr.h_name);
443 set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
444 }
76bbb78b
KB
445 }
446 if(select) {
447 if(Verbose)
448 if(Toc)
449 pentry(Hdr.h_name);
450 else
fd2d2fec 451 puts(Hdr.h_name);
76bbb78b
KB
452 else if(Toc)
453 puts(Hdr.h_name);
454 }
455 }
456 break;
457
458 case PASS: /* move files around */
459 if(argc != 1)
460 usage();
461 if(access(argv[0], 2) == -1) {
fd2d2fec
KB
462 (void) fperrno("Cannot write in <%s>", argv[0]);
463 exit(2);
76bbb78b
KB
464 }
465 strcpy(Fullname, argv[0]); /* destination directory */
fd2d2fec
KB
466 if(stat(Fullname, &Xstatb) < 0) {
467 fperrno("Cannot stat <%s>", Fullname);
468 exit(2);
469 }
470 if((Xstatb.st_mode&S_IFMT) != S_IFDIR) {
471 (void) fprintf(stderr, "<%s> is not a directory",
472 Fullname);
473 exit(2);
474 }
76bbb78b
KB
475 Dev = Xstatb.st_dev;
476 if( Fullname[ strlen(Fullname) - 1 ] != '/' )
477 strcat(Fullname, "/");
478 fullp = Fullname + strlen(Fullname);
479
480 while(getname()) {
481 if (A_directory && !Dir)
fd2d2fec 482 fperr("Use `-d' option to copy <%s>",
76bbb78b
KB
483 Hdr.h_name);
484 if(!ckname(Hdr.h_name))
485 continue;
486 i = 0;
487 while(Hdr.h_name[i] == '/')
488 i++;
489 strcpy(fullp, &(Hdr.h_name[i]));
490
491 if( PassLink && !A_directory && Dev == Statb.st_dev ) {
492 if(link(Hdr.h_name, Fullname) < 0) {
493 switch(errno) {
494 case ENOENT:
495 if(missdir(Fullname) != 0) {
fd2d2fec
KB
496 fperrno("Cannot create directory for <%s>",
497 Fullname);
76bbb78b
KB
498 continue;
499 }
500 break;
501 case EEXIST:
502 if(unlink(Fullname) < 0) {
fd2d2fec
KB
503 fperrno("Cannot unlink <%s>",
504 Fullname);
76bbb78b
KB
505 continue;
506 }
507 break;
508 default:
fd2d2fec
KB
509 fperrno("Cannot link <%s> to <%s>",
510 Hdr.h_name, Fullname);
76bbb78b
KB
511 continue;
512 }
513 if(link(Hdr.h_name, Fullname) < 0) {
fd2d2fec
KB
514 fperrno("Cannot link <%s> to <%s>",
515 Hdr.h_name, Fullname);
76bbb78b
KB
516 continue;
517 }
518 }
519
520 goto ckverbose;
521 }
fd2d2fec
KB
522 if( A_symlink ) {
523 symlsz = (int) mklong(Hdr.h_filesize);
524 if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
525 fperrno("Cannot read symbolic link <%s>",
526 Hdr.h_name);
527 continue;
528 }
529 Symlbuf[symlsz] = '\0';
530 if(!openout(Fullname, Symlbuf))
531 continue;
532 Blocks += ((symlsz + (BUFSIZE - 1)) / BUFSIZE);
533 if(Verbose)
534 puts(Fullname);
535 continue;
536 }
537 if(!(Ofile = openout(Fullname, (char *)0)))
76bbb78b 538 continue;
fd2d2fec
KB
539 if((Ifile = open(Hdr.h_name, 0)) < 0) {
540 fperrno("Cannot open <%s>", Hdr.h_name);
76bbb78b
KB
541 close(Ofile);
542 continue;
543 }
544 filesz = Statb.st_size;
545 for(; filesz > 0; filesz -= CPIOBSZ) {
546 ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
547 if(read(Ifile, Buf, ct) < 0) {
fd2d2fec 548 fperrno("Cannot read %s", Hdr.h_name);
76bbb78b
KB
549 break;
550 }
fd2d2fec
KB
551 if(write(Ofile, Buf, ct) < 0) {
552 fperrno("Cannot write %s", Hdr.h_name);
553 break;
554 }
555 /* Removed u370 ifdef which caused cpio */
556 /* to report blocks in terms of 4096 bytes. */
76bbb78b
KB
557
558 Blocks += ((ct + (BUFSIZE - 1)) / BUFSIZE);
559 }
560 close(Ifile);
fd2d2fec
KB
561 if(Acc_time) {
562 struct utimbuf utb;
563
564 utb.actime = Statb.st_atime;
565 utb.modtime = Statb.st_mtime;
566 (void)utime(Hdr.h_name, &utb);
567 }
76bbb78b
KB
568 if(Ofile) {
569 close(Ofile);
fd2d2fec
KB
570 if(chmod(Fullname, Hdr.h_mode) < 0)
571 fperrno("Cannot change mode of <%s>",
572 Fullname);
76bbb78b
KB
573 set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime));
574ckverbose:
575 if(Verbose)
fd2d2fec 576 puts(Fullname);
76bbb78b
KB
577 }
578 }
579 }
580 /* print number of blocks actually copied */
581 Blocks += ((sBlocks + (BUFSIZE - 1)) / BUFSIZE);
fd2d2fec 582 (void) fprintf(stderr, "%ld blocks\n", Blocks * (Bufsize>>9));
76bbb78b
KB
583 exit(0);
584}
585
586static
587usage()
588{
e4897c30
CT
589 (void) fprintf(stderr,
590 "Usage: %s\n %s\n %s\n %s\n %s\n",
fd2d2fec
KB
591 "cpio -o[acvB] <name-list >collection",
592 "cpio -o[acvB] -Ocollection <name-list",
593 "cpio -i[cdmrstuvfB6] [ pattern ... ] <collection",
594 "cpio -i[cdmrstuvfB6] -Icollection [ pattern ... ]",
595 "cpio -p[adlmruv] directory <name-list");
76bbb78b
KB
596}
597
598static
599chkswfile( sp, c, option )
600char *sp;
601char c;
602short option;
603{
fd2d2fec
KB
604 if( !option ) {
605 fperr( "-%c must be specified before -%c option",
76bbb78b 606 c == 'I' ? 'i' : 'o', c );
fd2d2fec
KB
607 exit(2);
608 }
609 if( (c == 'I' && option != IN) || (c == 'O' && option != OUT) ) {
610 fperr( "-%c option not permitted with -%c option", c,
76bbb78b 611 option );
fd2d2fec
KB
612 exit(2);
613 }
76bbb78b
KB
614 if( !sp )
615 return;
fd2d2fec
KB
616 fperr("No more than one -I or -O flag permitted");
617 exit(2);
76bbb78b
KB
618}
619
620static
621getname() /* get file name, get info for header */
622{
623 register char *namep = Name;
624 register ushort ftype;
fd2d2fec 625 struct stat Lstatb;
76bbb78b
KB
626 long tlong;
627
628 for(;;) {
629 if(gets(namep) == NULL)
630 return 0;
631 while(*namep == '.' && namep[1] == '/') {
632 namep++;
633 while(*namep == '/') namep++;
634 }
635 strcpy(Hdr.h_name, namep);
fd2d2fec
KB
636 if(lstat(namep, &Statb) < 0) {
637 fperrno("Cannot stat <%s>", Hdr.h_name);
76bbb78b
KB
638 continue;
639 }
640 ftype = Statb.st_mode & Filetype;
641 A_directory = (ftype == S_IFDIR);
642 A_special = (ftype == S_IFBLK)
643 || (ftype == S_IFCHR)
644 || (ftype == S_IFIFO);
fd2d2fec 645 A_symlink = (ftype == S_IFLNK);
76bbb78b
KB
646 Hdr.h_magic = MAGIC;
647 Hdr.h_namesize = strlen(Hdr.h_name) + 1;
648 Hdr.h_uid = Statb.st_uid;
649 Hdr.h_gid = Statb.st_gid;
650 Hdr.h_dev = Statb.st_dev;
651 Hdr.h_ino = Statb.st_ino;
652 Hdr.h_mode = Statb.st_mode;
653 MKSHORT(Hdr.h_mtime, Statb.st_mtime);
654 Hdr.h_nlink = Statb.st_nlink;
fd2d2fec
KB
655 tlong = ((Hdr.h_mode&S_IFMT) == S_IFREG ||
656 (Hdr.h_mode&S_IFMT) == S_IFLNK)? Statb.st_size: 0L;
76bbb78b
KB
657 MKSHORT(Hdr.h_filesize, tlong);
658 Hdr.h_rdev = Statb.st_rdev;
659 if( Cflag )
660 bintochar(tlong);
661 return 1;
662 }
663}
664
665static
666bintochar(t) /* ASCII header write */
667long t;
668{
669 sprintf(Chdr,"%.6o%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.11lo%.6ho%.11lo%s",
670 MAGIC, MK_USHORT(Statb.st_dev), MK_USHORT(Statb.st_ino), Statb.st_mode, Statb.st_uid,
671 Statb.st_gid, Statb.st_nlink, MK_USHORT(Statb.st_rdev),
672 Statb.st_mtime, (short)strlen(Hdr.h_name)+1, t, Hdr.h_name);
673}
674
675static
676chartobin() /* ASCII header read */
677{
678 sscanf(Chdr, "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6ho%11lo",
679 &Hdr.h_magic, &Hdr.h_dev, &Hdr.h_ino, &Hdr.h_mode, &Hdr.h_uid,
680 &Hdr.h_gid, &Hdr.h_nlink, &Hdr.h_rdev, &Longtime,
681 &Hdr.h_namesize, &Longfile);
682 MKSHORT(Hdr.h_filesize, Longfile);
683 MKSHORT(Hdr.h_mtime, Longtime);
684}
685
686
687/* Check the header for the magic number. Switch modes automatically to
688 match the type of header found.
689*/
690static
691chkhdr()
692{
693 bread(Chdr, CHARS);
694 chartobin();
695 if( Hdr.h_magic == MAGIC )
696 Cflag = 1;
697 else {
698 breread(&Hdr.h_magic, sizeof Hdr.h_magic);
fd2d2fec 699 if( Hdr.h_magic == MAGIC || Hdr.h_magic == (short)BSMAGIC )
76bbb78b 700 Cflag = 0;
fd2d2fec
KB
701 else {
702 fperr("This is not a cpio file. Bad magic number.");
703 exit(2);
704 }
76bbb78b
KB
705 }
706 breread(Chdr, 0);
707}
708
709
710static
711gethdr() /* get file headers */
712{
713 register ushort ftype;
714
715 if (Cflag) {
716 bread(Chdr, CHARS);
717 chartobin();
718 }
719 else
720 bread(&Hdr, HDRSIZE);
721
fd2d2fec
KB
722 if(Hdr.h_magic == (short)BSMAGIC)
723 swap((char *)&Hdr, HDRSIZE, 1, 0);
724 else if( Hdr.h_magic != MAGIC ) {
725 fperr("Out of phase--get help");
726 exit(2);
76bbb78b
KB
727 }
728 bread(Hdr.h_name, Hdr.h_namesize);
729 if(EQ(Hdr.h_name, "TRAILER!!!"))
730 return 0;
731 ftype = Hdr.h_mode & Filetype;
732 A_directory = (ftype == S_IFDIR);
733 A_special = (ftype == S_IFBLK)
734 || (ftype == S_IFCHR)
735 || (ftype == S_IFIFO);
fd2d2fec 736 A_symlink = (ftype == S_IFLNK);
76bbb78b
KB
737 return 1;
738}
739
740static
741ckname(namep) /* check filenames with patterns given on cmd line */
742register char *namep;
743{
744 char buf[sizeof Hdr.h_name];
745
746 if(fflag ^ !nmatch(namep, Pattern)) {
747 return 0;
748 }
749 if(Rename && !A_directory) { /* rename interactively */
750 fprintf(Wtty, "Rename <%s>\n", namep);
751 fflush(Wtty);
752 fgets(buf, sizeof buf, Rtty);
753 if(feof(Rtty))
754 exit(2);
755 buf[strlen(buf) - 1] = '\0';
756 if(EQ(buf, "")) {
757 strcpy(namep,buf);
758 printf("Skipped\n");
759 return 0;
760 }
761 else if(EQ(buf, "."))
762 printf("Same name\n");
763 else
764 strcpy(namep,buf);
765 }
766 return 1;
767}
768
769static
fd2d2fec 770openout(namep, symlname) /* open files for writing, set all necessary info */
76bbb78b 771register char *namep;
fd2d2fec 772char *symlname;
76bbb78b
KB
773{
774 register f;
775 register char *np;
776 int ans;
777
778 if(!strncmp(namep, "./", 2))
779 namep += 2;
780 np = namep;
781 if(A_directory) {
782 if( !Dir || Rename || EQ(namep, ".") || EQ(namep, "..") )
783 /* do not consider . or .. files */
784 return 0;
785 if(stat(namep, &Xstatb) == -1) {
786
787/* try creating (only twice) */
788 ans = 0;
789 do {
fd2d2fec 790 if(mkdir(namep, Hdr.h_mode) != 0) {
76bbb78b
KB
791 ans += 1;
792 }else {
793 ans = 0;
794 break;
795 }
796 }while(ans < 2 && missdir(namep) == 0);
797 if(ans == 1) {
798 fperrno("Cannot create directory for <%s>",
799 namep);
800 return(0);
801 }else if(ans == 2) {
802 fperrno("Cannot create directory <%s>", namep);
803 return(0);
804 }
805 }
806
807ret:
fd2d2fec
KB
808 if(chmod(namep, Hdr.h_mode) < 0)
809 fperrno("Cannot change mode of <%s>", namep);
76bbb78b 810 if(Uid == 0)
fd2d2fec
KB
811 if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
812 fperrno("Cannot change ownership of <%s>",
813 namep);
76bbb78b
KB
814 set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
815 return 0;
816 }
817 if(Hdr.h_nlink > 1)
818 if(!postml(namep, np))
819 return 0;
fd2d2fec 820 if(lstat(namep, &Xstatb) == 0) {
76bbb78b
KB
821 if(Uncond && !((!(Xstatb.st_mode & S_IWRITE) || A_special) && (Uid != 0))) {
822 if(unlink(namep) < 0) {
823 fperrno("cannot unlink current <%s>", namep);
824 }
825 }
826 if(!Uncond && (mklong(Hdr.h_mtime) <= Xstatb.st_mtime)) {
827 /* There's a newer or same aged version of file on destination */
fd2d2fec 828 fperr("current <%s> newer or same age", np);
76bbb78b
KB
829 return 0;
830 }
831 }
832 if( Option == PASS
833 && Hdr.h_ino == Xstatb.st_ino
834 && Hdr.h_dev == Xstatb.st_dev) {
fd2d2fec
KB
835 fperr("Attempt to pass file to self!");
836 exit(2);
837 }
838 if(A_symlink) {
839/* try symlinking (only twice) */
840 ans = 0;
841 do {
842 if(symlink(
843symlname, namep) < 0) {
844 ans += 1;
845 }else {
846 ans = 0;
847 break;
848 }
849 }while(ans < 2 && missdir(np) == 0);
850 if(ans == 1) {
851 fperrno("Cannot create directory for <%s>", namep);
852 return(0);
853 }else if(ans == 2) {
854 fperrno("Cannot symlink <%s> and <%s>", namep, symlname);
855 return(0);
856 }
857
858 return 0;
76bbb78b
KB
859 }
860 if(A_special) {
861 if((Hdr.h_mode & Filetype) == S_IFIFO)
862 Hdr.h_rdev = 0;
863
864/* try creating (only twice) */
865 ans = 0;
866 do {
867 if(mknod(namep, Hdr.h_mode, Hdr.h_rdev) < 0) {
868 ans += 1;
869 }else {
870 ans = 0;
871 break;
872 }
873 }while(ans < 2 && missdir(np) == 0);
874 if(ans == 1) {
875 fperrno("Cannot create directory for <%s>", namep);
876 return(0);
877 }else if(ans == 2) {
878 fperrno("Cannot mknod <%s>", namep);
879 return(0);
880 }
881
882 goto ret;
883 }
884
885/* try creating (only twice) */
886 ans = 0;
887 do {
888 if((f = creat(namep, Hdr.h_mode)) < 0) {
889 ans += 1;
890 }else {
891 ans = 0;
892 break;
893 }
894 }while(ans < 2 && missdir(np) == 0);
895 if(ans == 1) {
896 fperrno("Cannot create directory for <%s>", namep);
897 return(0);
898 }else if(ans == 2) {
899 fperrno("Cannot create <%s>", namep);
900 return(0);
901 }
902
903 if(Uid == 0)
fd2d2fec
KB
904 if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
905 fperrno("Cannot change ownership of <%s>", namep);
76bbb78b
KB
906 return f;
907}
908
909
910/* Shared by bread() and breread()
911*/
912static int nleft = 0; /* unread chars left in Cbuf */
913static char *ip; /* pointer to next char to be read from Cbuf */
914
915/* Reread the current buffer Cbuf.
916 A character count, c, of 0 simply resets the pointer so next bread gets
917 the same data again.
918*/
919static
920breread(b, c)
921char *b;
922int c;
923{
924 ip = Cbuf;
925 if( nleft )
926 nleft = Bufsize;
927 if( !c )
928 return;
929 bread(b, c);
930}
931
932static
933bread(b, c)
934register char *b;
935register int c;
936{
937 register int rv;
938 register char *p = ip;
939
940 if( !Cflag ) {
941 /* round c up to an even number */
942 c = (c+1)/2;
943 c *= 2;
944 }
945 while( c ) {
946 if( nleft == 0 ) {
947 while( (rv = read(Input, Cbuf, Bufsize)) == 0 ) {
948 Input = chgreel(0, Input, rv);
949 }
950 if( rv == Bufsize ) {
951 nleft = Bufsize;
952 p = Cbuf;
953 ++Blocks;
954 }
fd2d2fec
KB
955 else if( rv == -1 ) {
956 fperrno("Read error on archive");
957 exit(2);
958 }
76bbb78b
KB
959 else if( rv < Bufsize ) { /* short read */
960 smemcpy( &Cbuf[ Bufsize - rv ], Cbuf, rv );
961 nleft = rv;
962 p = &Cbuf[ Bufsize - rv ];
963 sBlocks += rv;
964 }
76bbb78b
KB
965 }
966 if( nleft <= c ) {
967 memcpy( b, p, nleft );
968 c -= nleft;
969 b += nleft;
970 p += nleft;
971 nleft = 0;
972 }
973 else {
974 memcpy( b, p, c );
975 nleft -= c;
976 b += c;
977 p += c;
978 c = 0;
979 }
980 }
981 ip = p;
982}
983
984
985static
986bwrite(rp, c)
987register char *rp;
988register c;
989{
990 register char *cp = Cp;
991 static unsigned Ccnt = 0;
992 register unsigned Cleft;
993 register int rv;
994
995 if( !Cflag ) {
996 /* round c up to an even number */
997 c = (c+1)/2;
998 c *= 2;
999 }
1000 while( c ) {
1001 if( (Cleft = Bufsize - Ccnt) <= c ) {
1002 memcpy( cp, rp, Cleft );
1003 rv = write(Output, Cbuf, Bufsize);
1004 if( rv == 0 || ( rv == -1 && errno == ENXIO ) ) {
1005 rv = eomchgreel();
1006 }
1007 if( rv == Bufsize ) {
1008 Ccnt = 0;
1009 cp = Cbuf;
1010 }
fd2d2fec
KB
1011 else if( rv == -1 ) {
1012 fperrno("Write error on archive");
1013 exit(2);
1014 }
76bbb78b
KB
1015 else if( rv < Bufsize ) {
1016 Output = chgreel(1, Output, 0);
1017 smemcpy( Cbuf, &Cbuf[ Bufsize - rv ], rv );
1018 Ccnt = Bufsize - rv;
1019 cp = &Cbuf[ rv ];
1020 }
76bbb78b
KB
1021 ++Blocks;
1022 rp += Cleft;
1023 c -= Cleft;
1024 }
1025 else {
1026 memcpy( cp, rp, c );
1027 Ccnt += c;
1028 cp += c;
1029 rp += c;
1030 c = 0;
1031 }
1032 }
1033 Cp = cp;
1034}
1035
1036
1037static int reelcount = 1; /* used below and in chgreel() */
1038
1039/* Change reel due to reaching end-of-media.
1040 Keep trying to get a successful write before considering the
1041 change-of-reel as successful.
1042*/
1043static
1044int
1045eomchgreel()
1046{
1047 int rv;
1048
1049 while( 1 ) {
1050 Output = chgreel(1, Output, 0);
1051 rv = write(Output, Cbuf, Bufsize);
1052 if( rv == Bufsize )
1053 return rv;
fd2d2fec
KB
1054 if( rv == -1 )
1055 fperrno( "Unable to write this medium" );
1056 else
1057 fperr( "Unable to write this medium: Premature EOF" );
1058 (void) fprintf(stderr, "Try again.\n");
76bbb78b
KB
1059 reelcount--;
1060 }
1061 /*NOTREACHED*/
1062}
1063
1064
1065static
1066postml(namep, np) /* linking funtion: Postml() is called after */
1067register char *namep, *np; /* namep is created. Postml() checks to see */
1068{ /* if namep should be linked to np. If so, */
1069 /* postml() removes the independent instance */
1070 register i; /* of namep and links namep to np. */
1071 static struct ml {
1072 short m_dev;
1073 ushort m_ino;
1074 char m_name[2];
1075 } **ml = 0;
1076 register struct ml *mlp;
1077 static unsigned mlsize = 0;
1078 static unsigned mlinks = 0;
1079 char *lnamep;
1080 int ans;
1081
1082 if( !ml ) {
1083 mlsize = LINKS;
fd2d2fec 1084 ml = (struct ml **) malloc(mlsize * sizeof(struct ml));
76bbb78b
KB
1085 }
1086 else if( mlinks == mlsize ) {
1087 mlsize += LINKS;
fd2d2fec
KB
1088 ml = (struct ml **) realloc((char *) ml,
1089 mlsize * sizeof(struct ml));
1090 }
1091 if (ml == NULL) {
1092 fperr("Out of memory for links");
1093 exit(2);
76bbb78b
KB
1094 }
1095 for(i = 0; i < mlinks; ++i) {
1096 mlp = ml[i];
1097 if(mlp->m_ino==Hdr.h_ino && mlp->m_dev==Hdr.h_dev) {
76bbb78b 1098 if(Verbose)
fd2d2fec
KB
1099 printf("%s linked to %s\n", ml[i]->m_name,
1100 np);
76bbb78b
KB
1101 unlink(namep);
1102 if(Option == IN && *(mlp->m_name) != '/') {
1103 Fullname[Pathend] = '\0';
1104 strcat(Fullname, mlp->m_name);
1105 lnamep = Fullname;
1106 }
1107 lnamep = mlp->m_name;
1108
1109/* try linking (only twice) */
1110 ans = 0;
1111 do {
1112 if(link(lnamep, namep) < 0) {
1113 ans += 1;
1114 }else {
1115 ans = 0;
1116 break;
1117 }
1118 }while(ans < 2 && missdir(np) == 0);
1119 if(ans == 1) {
1120 fperrno("Cannot create directory for <%s>", np);
1121 return(0);
1122 }else if(ans == 2) {
1123 fperrno("Cannot link <%s> & <%s>", lnamep, np);
1124 return(0);
1125 }
1126
1127 set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
1128 return 0;
1129 }
1130 }
fd2d2fec 1131 if( !(ml[mlinks] = (struct ml *)malloc(strlen(np) + 2 + sizeof(struct ml)))) {
76bbb78b
KB
1132 static int first=1;
1133
1134 if(first)
fd2d2fec 1135 fperr("Out of memory for links");
76bbb78b
KB
1136 first = 0;
1137 return 1;
1138 }
1139 ml[mlinks]->m_dev = Hdr.h_dev;
1140 ml[mlinks]->m_ino = Hdr.h_ino;
1141 strcpy(ml[mlinks]->m_name, np);
1142 ++mlinks;
1143 return 1;
1144}
1145
1146static
1147pentry(namep) /* print verbose table of contents */
1148register char *namep;
1149{
76bbb78b 1150 static short lastid = -1;
76bbb78b 1151 static struct passwd *pw;
76bbb78b
KB
1152 static char tbuf[32];
1153 char *ctime();
1154
1155 printf("%-7o", MK_USHORT(Hdr.h_mode));
1156 if(lastid == Hdr.h_uid)
1157 printf("%-6s", pw->pw_name);
1158 else {
1159 setpwent();
1160 if(pw = getpwuid((int)Hdr.h_uid)) {
1161 printf("%-6s", pw->pw_name);
1162 lastid = Hdr.h_uid;
1163 } else {
1164 printf("%-6d", Hdr.h_uid);
1165 lastid = -1;
1166 }
1167 }
1168 printf("%7ld ", mklong(Hdr.h_filesize));
1169 U.l = mklong(Hdr.h_mtime);
1170 strcpy(tbuf, ctime((long *)&U.l));
1171 tbuf[24] = '\0';
fd2d2fec
KB
1172 printf(" %s %s", &tbuf[4], namep);
1173 if (A_symlink)
1174 printf(" -> %s", Symlbuf);
1175 putchar('\n');
76bbb78b
KB
1176}
1177
1178 /* pattern matching functions */
1179static
1180nmatch(s, pat)
1181char *s, **pat;
1182{
1183 if( !pat )
1184 return 1;
1185 while(*pat) {
1186 if((**pat == '!' && !gmatch(s, *pat+1))
1187 || gmatch(s, *pat))
1188 return 1;
1189 ++pat;
1190 }
1191 return 0;
1192}
1193
1194
1195static
1196gmatch(s, p)
1197register char *s, *p;
1198{
1199 register int c;
1200 register cc, ok, lc, scc;
1201
1202 scc = *s;
1203 lc = 077777;
1204 switch (c = *p) {
1205
1206 case '[':
1207 ok = 0;
1208 while (cc = *++p) {
1209 switch (cc) {
1210
1211 case ']':
1212 if (ok)
1213 return(gmatch(++s, ++p));
1214 else
1215 return(0);
1216
1217 case '-':
1218 ok |= ((lc <= scc) && (scc <= (cc=p[1])));
1219 }
1220 if (scc==(lc=cc)) ok++;
1221 }
1222 return(0);
1223
1224 case '?':
1225 caseq:
1226 if(scc) return(gmatch(++s, ++p));
1227 return(0);
1228 case '*':
1229 return(umatch(s, ++p));
1230 case 0:
1231 return(!scc);
1232 }
1233 if (c==scc) goto caseq;
1234 return(0);
1235}
1236
1237
1238
1239static
1240umatch(s, p)
1241register char *s, *p;
1242{
1243 if(*p==0) return(1);
1244 while(*s)
1245 if (gmatch(s++,p)) return(1);
1246 return(0);
1247}
1248
fd2d2fec
KB
1249swap(buf, bytecount, bytes, halfwords) /* swap halfwords, bytes or both */
1250char *buf;
1251int bytecount;
1252int bytes, halfwords;
76bbb78b 1253{
fd2d2fec
KB
1254 register int count;
1255 int n, i;
1256
1257 if(bytes) {
1258 register union swpbytes {
1259 short shortw;
1260 char charv[2];
1261 } *pbuf;
1262 register char c;
1263
1264 count = bytecount;
1265 pbuf = (union swpbytes *)buf;
1266 if (count % sizeof(union swpbytes))
1267 pbuf->charv[count] = 0;
1268 count = (count + (sizeof(union swpbytes) - 1)) / sizeof(union swpbytes);
1269 while (count--) {
1270 c = pbuf->charv[0];
1271 pbuf->charv[0] = pbuf->charv[1];
1272 pbuf->charv[1] = c;
1273 ++pbuf;
76bbb78b
KB
1274 }
1275 }
fd2d2fec
KB
1276 if (halfwords) {
1277 register union swphalf {
1278 long longw;
1279 short shortv[2];
1280 char charv[4];
1281 } *pbuf;
1282 register short cc;
1283
1284 count = bytecount;
1285 pbuf = (union swphalf *)buf;
1286 if (n = count % sizeof(union swphalf))
1287 if(bytes && n % 2)
1288 for(i = count + 1; i <= count + (sizeof(union swphalf) - n); i++)
1289 pbuf->charv[i] = 0;
1290 else
1291 for (i = count; i < count + (sizeof(union swphalf) - n); i++)
1292 pbuf->charv[i] = 0;
1293 count = (count + (sizeof(union swphalf) - 1)) / sizeof(union swphalf);
1294 while (count--) {
76bbb78b
KB
1295 cc = pbuf->shortv[0];
1296 pbuf->shortv[0] = pbuf->shortv[1];
1297 pbuf->shortv[1] = cc;
1298 ++pbuf;
1299 }
1300 }
1301}
1302
1303
1304static
1305set_time(namep, atime, mtime) /* set access and modification times */
1306register char *namep;
1307time_t atime, mtime;
1308{
fd2d2fec 1309 static struct utimbuf timevec;
76bbb78b
KB
1310
1311 if(!Mod_time)
1312 return;
fd2d2fec
KB
1313 timevec.actime = atime;
1314 timevec.modtime = mtime;
1315 (void)utime(namep, &timevec);
76bbb78b
KB
1316}
1317
1318
1319
1320static
1321chgreel(x, fl, rv)
e4897c30 1322 int x, fl, rv;
76bbb78b
KB
1323{
1324 register f;
1325 char str[BUFSIZ];
1326 struct stat statb;
1327
1328 fstat(fl, &statb);
1329 if((statb.st_mode&S_IFMT) != S_IFCHR) {
1330 fperrno("Can't %s: ", x? "write output": "read input");
1331 exit(2);
1332 }
1333 if( rv == 0 ||
1334 ( rv == -1 && ( errno == ENOSPC || errno == ENXIO ) ) )
fd2d2fec 1335 fperr( "\007Reached end of medium on %s",
76bbb78b
KB
1336 x? "output":"input" );
1337 else {
1338 fperrno( "\007Encountered an error on %s",
1339 x? "output":"input" );
1340 exit(2);
1341 }
fd2d2fec
KB
1342 if( Rtty == NULL ) {
1343 Rtty = fopen(ttyname, "r");
1344 if( Rtty == NULL ) {
1345 fperrno("Cannot prompt (can't open %s)", ttyname);
1346 exit(2);
1347 }
1348 }
76bbb78b
KB
1349 close(fl);
1350 reelcount++;
1351again:
1352 if( swfile ) {
1353 askagain:
1354 fperr( eommsg, reelcount );
1355 fgets(str, sizeof str, Rtty);
1356 switch( *str ) {
1357 case '\n':
1358 strcpy( str, swfile );
1359 break;
1360 case 'q':
1361 exit(2);
1362 default:
1363 goto askagain;
1364 }
1365 }
1366 else {
fd2d2fec 1367 fperr("If you want to go on, type device/file name when ready.");
76bbb78b
KB
1368 fgets(str, sizeof str, Rtty);
1369 str[strlen(str) - 1] = '\0';
1370 if(!*str)
1371 exit(2);
1372 }
1373 if((f = open(str, x? 1: 0)) < 0) {
fd2d2fec 1374 fperrno("Can't open <%s>", str);
76bbb78b
KB
1375 goto again;
1376 }
1377 return f;
1378}
1379
1380
1381
1382static
1383missdir(namep)
1384register char *namep;
1385{
1386 register char *np;
1387 register ct = 2;
1388
1389 for(np = namep; *np; ++np)
1390 if(*np == '/') {
1391 if(np == namep) continue; /* skip over 'root slash' */
1392 *np = '\0';
1393 if(stat(namep, &Xstatb) == -1) {
1394 if(Dir) {
fd2d2fec 1395 if((ct = mkdir(namep, 0777)) != 0) {
76bbb78b
KB
1396 *np = '/';
1397 return(ct);
1398 }
1399 }else {
fd2d2fec 1400 fperr("missing 'd' option");
76bbb78b
KB
1401 return(-1);
1402 }
1403 }
1404 *np = '/';
1405 }
1406 if (ct == 2) ct = 0; /* the file already exists */
1407 return ct;
1408}
1409
1410
1411
1412static
1413pwd() /* get working directory */
1414{
fd2d2fec
KB
1415 if (getwd(Fullname) == 0) {
1416 (void)fprintf(stderr, "cpio: %s\n",
1417 Fullname);
76bbb78b 1418 exit(2);
76bbb78b 1419 }
fd2d2fec
KB
1420 Pathend = strlen(Fullname);
1421 Fullname[Pathend++] = '/';
1422 Fullname[Pathend] = '\0';
76bbb78b
KB
1423}
1424
1425
1426/*
1427 print message on the stderr
1428*/
1429static
1430fperr( va_alist )
1431va_dcl
1432{
1433 va_list args;
1434 char *fmt;
1435
76bbb78b 1436 va_start( args );
fd2d2fec 1437 fprintf( stderr, "cpio: ");
76bbb78b
KB
1438 fmt = va_arg( args, char * );
1439 vfprintf( stderr, fmt, args );
fd2d2fec 1440 putc( '\n', stderr);
76bbb78b
KB
1441 fflush( stderr );
1442}
1443
1444/*
1445 print message on the stderr followed by error number and meaning.
1446*/
1447static
1448fperrno( va_alist )
1449va_dcl
1450{
1451 va_list args;
1452 char *fmt;
1453
76bbb78b 1454 va_start( args );
fd2d2fec 1455 fprintf( stderr, "cpio: ");
76bbb78b
KB
1456 fmt = va_arg( args, char * );
1457 vfprintf( stderr, fmt, args );
fd2d2fec 1458 fprintf( stderr, ": " );
76bbb78b
KB
1459 fflush( stderr );
1460 perror("");
1461}
1462
1463
fd2d2fec
KB
1464/* Safe memory copy.
1465 Fast if the to and from strings do not overlap,
1466 slower but safe if they do.
1467*/
1468
1469static char *
1470smemcpy( to, from, count )
1471register char *to, *from;
1472register unsigned count;
76bbb78b 1473{
fd2d2fec 1474 char *savedto;
76bbb78b 1475
fd2d2fec
KB
1476 if( &to[ count ] <= from || &from[ count ] <= to )
1477 return memcpy( to, from, count );
76bbb78b 1478
fd2d2fec
KB
1479 if( to == from )
1480 return to;
1481
1482 savedto = to;
1483 if( to < from )
1484 while( count-- )
1485 *(to++) = *(from++);
1486 else {
1487 to += count;
1488 from += count;
1489 while( count-- )
1490 *(--to) = *(--from);
1491 }
1492
1493 return savedto;
76bbb78b 1494}