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