Commit | Line | Data |
---|---|---|
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 KB |
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> | |
fd2d2fec KB |
27 | #include <sys/param.h> |
28 | #include <sys/types.h> | |
76bbb78b KB |
29 | #include <sys/stat.h> |
30 | ||
fd2d2fec KB |
31 | struct utimbuf { |
32 | time_t actime; | |
33 | time_t modtime; | |
34 | }; | |
35 | #ifndef S_IFIFO | |
36 | #define S_IFIFO 010000 | |
37 | #endif | |
38 | ||
76bbb78b KB |
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 */ | |
fd2d2fec | 47 | #define BSMAGIC 0143561 /* byte-swapped cpio magic number */ |
76bbb78b KB |
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 | ||
fd2d2fec | 81 | char Symlbuf[MAXPATHLEN + 1]; /* target of symbolic link */ |
76bbb78b KB |
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, | |
76bbb78b KB |
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, | |
fd2d2fec | 143 | A_symlink, |
76bbb78b KB |
144 | Filetype = S_IFMT; |
145 | ||
146 | extern errno; | |
147 | extern void exit(); | |
76bbb78b KB |
148 | char *malloc(); |
149 | FILE *popen(); | |
150 | ||
fd2d2fec KB |
151 | static char *smemcpy(); |
152 | ||
76bbb78b KB |
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; | |
fd2d2fec | 178 | int symlsz; |
76bbb78b KB |
179 | register char *fullp; |
180 | register i; | |
181 | int ans; | |
fd2d2fec | 182 | register char *symlinkp; |
76bbb78b KB |
183 | short select; /* set when files are selected */ |
184 | extern char *optarg; | |
185 | extern int optind; | |
186 | ||
fd2d2fec KB |
187 | signal(SIGSYS, SIG_IGN); |
188 | if(argc <= 1 || *argv[1] != '-') | |
76bbb78b KB |
189 | usage(); |
190 | Uid = getuid(); | |
76bbb78b | 191 | |
fd2d2fec | 192 | while( (ans = getopt( argc, argv, "aBC:ifopcdlmrSsbtuvM:6eI:O:")) != EOF ) { |
76bbb78b KB |
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 ); | |
fd2d2fec KB |
204 | if( Bufsize == 0 ) { |
205 | fperr("Illegal argument to -%c, '%s'", | |
76bbb78b | 206 | ans, optarg ); |
fd2d2fec KB |
207 | exit(2); |
208 | } | |
76bbb78b KB |
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) { | |
fd2d2fec | 239 | fperrno("Cannot rename (%s missing)", |
76bbb78b | 240 | ttyname ); |
fd2d2fec | 241 | exit(2); |
76bbb78b KB |
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 */ | |
fd2d2fec KB |
253 | halfswap++; |
254 | byteswap++; | |
76bbb78b KB |
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 */ | |
fd2d2fec | 264 | Verbose++; |
76bbb78b KB |
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 ); | |
fd2d2fec KB |
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 | } | |
76bbb78b KB |
282 | swfile = optarg; |
283 | break; | |
284 | case 'O': | |
285 | chkswfile( swfile, ans, Option ); | |
fd2d2fec KB |
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 | } | |
76bbb78b KB |
295 | swfile = optarg; |
296 | break; | |
297 | default: | |
298 | usage(); | |
299 | } | |
300 | } | |
301 | if(!Option) { | |
fd2d2fec KB |
302 | (void) fprintf(stderr, |
303 | "Options must include one of -o, -i, or -p\n"); | |
304 | exit(2); | |
76bbb78b KB |
305 | } |
306 | ||
307 | if(Option == PASS) { | |
308 | if(Rename) { | |
fd2d2fec KB |
309 | (void) fprintf(stderr, |
310 | "Pass and Rename cannot be used together\n"); | |
311 | exit(2); | |
76bbb78b KB |
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 { | |
fd2d2fec KB |
319 | Cp = Cbuf = (char *)malloc(Bufsize); |
320 | if(Cp == NULL) { | |
321 | perror("cpio"); | |
322 | exit(2); | |
323 | } | |
76bbb78b KB |
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) | |
fd2d2fec KB |
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); | |
76bbb78b KB |
356 | continue; |
357 | } | |
358 | if((Ifile = open(Hdr.h_name, 0)) < 0) { | |
fd2d2fec | 359 | fperrno("Cannot open <%s>", Hdr.h_name); |
76bbb78b KB |
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) { | |
fd2d2fec | 369 | fperrno("Cannot read %s", Hdr.h_name); |
76bbb78b KB |
370 | continue; |
371 | } | |
372 | bwrite(Buf,ct); | |
373 | } | |
374 | close(Ifile); | |
fd2d2fec KB |
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 | } | |
76bbb78b | 382 | if(Verbose) |
fd2d2fec | 383 | (void) fprintf(stderr, "%s\n", Hdr.h_name); |
76bbb78b KB |
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()) { | |
fd2d2fec KB |
407 | if (A_symlink) { |
408 | symlsz = (int) mklong(Hdr.h_filesize); | |
409 | bread(Symlbuf, symlsz); | |
410 | Symlbuf[symlsz] = '\0'; | |
4dc7a4c9 | 411 | if( ckname(Hdr.h_name) && !Toc) |
fd2d2fec KB |
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 | } | |
76bbb78b KB |
428 | } |
429 | } | |
fd2d2fec KB |
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 | } | |
76bbb78b KB |
437 | } |
438 | if(select) { | |
439 | if(Verbose) | |
440 | if(Toc) | |
441 | pentry(Hdr.h_name); | |
442 | else | |
fd2d2fec | 443 | puts(Hdr.h_name); |
76bbb78b KB |
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) { | |
fd2d2fec KB |
454 | (void) fperrno("Cannot write in <%s>", argv[0]); |
455 | exit(2); | |
76bbb78b KB |
456 | } |
457 | strcpy(Fullname, argv[0]); /* destination directory */ | |
fd2d2fec KB |
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 | } | |
76bbb78b KB |
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) | |
fd2d2fec | 474 | fperr("Use `-d' option to copy <%s>", |
76bbb78b KB |
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) { | |
fd2d2fec KB |
488 | fperrno("Cannot create directory for <%s>", |
489 | Fullname); | |
76bbb78b KB |
490 | continue; |
491 | } | |
492 | break; | |
493 | case EEXIST: | |
494 | if(unlink(Fullname) < 0) { | |
fd2d2fec KB |
495 | fperrno("Cannot unlink <%s>", |
496 | Fullname); | |
76bbb78b KB |
497 | continue; |
498 | } | |
499 | break; | |
500 | default: | |
fd2d2fec KB |
501 | fperrno("Cannot link <%s> to <%s>", |
502 | Hdr.h_name, Fullname); | |
76bbb78b KB |
503 | continue; |
504 | } | |
505 | if(link(Hdr.h_name, Fullname) < 0) { | |
fd2d2fec KB |
506 | fperrno("Cannot link <%s> to <%s>", |
507 | Hdr.h_name, Fullname); | |
76bbb78b KB |
508 | continue; |
509 | } | |
510 | } | |
511 | ||
512 | goto ckverbose; | |
513 | } | |
fd2d2fec KB |
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))) | |
76bbb78b | 530 | continue; |
fd2d2fec KB |
531 | if((Ifile = open(Hdr.h_name, 0)) < 0) { |
532 | fperrno("Cannot open <%s>", Hdr.h_name); | |
76bbb78b KB |
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) { | |
fd2d2fec | 540 | fperrno("Cannot read %s", Hdr.h_name); |
76bbb78b KB |
541 | break; |
542 | } | |
fd2d2fec KB |
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. */ | |
76bbb78b KB |
549 | |
550 | Blocks += ((ct + (BUFSIZE - 1)) / BUFSIZE); | |
551 | } | |
552 | close(Ifile); | |
fd2d2fec KB |
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 | } | |
76bbb78b KB |
560 | if(Ofile) { |
561 | close(Ofile); | |
fd2d2fec KB |
562 | if(chmod(Fullname, Hdr.h_mode) < 0) |
563 | fperrno("Cannot change mode of <%s>", | |
564 | Fullname); | |
76bbb78b KB |
565 | set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime)); |
566 | ckverbose: | |
567 | if(Verbose) | |
fd2d2fec | 568 | puts(Fullname); |
76bbb78b KB |
569 | } |
570 | } | |
571 | } | |
572 | /* print number of blocks actually copied */ | |
573 | Blocks += ((sBlocks + (BUFSIZE - 1)) / BUFSIZE); | |
fd2d2fec | 574 | (void) fprintf(stderr, "%ld blocks\n", Blocks * (Bufsize>>9)); |
76bbb78b KB |
575 | exit(0); |
576 | } | |
577 | ||
578 | static | |
579 | usage() | |
580 | { | |
fd2d2fec KB |
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"); | |
76bbb78b KB |
587 | } |
588 | ||
589 | static | |
590 | chkswfile( sp, c, option ) | |
591 | char *sp; | |
592 | char c; | |
593 | short option; | |
594 | { | |
fd2d2fec KB |
595 | if( !option ) { |
596 | fperr( "-%c must be specified before -%c option", | |
76bbb78b | 597 | c == 'I' ? 'i' : 'o', c ); |
fd2d2fec KB |
598 | exit(2); |
599 | } | |
600 | if( (c == 'I' && option != IN) || (c == 'O' && option != OUT) ) { | |
601 | fperr( "-%c option not permitted with -%c option", c, | |
76bbb78b | 602 | option ); |
fd2d2fec KB |
603 | exit(2); |
604 | } | |
76bbb78b KB |
605 | if( !sp ) |
606 | return; | |
fd2d2fec KB |
607 | fperr("No more than one -I or -O flag permitted"); |
608 | exit(2); | |
76bbb78b KB |
609 | } |
610 | ||
611 | static | |
612 | getname() /* get file name, get info for header */ | |
613 | { | |
614 | register char *namep = Name; | |
615 | register ushort ftype; | |
fd2d2fec | 616 | struct stat Lstatb; |
76bbb78b KB |
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); | |
fd2d2fec KB |
627 | if(lstat(namep, &Statb) < 0) { |
628 | fperrno("Cannot stat <%s>", Hdr.h_name); | |
76bbb78b KB |
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); | |
fd2d2fec | 636 | A_symlink = (ftype == S_IFLNK); |
76bbb78b KB |
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; | |
fd2d2fec KB |
646 | tlong = ((Hdr.h_mode&S_IFMT) == S_IFREG || |
647 | (Hdr.h_mode&S_IFMT) == S_IFLNK)? Statb.st_size: 0L; | |
76bbb78b KB |
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); | |
fd2d2fec | 690 | if( Hdr.h_magic == MAGIC || Hdr.h_magic == (short)BSMAGIC ) |
76bbb78b | 691 | Cflag = 0; |
fd2d2fec KB |
692 | else { |
693 | fperr("This is not a cpio file. Bad magic number."); | |
694 | exit(2); | |
695 | } | |
76bbb78b KB |
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 | ||
fd2d2fec KB |
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); | |
76bbb78b KB |
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); | |
fd2d2fec | 727 | A_symlink = (ftype == S_IFLNK); |
76bbb78b KB |
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 | |
fd2d2fec | 761 | openout(namep, symlname) /* open files for writing, set all necessary info */ |
76bbb78b | 762 | register char *namep; |
fd2d2fec | 763 | char *symlname; |
76bbb78b KB |
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 { | |
fd2d2fec | 781 | if(mkdir(namep, Hdr.h_mode) != 0) { |
76bbb78b KB |
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: | |
fd2d2fec KB |
799 | if(chmod(namep, Hdr.h_mode) < 0) |
800 | fperrno("Cannot change mode of <%s>", namep); | |
76bbb78b | 801 | if(Uid == 0) |
fd2d2fec KB |
802 | if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0) |
803 | fperrno("Cannot change ownership of <%s>", | |
804 | namep); | |
76bbb78b KB |
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; | |
fd2d2fec | 811 | if(lstat(namep, &Xstatb) == 0) { |
76bbb78b KB |
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 */ | |
fd2d2fec | 819 | fperr("current <%s> newer or same age", np); |
76bbb78b KB |
820 | return 0; |
821 | } | |
822 | } | |
823 | if( Option == PASS | |
824 | && Hdr.h_ino == Xstatb.st_ino | |
825 | && Hdr.h_dev == Xstatb.st_dev) { | |
fd2d2fec KB |
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; | |
76bbb78b KB |
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) | |
fd2d2fec KB |
895 | if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0) |
896 | fperrno("Cannot change ownership of <%s>", namep); | |
76bbb78b KB |
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 | } | |
fd2d2fec KB |
946 | else if( rv == -1 ) { |
947 | fperrno("Read error on archive"); | |
948 | exit(2); | |
949 | } | |
76bbb78b KB |
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 | } | |
76bbb78b KB |
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 | } | |
fd2d2fec KB |
1002 | else if( rv == -1 ) { |
1003 | fperrno("Write error on archive"); | |
1004 | exit(2); | |
1005 | } | |
76bbb78b KB |
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 | } | |
76bbb78b KB |
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; | |
fd2d2fec KB |
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"); | |
76bbb78b KB |
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; | |
fd2d2fec | 1075 | ml = (struct ml **) malloc(mlsize * sizeof(struct ml)); |
76bbb78b KB |
1076 | } |
1077 | else if( mlinks == mlsize ) { | |
1078 | mlsize += LINKS; | |
fd2d2fec KB |
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); | |
76bbb78b KB |
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) { | |
76bbb78b | 1089 | if(Verbose) |
fd2d2fec KB |
1090 | printf("%s linked to %s\n", ml[i]->m_name, |
1091 | np); | |
76bbb78b KB |
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 | } | |
fd2d2fec | 1122 | if( !(ml[mlinks] = (struct ml *)malloc(strlen(np) + 2 + sizeof(struct ml)))) { |
76bbb78b KB |
1123 | static int first=1; |
1124 | ||
1125 | if(first) | |
fd2d2fec | 1126 | fperr("Out of memory for links"); |
76bbb78b KB |
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'; | |
fd2d2fec KB |
1166 | printf(" %s %s", &tbuf[4], namep); |
1167 | if (A_symlink) | |
1168 | printf(" -> %s", Symlbuf); | |
1169 | putchar('\n'); | |
76bbb78b KB |
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 | ||
fd2d2fec KB |
1243 | swap(buf, bytecount, bytes, halfwords) /* swap halfwords, bytes or both */ |
1244 | char *buf; | |
1245 | int bytecount; | |
1246 | int bytes, halfwords; | |
76bbb78b | 1247 | { |
fd2d2fec KB |
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; | |
76bbb78b KB |
1268 | } |
1269 | } | |
fd2d2fec KB |
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--) { | |
76bbb78b KB |
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 | { | |
fd2d2fec | 1303 | static struct utimbuf timevec; |
76bbb78b KB |
1304 | |
1305 | if(!Mod_time) | |
1306 | return; | |
fd2d2fec KB |
1307 | timevec.actime = atime; |
1308 | timevec.modtime = mtime; | |
1309 | (void)utime(namep, &timevec); | |
76bbb78b KB |
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 ) ) ) | |
fd2d2fec | 1328 | fperr( "\007Reached end of medium on %s", |
76bbb78b KB |
1329 | x? "output":"input" ); |
1330 | else { | |
1331 | fperrno( "\007Encountered an error on %s", | |
1332 | x? "output":"input" ); | |
1333 | exit(2); | |
1334 | } | |
fd2d2fec KB |
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 | } | |
76bbb78b KB |
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 { | |
fd2d2fec | 1360 | fperr("If you want to go on, type device/file name when ready."); |
76bbb78b KB |
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) { | |
fd2d2fec | 1367 | fperrno("Can't open <%s>", str); |
76bbb78b KB |
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) { | |
fd2d2fec | 1388 | if((ct = mkdir(namep, 0777)) != 0) { |
76bbb78b KB |
1389 | *np = '/'; |
1390 | return(ct); | |
1391 | } | |
1392 | }else { | |
fd2d2fec | 1393 | fperr("missing 'd' option"); |
76bbb78b KB |
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 | { | |
fd2d2fec KB |
1408 | if (getwd(Fullname) == 0) { |
1409 | (void)fprintf(stderr, "cpio: %s\n", | |
1410 | Fullname); | |
76bbb78b | 1411 | exit(2); |
76bbb78b | 1412 | } |
fd2d2fec KB |
1413 | Pathend = strlen(Fullname); |
1414 | Fullname[Pathend++] = '/'; | |
1415 | Fullname[Pathend] = '\0'; | |
76bbb78b KB |
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 | ||
76bbb78b | 1429 | va_start( args ); |
fd2d2fec | 1430 | fprintf( stderr, "cpio: "); |
76bbb78b KB |
1431 | fmt = va_arg( args, char * ); |
1432 | vfprintf( stderr, fmt, args ); | |
fd2d2fec | 1433 | putc( '\n', stderr); |
76bbb78b KB |
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 | ||
76bbb78b | 1447 | va_start( args ); |
fd2d2fec | 1448 | fprintf( stderr, "cpio: "); |
76bbb78b KB |
1449 | fmt = va_arg( args, char * ); |
1450 | vfprintf( stderr, fmt, args ); | |
fd2d2fec | 1451 | fprintf( stderr, ": " ); |
76bbb78b KB |
1452 | fflush( stderr ); |
1453 | perror(""); | |
1454 | } | |
1455 | ||
1456 | ||
fd2d2fec KB |
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; | |
76bbb78b | 1466 | { |
fd2d2fec | 1467 | char *savedto; |
76bbb78b | 1468 | |
fd2d2fec KB |
1469 | if( &to[ count ] <= from || &from[ count ] <= to ) |
1470 | return memcpy( to, from, count ); | |
76bbb78b | 1471 | |
fd2d2fec KB |
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; | |
76bbb78b | 1487 | } |