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