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