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