1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1987-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Glenn Fowler
23 * AT&T Bell Laboratories
24 *
25 * pax file support
26 */
27
28 #include "pax.h"
29
30 #include <tm.h>
31
32 /*
33 * "nocomment" is a hardwired "nocom"
34 * should be an sfio discipline
35 */
36
37 #include "nocomment.c"
38
39 #if __STDC__
40 #define chmod(a,b) (error(-1,"%s#%d: chmod(%s,%05o)",__FILE__,__LINE__,a,b),chmod(a,b))
41 #endif
42
43 /*
44 * return read file descriptor for filtered current input file
45 */
46
47 int
apply(register Archive_t * ap,register File_t * f,Filter_t * fp)48 apply(register Archive_t* ap, register File_t* f, Filter_t* fp)
49 {
50 register int n;
51 char* arg;
52 int rfd;
53 int wfd;
54
55 if (state.filter.line <= 0)
56 arg = f->path;
57 else if (!*(arg = state.filter.command))
58 {
59 if ((rfd = open(f->st->st_size ? f->path : "/dev/null", O_RDONLY|O_BINARY)) < 0)
60 error(ERROR_SYSTEM|2, "%s: cannot read", f->path);
61 return rfd;
62 }
63 message((-4, "filter: %s %s", fp->command, f->path));
64 if ((wfd = open(state.tmp.file, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR)) < 0)
65 {
66 error(2, "%s: cannot create filter temporary %s", f->path, state.tmp.file);
67 return -1;
68 }
69 if ((rfd = open(state.tmp.file, O_RDONLY|O_BINARY)) < 0)
70 {
71 error(2, "%s: cannot open filter temporary %s", f->path, state.tmp.file);
72 close(wfd);
73 if (remove(state.tmp.file))
74 error(1, "%s: cannot remove filter temporary %s", f->path, state.tmp.file);
75 return -1;
76 }
77 if (remove(state.tmp.file))
78 error(1, "%s: cannot remove filter temporary %s", f->path, state.tmp.file);
79 if (ap->format->checksum)
80 f->checksum = 0;
81 f->st->st_size = 0;
82 if (streq(*fp->argv, "nocomment"))
83 {
84 int errors = error_info.errors;
85 off_t count;
86 Sfio_t* ip;
87 Sfio_t* op;
88
89 if ((ip = sfopen(NiL, f->path, "r")) && (op = sfnew(NiL, NiL, SF_UNBOUND, wfd, SF_WRITE)) && (count = nocomment(ip, op)) < 0)
90 error(2, "%s: %s: filter error", f->path, *fp->argv);
91 if (ip)
92 {
93 sfclose(ip);
94 if (op)
95 sfclose(op);
96 else
97 error(2, "%s: cannot redirect filter", f->path);
98 }
99 else
100 error(2, "%s: cannot read", f->path);
101 if (errors != error_info.errors)
102 {
103 close(rfd);
104 close(wfd);
105 return -1;
106 }
107 f->st->st_size = count;
108 }
109 else
110 {
111 Proc_t* proc;
112
113 *fp->patharg = arg;
114 if (!(proc = procopen(*fp->argv, fp->argv, NiL, NiL, PROC_READ)))
115 {
116 error(2, "%s: cannot execute filter %s", f->path, *fp->argv);
117 close(rfd);
118 close(wfd);
119 return -1;
120 }
121 holeinit(wfd);
122 while ((n = read(proc->rfd, state.tmp.buffer, state.buffersize)) > 0)
123 {
124 if (holewrite(wfd, state.tmp.buffer, n) != n)
125 {
126 error(2, "%s: filter write error", f->path);
127 break;
128 }
129 if (ap->format->checksum)
130 f->checksum = (*ap->format->checksum)(&state, ap, f, state.tmp.buffer, n, f->checksum);
131 f->st->st_size += n;
132 }
133 holedone(wfd);
134 if (n < 0)
135 error(ERROR_SYSTEM|2, "%s: %s filter read error", f->path, *fp->argv);
136 if (n = procclose(proc))
137 error(2, "%s: %s filter exit code %d", f->path, *fp->argv, n);
138 }
139 close(wfd);
140 message((-1, "%s: filter file size = %ld", f->path, f->st->st_size));
141 return rfd;
142 }
143
144 /*
145 * return read file descriptor for current input file
146 */
147
148 int
openin(register Archive_t * ap,register File_t * f)149 openin(register Archive_t* ap, register File_t* f)
150 {
151 register int n;
152 Filter_t* fp;
153 int rfd;
154
155 if (f->type != X_IFREG)
156 rfd = -1;
157 else if (fp = filter(ap, f))
158 rfd = apply(ap, f, fp);
159 else if ((rfd = open(f->st->st_size ? f->path : "/dev/null", O_RDONLY|O_BINARY)) < 0)
160 error(ERROR_SYSTEM|2, "%s: cannot read", f->path);
161 else if (ap->format->checksum)
162 {
163 f->checksum = 0;
164 if (lseek(rfd, (off_t)0, SEEK_SET) != 0)
165 error(ERROR_SYSTEM|1, "%s: %s checksum seek error", f->path, ap->format->name);
166 else
167 {
168 while ((n = read(rfd, state.tmp.buffer, state.buffersize)) > 0)
169 f->checksum = (*ap->format->checksum)(&state, ap, f, state.tmp.buffer, n, f->checksum);
170 if (n < 0)
171 error(ERROR_SYSTEM|2, "%s: %s checksum read error", f->path, ap->format->name);
172 if (lseek(rfd, (off_t)0, SEEK_SET) != 0)
173 error(ERROR_SYSTEM|1, "%s: %s checksum seek error", f->path, ap->format->name);
174 }
175 }
176 if (rfd < 0)
177 f->st->st_size = 0;
178 return rfd;
179 }
180
181 /*
182 * create directory and all path name components leading to directory
183 */
184
185 static int
missdir(register Archive_t * ap,register File_t * f)186 missdir(register Archive_t* ap, register File_t* f)
187 {
188 register char* s;
189 register char* t;
190 long pp;
191 struct stat* st;
192 struct stat* sp;
193 struct stat st0;
194 struct stat st1;
195
196 s = f->name;
197 pathcanon(s, 0, 0);
198 if (t = strchr(*s == '/' ? s + 1 : s, '/'))
199 {
200 if (!state.mkdir)
201 {
202 if (!state.warnmkdir)
203 {
204 state.warnmkdir = 1;
205 error(1, "omit the --nomkdir option to create intermediate directories");
206 }
207 return -1;
208 }
209 st = 0;
210 sp = &st0;
211 do
212 {
213 *t = 0;
214 if (stat(s, sp))
215 {
216 *t = '/';
217 break;
218 }
219 *t = '/';
220 st = sp;
221 sp = (sp == &st0) ? &st1 : &st0;
222 } while (t = strchr(t + 1, '/'));
223 if (t)
224 {
225 if (!st && stat(".", st = &st0))
226 error(ERROR_SYSTEM|3, "%s: cannot stat .", s);
227 pp = f->perm;
228 f->perm = st->st_mode & state.modemask;
229 sp = f->st;
230 f->st = st;
231 do
232 {
233 *t = 0;
234 if (mkdir(s, f->perm))
235 {
236 error(ERROR_SYSTEM|2, "%s: cannot create directory", s);
237 *t = '/';
238 f->perm = pp;
239 f->st = sp;
240 return -1;
241 }
242 setfile(ap, f);
243 *t = '/';
244 } while (t = strchr(t + 1, '/'));
245 f->perm = pp;
246 f->st = sp;
247 }
248 }
249 return 0;
250 }
251
252 /*
253 * open file for writing, set all necessary info
254 */
255
256 int
openout(register Archive_t * ap,register File_t * f)257 openout(register Archive_t* ap, register File_t* f)
258 {
259 register int fd;
260 int exists;
261 int perm;
262 int c;
263 Tv_t t1;
264 Tv_t t2;
265 size_t updated;
266 struct stat st;
267
268 pathcanon(f->name, 0, 0);
269
270 /*
271 * if not found and state.update then check down the view
272 *
273 * NOTE: VPATH in app code is ugly but the benefits of the
274 * combination with state.update win over beauty
275 */
276
277 if (f->ro)
278 {
279 f->name = "PAX-INTERNAL-ERROR";
280 f->skip = 1;
281 exists = 0;
282 }
283 else if (exists = !(*state.statf)(f->name, &st))
284 {
285 if (!state.clobber && !S_ISDIR(st.st_mode))
286 {
287 error(1, "%s: already exists -- not overwritten", f->name);
288 return -1;
289 }
290 f->chmod = f->perm != (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) &&
291 (state.chmod || state.update || S_ISDIR(st.st_mode));
292 st.st_mode = modex(st.st_mode);
293 }
294 else
295 {
296 typedef struct View
297 {
298 struct View* next;
299 char* root;
300 dev_t dev;
301 ino_t ino;
302 } View_t;
303
304 View_t* vp;
305 View_t* tp;
306 char* s;
307 char* e;
308
309 static View_t* view;
310 static char* offset;
311
312 if (state.update && !offset)
313 {
314 if (s = getenv("VPATH"))
315 {
316 if (!(s = strdup(s)))
317 nospace();
318 do
319 {
320 if (e = strchr(s, ':'))
321 *e++ = 0;
322 if (!(vp = newof(0, View_t, 1, 0)))
323 nospace();
324 vp->root = s;
325 if (stat(s, &st))
326 {
327 vp->dev = 0;
328 vp->ino = 0;
329 }
330 else
331 {
332 vp->dev = st.st_dev;
333 vp->ino = st.st_ino;
334 }
335 if (view)
336 tp = tp->next = vp;
337 else
338 view = tp = vp;
339 } while (s = e);
340 s = state.pwd;
341 e = 0;
342 for (;;)
343 {
344 if (stat(s, &st))
345 error(ERROR_SYSTEM|3, "%s: cannot stat pwd component", s);
346 for (vp = view; vp; vp = vp->next)
347 if (vp->ino == st.st_ino && vp->dev == st.st_dev)
348 {
349 offset = e ? e + 1 : ".";
350 tp = view;
351 view = vp->next;
352 while (tp && tp != view)
353 {
354 vp = tp;
355 tp = tp->next;
356 free(vp);
357 }
358 if (e)
359 *e = '/';
360 goto found;
361 }
362 if (e)
363 *e = '/';
364 else
365 e = s + strlen(s);
366 while (e > s && *--e != '/');
367 if (e <= s)
368 break;
369 *e = 0;
370 }
371 }
372 found:
373 if (!offset)
374 offset = ".";
375 }
376 st.st_mode = 0;
377 st.st_mtime = 0;
378 if (*f->name != '/')
379 for (vp = view; vp; vp = vp->next)
380 {
381 sfsprintf(state.tmp.buffer, state.tmp.buffersize - 1, "%s/%s/%s", vp->root, offset, f->name);
382 if (!stat(state.tmp.buffer, &st))
383 break;
384 }
385 f->chmod = state.chmod || state.update;
386 }
387 if (f->delta.op == DELTA_delete)
388 {
389 if (exists)
390 switch (X_ITYPE(st.st_mode))
391 {
392 case X_IFDIR:
393 if (!f->ro)
394 {
395 if (rmdir(f->name))
396 error(ERROR_SYSTEM|2, "%s: cannot remove directory", f->name);
397 else
398 listentry(f);
399 }
400 break;
401 default:
402 if (remove(f->name))
403 error(ERROR_SYSTEM|2, "%s: cannot remove file", f->name);
404 else
405 listentry(f);
406 break;
407 }
408 return -1;
409 }
410 if (state.operation == (IN|OUT))
411 {
412 if (exists && f->st->st_ino == st.st_ino && f->st->st_dev == st.st_dev)
413 {
414 error(2, "attempt to pass %s to self", f->name);
415 return -1;
416 }
417 if (state.linkf && f->type != X_IFDIR && (state.linkf == pathsetlink || f->st->st_dev == state.dev))
418 {
419 if (exists)
420 remove(f->name);
421 if ((*state.linkf)(f->path, f->name))
422 {
423 if (!exists && missdir(ap, f))
424 {
425 error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
426 return -1;
427 }
428 if (exists || (*state.linkf)(f->path, f->name))
429 {
430 error(ERROR_SYSTEM|2, "%s: cannot link to %s", f->path, f->name);
431 return -1;
432 }
433 }
434 setfile(ap, f);
435 return -2;
436 }
437 }
438 switch (f->type)
439 {
440 case X_IFDIR:
441 if (!(ap->format->flags & KEEPSIZE))
442 f->st->st_size = 0;
443 if (f->ro)
444 return -1;
445 if (exists && X_ITYPE(st.st_mode) != X_IFDIR)
446 {
447 if (remove(f->name))
448 {
449 error(ERROR_SYSTEM|2, "cannot remove current %s", f->name);
450 return -1;
451 }
452 exists = 0;
453 }
454 if (!exists && mkdir(f->name, f->perm) && (missdir(ap, f) || mkdir(f->name, f->perm)))
455 {
456 error(ERROR_SYSTEM|2, "%s: cannot create directory", f->name);
457 return -1;
458 }
459 updated = ap->updated;
460 setfile(ap, f);
461 if (!exists || f->chmod || state.update && ((c = tvcmp(tvmtime(&t1, f->st), tvmtime(&t2, &st))) > 0 || state.update == OPT_different && c))
462 {
463 listentry(f);
464 fd = -1;
465 }
466 else
467 {
468 ap->updated = updated;
469 if (state.update)
470 fd = -1;
471 else
472 fd = -2;
473 }
474 return fd;
475 case X_IFLNK:
476 if (exists && prune(ap, f, &st))
477 return -1;
478 if (!*f->linkpath)
479 return -2;
480 if (streq(f->name, f->linkpath))
481 {
482 error(1, "%s: symbolic link loops to self", f->name);
483 return -1;
484 }
485 if (exists && remove(f->name))
486 {
487 error(ERROR_SYSTEM|2, "cannot remove current %s", f->name);
488 return -1;
489 }
490 if (pathsetlink(f->linkpath, f->name))
491 {
492 if (!exists && missdir(ap, f))
493 {
494 error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
495 return -1;
496 }
497 if (exists || pathsetlink(f->linkpath, f->name))
498 {
499 error(ERROR_SYSTEM|2, "%s: cannot symlink to %s", f->name, f->linkpath);
500 return -1;
501 }
502 }
503 setfile(ap, f);
504 listentry(f);
505 return -1;
506 case X_IFSOCK:
507 IDEVICE(f->st, 0);
508 /*FALLTHROUGH*/
509 case X_IFBLK:
510 case X_IFCHR:
511 case X_IFIFO:
512 if (exists && (prune(ap, f, &st) || state.update && f->st->st_dev != st.st_dev))
513 return -1;
514 if (!(ap->format->flags & KEEPSIZE))
515 f->st->st_size = 0;
516 break;
517 case X_IFREG:
518 if (exists && prune(ap, f, &st))
519 return -1;
520 break;
521 }
522 if (!addlink(ap, f))
523 return -1;
524 switch (f->type)
525 {
526 case X_IFIFO:
527 if (exists && remove(f->name))
528 {
529 error(ERROR_SYSTEM|2, "cannot remove current %s", f->name);
530 return -1;
531 }
532 if (mkfifo(f->name, f->st->st_mode & S_IPERM))
533 {
534 if (errno == EPERM)
535 {
536 nofifo:
537 error(ERROR_SYSTEM|2, "%s: cannot create fifo file", f->name);
538 return -1;
539 }
540 if (!exists && missdir(ap, f))
541 {
542 error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
543 return -1;
544 }
545 if (exists || mkfifo(f->name, f->st->st_mode & S_IPERM))
546 goto nofifo;
547 }
548 setfile(ap, f);
549 return -2;
550 case X_IFSOCK:
551 IDEVICE(f->st, 0);
552 /*FALLTHROUGH*/
553 case X_IFBLK:
554 case X_IFCHR:
555 if (exists && remove(f->name))
556 {
557 error(ERROR_SYSTEM|2, "cannot remove current %s", f->name);
558 return -1;
559 }
560 if (mknod(f->name, f->st->st_mode, idevice(f->st)))
561 {
562 if (errno == EPERM)
563 {
564 nospecial:
565 error(ERROR_SYSTEM|2, "%s: cannot create %s special file", f->name, (f->type == X_IFBLK) ? "block" : "character");
566 return -1;
567 }
568 if (!exists && missdir(ap, f))
569 {
570 error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
571 return -1;
572 }
573 if (exists || mknod(f->name, f->st->st_mode, idevice(f->st)))
574 goto nospecial;
575 }
576 setfile(ap, f);
577 return -2;
578 default:
579 error(1, "%s: unknown file type 0%03o -- creating regular file", f->name, f->type >> 12);
580 /*FALLTHROUGH*/
581 case X_IFREG:
582 if (f->ro)
583 return dup(1);
584 if (state.intermediate)
585 {
586 char* d;
587 char* e;
588 int n;
589 int ifd;
590
591 /*
592 * copy to intermediate output file and rename
593 * to real file only on success - a handy
594 * backup option
595 *
596 * thanks to the amazing dr. ek
597 */
598
599 if (missdir(ap, f))
600 {
601 error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
602 return -1;
603 }
604 d = (e = strrchr(f->name, '/')) ? f->name : ".";
605 for (n = 0;; n++)
606 {
607 if (e)
608 *e = 0;
609 f->intermediate = pathtemp(ap->path.temp, sizeof(ap->path.temp), d, error_info.id, &ifd);
610 if (e)
611 *e = '/';
612 message((-4, "%s: intermediate %s", f->name, f->intermediate));
613 if (f->intermediate)
614 {
615 ap->errors = error_info.errors;
616 return ifd;
617 }
618 if (n)
619 {
620 error(ERROR_SYSTEM|2, "%s: cannot create intermediate name", f->name);
621 return -1;
622 }
623 }
624 }
625
626 /*
627 * ok, the exists bits are only used right here
628 * you do the defines if its that important
629 *
630 * <chmod u+w><remove><missdir>
631 * 4 don't attempt
632 * 2 attempted and succeeded
633 * 1 attempted and failed
634 */
635
636 if (!exists)
637 exists |= 0440;
638 else if (!state.linkf)
639 exists |= remove(f->name) ? 0010 : 0420;
640 else if (st.st_mode & S_IWUSR)
641 exists |= 0400;
642 if ((perm = f->perm) & (S_ISUID|S_ISGID|S_ISVTX))
643 perm &= ~(S_ISUID|S_ISGID|S_ISVTX);
644 while ((fd = open(f->name, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, perm)) < 0)
645 {
646 again:
647 if (!(exists & 0007))
648 {
649 if (missdir(ap, f))
650 {
651 error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
652 return -1;
653 }
654 exists |= 0002;
655 }
656 else if (!(exists & 0700))
657 {
658 if (chmod(f->name, perm | S_IWUSR))
659 {
660 exists |= 0100;
661 goto again;
662 }
663 exists |= 0200;
664 }
665 else if (!(exists & 0070))
666 {
667 if (remove(f->name))
668 {
669 exists |= 0010;
670 goto again;
671 }
672 exists ^= 0620;
673 }
674 else
675 {
676 error(ERROR_SYSTEM|2, "%s: cannot create%s%s", f->name, (exists & 0100) ? ERROR_translate(0, 0, 0, ", cannot enable user write") : "", (exists & 0010) ? ERROR_translate(0, 0, 0, ", cannot remove") : "");
677 return -1;
678 }
679 }
680 if (perm != f->perm)
681 f->chmod = 1;
682 else if ((exists & 0200) && chmod(f->name, f->perm))
683 error(ERROR_SYSTEM|1, "%s: cannot restore original mode %s", f->name, fmtperm(st.st_mode & S_IPERM));
684 return fd;
685 }
686 }
687
688 /*
689 * close an openin() fd, doing atime reset if necessary
690 */
691
692 int
closein(register Archive_t * ap,register File_t * f,int fd)693 closein(register Archive_t* ap, register File_t* f, int fd)
694 {
695 int r;
696
697 r = 0;
698 if (close(fd))
699 r = -1;
700 if (state.resetacctime && f->type != X_IFLNK && !f->skip)
701 {
702 Tv_t av;
703 Tv_t mv;
704
705 tvgetatime(&av, f->st);
706 tvgetmtime(&mv, f->st);
707 settime(f->path, &av, &mv, NiL);
708 }
709 return r;
710 }
711
712 /*
713 * close an openout() fd, doing the intermediate rename if needed
714 */
715
716 int
closeout(register Archive_t * ap,register File_t * f,int fd)717 closeout(register Archive_t* ap, register File_t* f, int fd)
718 {
719 register char* s;
720 int r;
721
722 r = 0;
723 if (state.sync && fsync(fd))
724 r = -1;
725 if (close(fd))
726 r = -1;
727 if (s = f->intermediate)
728 {
729 f->intermediate = 0;
730 if (ap->errors != error_info.errors)
731 {
732 if (remove(s))
733 error(ERROR_SYSTEM|2, "%s: cannot remove intermediate file %s", f->name, s);
734 return -1;
735 }
736 if (rename(s, f->name) && (remove(f->name) || rename(s, f->name)))
737 {
738 error(ERROR_SYSTEM|2, "%s: cannot rename from intermediate file %s", f->name, s);
739 return -1;
740 }
741 if (chmod(f->name, f->perm))
742 {
743 error(ERROR_SYSTEM|1, "%s: cannot change mode to %s", f->name, fmtperm(f->perm));
744 return -1;
745 }
746 }
747 return r;
748 }
749
750 /*
751 * get file info for output
752 */
753
754 int
getfile(register Archive_t * ap,register File_t * f,register Ftw_t * ftw)755 getfile(register Archive_t* ap, register File_t* f, register Ftw_t* ftw)
756 {
757 register char* name;
758 register int n;
759 char* e;
760
761 name = ftw->path;
762 message((-4, "getfile(%s)", name));
763 switch (ftw->info)
764 {
765 case FTW_NS:
766 error(2, "%s: not found", name);
767 return 0;
768 case FTW_DNR:
769 if (state.files)
770 error(2, "%s: cannot read directory", name);
771 break;
772 case FTW_D:
773 case FTW_DNX:
774 case FTW_DP:
775 if (!state.descend)
776 ftw->status = FTW_SKIP;
777 else if (ftw->info == FTW_DNX)
778 {
779 error(2, "%s: cannot search directory", name);
780 ftw->status = FTW_SKIP;
781 }
782 else if (!state.files)
783 {
784 /*
785 * stdin files most likely come from tw/find with
786 * directory descendents already included; in posix
787 * omitting -d would result in duplicate output copies
788 * so we avoid the problem by peeking ahead and
789 * pruning all paths with this dir prefix
790 */
791
792 n = ftw->pathlen;
793 name = stash(&ap->path.peek, name, n);
794 name[n] = '/';
795 if (!state.peekfile || !strncmp(state.peekfile, name, n))
796 while (state.peekfile = sfgetr(sfstdin, '\n', 1))
797 if (strncmp(state.peekfile, name, n))
798 {
799 state.peeklen = sfvalue(sfstdin) - 1;
800 break;
801 }
802 name[n] = 0;
803 }
804 break;
805 }
806 if (ap->delta)
807 ap->delta->hdr = ap->delta->hdrbuf;
808 name = stash(&ap->path.name, name, ftw->pathlen);
809 pathcanon(name, 0, 0);
810 f->path = stash(&ap->path.path, name, ftw->pathlen);
811 f->name = map(ap, name);
812 if (state.files && state.operation == (IN|OUT) && dirprefix(state.destination, name, 0))
813 return 0;
814 f->namesize = strlen(f->name) + 1;
815 ap->st = ftw->statb;
816 f->st = &ap->st;
817 f->perm = f->st->st_mode & S_IPERM;
818 f->st->st_mode = modex(f->st->st_mode);
819 f->uidname = 0;
820 f->gidname = 0;
821 f->link = 0;
822 if ((f->type = X_ITYPE(f->st->st_mode)) == X_IFLNK)
823 {
824 f->linkpathsize = f->st->st_size + 1;
825 f->linkpath = stash(&ap->stash.link, NiL, f->linkpathsize);
826 if (pathgetlink(f->path, f->linkpath, f->linkpathsize) != f->st->st_size)
827 {
828 error(2, "%s: cannot read symbolic link", f->path);
829 ftw->status = FTW_SKIP;
830 return 0;
831 }
832 f->linktype = SOFTLINK;
833 pathcanon(f->linkpath, 0, 0);
834 if (!(state.ftwflags & FTW_PHYSICAL))
835 f->linkpath = map(ap, f->linkpath);
836 if (streq(f->path, f->linkpath))
837 {
838 error(2, "%s: symbolic link loops to self", f->path);
839 ftw->status = FTW_SKIP;
840 return 0;
841 }
842 }
843 else
844 {
845 f->linktype = NOLINK;
846 f->linkpath = 0;
847 f->linkpathsize = 0;
848 }
849 f->ro = ropath(f->name);
850 if (!validout(ap, f))
851 return 0;
852 if (!(state.operation & IN) && f->type != X_IFDIR)
853 {
854 if (!addlink(ap, f) && !state.header.linkdata)
855 f->st->st_size = 0;
856 message((-4, "getfile(%s): dev'=%d ino'=%d", f->name, f->st->st_dev, f->st->st_ino));
857 }
858 ap->entries++;
859 f->delta.op = 0;
860 f->longname = 0;
861 f->longlink = 0;
862 f->skip = 0;
863 if (state.mode)
864 {
865 f->st->st_mode = strperm(state.mode, &e, f->st->st_mode);
866 if (*e)
867 error(2, "%s: invalid mode expression", state.mode);
868 }
869 if (state.mtime)
870 {
871 f->st->st_mtime = tmdate(state.mtime, &e, NiL);
872 if (*e)
873 error(2, "%s: invalid mtime", state.mtime);
874 }
875 message((-2, "getfile(): path=%s name=%s mode=%s size=%I*d mtime=%s", name, f->name, fmtmode(f->st->st_mode, 1), sizeof(f->st->st_size), f->st->st_size, fmttime("%K", f->st->st_mtime)));
876 return 1;
877 }
878
879 /*
880 * check that f is valid for archive output
881 */
882
883 int
validout(register Archive_t * ap,register File_t * f)884 validout(register Archive_t* ap, register File_t* f)
885 {
886 if (f->ro)
887 return 0;
888 switch (f->type)
889 {
890 case X_IFBLK:
891 case X_IFCHR:
892 f->st->st_size = 0;
893 break;
894 case X_IFREG:
895 IDEVICE(f->st, 0);
896 break;
897 case X_IFDIR:
898 case X_IFIFO:
899 case X_IFLNK:
900 f->st->st_size = 0;
901 IDEVICE(f->st, 0);
902 break;
903 }
904 return ap->format->validate ? ((*ap->format->validate)(&state, ap, f) > 0) : 1;
905 }
906
907 /*
908 * add file which may be a link
909 * 0 returned if <dev,ino> already added
910 */
911
912 int
addlink(register Archive_t * ap,register File_t * f)913 addlink(register Archive_t* ap, register File_t* f)
914 {
915 register Link_t* p;
916 register char* s;
917 int n;
918 Fileid_t id;
919 unsigned short us;
920
921 id.dev = f->st->st_dev;
922 id.ino = f->st->st_ino;
923 if (!ap->delta)
924 switch (state.operation)
925 {
926 case IN:
927 us = id.dev;
928 if (us > state.devcnt)
929 {
930 state.devcnt = us;
931 state.inocnt = id.ino;
932 }
933 else if (us == state.devcnt)
934 {
935 us = id.ino;
936 if (us > state.inocnt)
937 state.inocnt = us;
938 }
939 break;
940 case IN|OUT:
941 if (!state.pass)
942 break;
943 /*FALLTHROUGH*/
944 case OUT:
945 if (!++state.inocnt)
946 {
947 if (!++state.devcnt)
948 goto toomany;
949 state.inocnt = 1;
950 }
951 f->st->st_dev = state.devcnt;
952 f->st->st_ino = state.inocnt;
953 break;
954 }
955 if (f->type == X_IFDIR)
956 return 0;
957 if (ap->format->flags & NOHARDLINKS)
958 {
959 if (state.operation == IN || f->st->st_nlink <= 1)
960 return 1;
961 }
962 else if ((ap->format->flags & LINKTYPE) && state.operation == IN)
963 {
964 if (f->linktype == NOLINK)
965 return 1;
966 f->linkpath = map(ap, f->linkpath);
967 goto linked;
968 }
969 else if (f->st->st_nlink <= 1)
970 return 1;
971 if (p = (Link_t*)hashget(state.linktab, (char*)&id))
972 {
973 if (ap->format->flags & NOHARDLINKS)
974 {
975 error(1, "%s: hard link information lost in %s format", f->name, ap->format->name);
976 return 1;
977 }
978 f->st->st_dev = p->id.dev;
979 f->st->st_ino = p->id.ino;
980 f->link = p;
981 f->linktype = HARDLINK;
982 f->linkpath = p->name;
983 if (state.pass && (state.operation & OUT) || !state.pass && state.operation == OUT)
984 return 0;
985 linked:
986 message((-1, "addlink(%s,%s)", f->name, f->linkpath));
987 if (ap->format->event && (ap->format->events & PAX_EVENT_BUG_19951031))
988 (*ap->format->event)(&state, ap, f, NiL, PAX_EVENT_BUG_19951031);
989 if (streq(f->name, f->linkpath))
990 {
991 error(2, "%s: hard link loops to self", f->name);
992 return 0;
993 }
994 if (!state.list)
995 {
996 s = f->linkpath;
997 if (access(s, F_OK))
998 {
999 f->skip = 1;
1000 error(2, "%s must exist for hard link %s", s, f->name);
1001 return 0;
1002 }
1003 remove(f->name);
1004 if (state.operation == IN && *s != '/')
1005 {
1006 strcpy(state.pwd + state.pwdlen, s);
1007 s = state.pwd;
1008 }
1009 if (link(s, f->name))
1010 {
1011 if (missdir(ap, f))
1012 {
1013 error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
1014 return 0;
1015 }
1016 if (link(s, f->name))
1017 {
1018 error(ERROR_SYSTEM|2, "%s: cannot link to %s", f->linkpath, f->name);
1019 return -1;
1020 }
1021 }
1022 listentry(f);
1023 }
1024 return 0;
1025 }
1026 n = strlen(f->name) + 1;
1027 if (!(p = newof(0, Link_t, 1, n)))
1028 goto toomany;
1029 f->link = p;
1030 strcpy(p->name = (char*)p + sizeof(*p), f->name);
1031 p->namesize = n;
1032 p->id.dev = f->st->st_dev;
1033 p->id.ino = f->st->st_ino;
1034 hashput(state.linktab, NiL, p);
1035 return -1;
1036 toomany:
1037 if (!state.warnlinknum)
1038 {
1039 state.warnlinknum = 1;
1040 error(1, "too many hard links -- some links may become copies");
1041 }
1042 return -1;
1043 }
1044
1045 /*
1046 * get file uid and gid names given numbers
1047 */
1048
1049 void
getidnames(register File_t * f)1050 getidnames(register File_t* f)
1051 {
1052 if (!f->uidname)
1053 f->uidname = fmtuid(f->st->st_uid);
1054 if (!f->gidname)
1055 f->gidname = fmtgid(f->st->st_gid);
1056 }
1057
1058 /*
1059 * set file uid and gid numbers given names
1060 */
1061
1062 void
setidnames(register File_t * f)1063 setidnames(register File_t* f)
1064 {
1065 register int id;
1066
1067 if (f->uidname)
1068 {
1069 if ((id = struid(f->uidname)) < 0)
1070 {
1071 if (id == -1 && state.owner)
1072 error(1, "%s: invalid user name", f->uidname);
1073 f->uidname = 0;
1074 id = state.uid;
1075 }
1076 f->st->st_uid = id;
1077 }
1078 if (f->gidname)
1079 {
1080 if ((id = strgid(f->gidname)) < 0)
1081 {
1082 if (id == -1 && state.owner)
1083 error(1, "%s: invalid group name", f->gidname);
1084 f->gidname = 0;
1085 id = state.gid;
1086 }
1087 f->st->st_gid = id;
1088 }
1089 }
1090
1091 /*
1092 * allocate and initialize new archive pointer
1093 */
1094
1095 Archive_t*
initarchive(const char * name,int mode)1096 initarchive(const char* name, int mode)
1097 {
1098 Archive_t* ap;
1099
1100 if (!(ap = newof(0, Archive_t, 1, 0)))
1101 nospace();
1102 initfile(ap, &ap->file, &ap->st, NiL, 0);
1103 ap->name = (char*)name;
1104 ap->expected = ap->format = 0;
1105 ap->section = 0;
1106 ap->sum = -1;
1107 ap->mio.mode = ap->tio.mode = mode;
1108 ap->io = &ap->mio;
1109 return ap;
1110 }
1111
1112 /*
1113 * return pointer to archive for op
1114 */
1115
1116 Archive_t*
getarchive(int op)1117 getarchive(int op)
1118 {
1119 Archive_t** app;
1120
1121 app = (op & OUT) ? &state.out : &state.in;
1122 if (!*app)
1123 *app = initarchive(NiL, (op & OUT) ? (state.append ? (O_WRONLY|O_CREAT) : (O_WRONLY|O_CREAT|O_TRUNC)) : O_RDONLY);
1124 return *app;
1125 }
1126
1127 /*
1128 * initialize file info with name and mode
1129 */
1130
1131 void
initfile(register Archive_t * ap,register File_t * f,struct stat * st,register char * name,int mode)1132 initfile(register Archive_t* ap, register File_t* f, struct stat* st, register char* name, int mode)
1133 {
1134 memzero(f, sizeof(*f));
1135 f->st = st;
1136 memzero(f->st, sizeof(*f->st));
1137 if (name)
1138 {
1139 f->id = f->name = f->path = name;
1140 f->namesize = strlen(name) + 1;
1141 }
1142 f->st->st_mode = modex(mode);
1143 f->st->st_nlink = 1; /* system V needs this!!! */
1144 }
1145
1146 /*
1147 * set copied file info
1148 */
1149
1150 void
setfile(register Archive_t * ap,register File_t * f)1151 setfile(register Archive_t* ap, register File_t* f)
1152 {
1153 register Post_t* p;
1154 int updated;
1155 Post_t post;
1156
1157 if (f->skip || f->extended)
1158 return;
1159 switch (f->type)
1160 {
1161 case X_IFLNK:
1162 updated = 0;
1163 #if _lib_lchown
1164 if (state.owner)
1165 {
1166 if (state.flags & SETIDS)
1167 {
1168 post.uid = state.setuid;
1169 post.gid = state.setgid;
1170 }
1171 else
1172 {
1173 post.uid = f->st->st_uid;
1174 post.gid = f->st->st_gid;
1175 }
1176 if (lchown(f->name, post.uid, post.gid) < 0)
1177 error(1, "%s: cannot chown to (%d,%d)", f->name, post.uid, post.gid);
1178 }
1179 #endif
1180 #if _lib_lchmod
1181 if (f->chmod)
1182 {
1183 int m;
1184 struct stat st;
1185
1186 if (lchmod(f->name, f->perm & state.modemask))
1187 error(1, "%s: cannot chmod to %s", f->name, fmtmode(f->perm & state.modemask, 0) + 1);
1188 else if (m = f->perm & (S_ISUID|S_ISGID|S_ISVTX))
1189 {
1190 if (lstat(f->name, &st))
1191 error(1, "%s: not found", f->name);
1192 else if (m ^= (st.st_mode & (S_ISUID|S_ISGID|S_ISVTX)))
1193 error(1, "%s: mode %s not set", f->name, fmtmode(m, 0) + 1);
1194 }
1195 }
1196 #endif
1197 ap->updated += updated;
1198 return;
1199 case X_IFDIR:
1200 if (f->chmod || state.acctime || state.modtime || state.owner || (f->perm & S_IRWXU) != S_IRWXU)
1201 {
1202 if (!(p = newof(0, Post_t, 1, 0)))
1203 error(3, "not enough space for file restoration info");
1204 tvgetatime(&p->atime, f->st);
1205 tvgetmtime(&p->mtime, f->st);
1206 p->uid = f->st->st_uid;
1207 p->gid = f->st->st_gid;
1208 p->mode = f->perm;
1209 if ((f->perm & S_IRWXU) != S_IRWXU)
1210 {
1211 p->chmod = 1;
1212 if (chmod(f->name, f->perm|S_IRWXU))
1213 error(1, "%s: cannot chmod to %s", f->name, fmtmode(f->st->st_mode|X_IRWXU, 1) + 1);
1214 }
1215 else
1216 p->chmod = f->chmod;
1217 hashput(state.restore, f->name, p);
1218 ap->updated++;
1219 return;
1220 }
1221 break;
1222 }
1223 ap->updated++;
1224 p = &post;
1225 if (state.acctime)
1226 tvgetatime(&p->atime, f->st);
1227 tvgetmtime(&p->mtime, f->st);
1228 p->uid = f->st->st_uid;
1229 p->gid = f->st->st_gid;
1230 p->mode = f->perm;
1231 p->chmod = f->chmod;
1232 restore(f->name, (char*)p, NiL);
1233 }
1234
1235 /*
1236 * set access and modification times of file
1237 */
1238
1239 void
settime(const char * name,Tv_t * ap,Tv_t * mp,Tv_t * cp)1240 settime(const char* name, Tv_t* ap, Tv_t* mp, Tv_t* cp)
1241 {
1242 if (*name && tvtouch(name, ap, mp, cp, 0) && errno != ENOENT && errno != ENOTDIR)
1243 error(1, "%s: cannot set times", name);
1244 }
1245
1246 /*
1247 * restore file status after processing
1248 */
1249
1250 int
restore(register const char * name,char * ap,void * handle)1251 restore(register const char* name, char* ap, void* handle)
1252 {
1253 register Post_t* p = (Post_t*)ap;
1254 int m;
1255 struct stat st;
1256
1257 NoP(handle);
1258 if (!*name)
1259 return 0;
1260 if (state.owner)
1261 {
1262 if (state.flags & SETIDS)
1263 {
1264 p->uid = state.setuid;
1265 p->gid = state.setgid;
1266 }
1267 if (chown(name, p->uid, p->gid) < 0)
1268 error(1, "%s: cannot chown to (%d,%d)", name, p->uid, p->gid);
1269 }
1270 if (p->chmod)
1271 {
1272 if (chmod(name, p->mode & state.modemask))
1273 error(1, "%s: cannot chmod to %s", name, fmtmode(p->mode & state.modemask, 0) + 1);
1274 else if (m = p->mode & (S_ISUID|S_ISGID|S_ISVTX))
1275 {
1276 if (stat(name, &st))
1277 error(1, "%s: not found", name);
1278 else if (m ^= (st.st_mode & (S_ISUID|S_ISGID|S_ISVTX)))
1279 error(1, "%s: mode %s not set", name, fmtmode(m, 0) + 1);
1280 }
1281 }
1282 if (state.modtime)
1283 settime(name, state.acctime ? &p->atime : 0, &p->mtime, NiL);
1284 return 0;
1285 }
1286
1287 /*
1288 * return 1 if f output can be pruned
1289 */
1290
1291 int
prune(register Archive_t * ap,register File_t * f,register struct stat * st)1292 prune(register Archive_t* ap, register File_t* f, register struct stat* st)
1293 {
1294 Tv_t t1;
1295 Tv_t t2;
1296 struct stat so;
1297 int c;
1298
1299 if (state.operation != (IN|OUT) && state.update == OPT_update && !streq(f->name, f->path))
1300 {
1301 if ((*state.statf)(f->path, &so))
1302 return 0;
1303 st = &so;
1304 }
1305 if (st->st_mode == f->st->st_mode)
1306 {
1307 if (ap->delta && !tvcmp(tvmtime(&t1, f->st), tvmtime(&t2, st)))
1308 return 1;
1309 if (state.update && (!(c = tvcmp(tvmtime(&t1, f->st), tvmtime(&t2, st))) || state.update != OPT_different && c < 0))
1310 {
1311 if (state.exact)
1312 state.pattern->matched = 0;
1313 return 1;
1314 }
1315 }
1316 return 0;
1317 }
1318
1319 /*
1320 * write siz bytes of buf to fd checking for HOLE_MIN hole chunks
1321 * we assume siz is rounded nicely until the end
1322 */
1323
1324 ssize_t
holewrite(int fd,void * buf,size_t siz)1325 holewrite(int fd, void* buf, size_t siz)
1326 {
1327 register char* t = (char*)buf;
1328 register char* e = t + siz;
1329 register char* b = 0;
1330 register char* s;
1331 ssize_t i;
1332 ssize_t n = 0;
1333
1334 static char hole[HOLE_MIN];
1335
1336 #if DEBUG
1337 if (state.test & 0000100)
1338 b = t;
1339 else
1340 #endif
1341 while (t < e)
1342 {
1343 s = t;
1344 if ((t += HOLE_MIN) > e)
1345 t = e;
1346 if (!*s && !*(t - 1) && !memcmp(s, hole, t - s))
1347 {
1348 if (b)
1349 {
1350 if (state.hole)
1351 {
1352 if (lseek(fd, state.hole, SEEK_CUR) < state.hole)
1353 return -1;
1354 state.hole = 0;
1355 }
1356 if ((i = write(fd, b, s - b)) != (s - b))
1357 return i;
1358 n += i;
1359 b = 0;
1360 }
1361 state.hole += t - s;
1362 n += t - s;
1363 }
1364 else if (!b)
1365 b = s;
1366 }
1367 if (b)
1368 {
1369 if (state.hole)
1370 {
1371 if (lseek(fd, state.hole, SEEK_CUR) < state.hole)
1372 return -1;
1373 state.hole = 0;
1374 }
1375 if ((i = write(fd, b, e - b)) != (e - b))
1376 return i;
1377 n += i;
1378 }
1379 return n;
1380 }
1381
1382 /*
1383 * make a seekable copy of ap->io input
1384 */
1385
1386 void
seekable(Archive_t * ap)1387 seekable(Archive_t* ap)
1388 {
1389 off_t m;
1390 off_t z;
1391 char* s;
1392 int rfd;
1393 int wfd;
1394
1395 if ((wfd = open(state.tmp.file, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR)) < 0)
1396 error(ERROR_SYSTEM|3, "%s: cannot create seekable temporary %s", ap->name, state.tmp.file);
1397 if ((rfd = open(state.tmp.file, O_RDONLY|O_BINARY)) < 0)
1398 error(ERROR_SYSTEM|3, "%s: cannot open seekable temporary %s", ap->name, state.tmp.file);
1399 if (remove(state.tmp.file))
1400 error(ERROR_SYSTEM|1, "%s: cannot remove seekable temporary %s", ap->name, state.tmp.file);
1401 ap->io->seekable = 1;
1402 z = 0;
1403 s = ap->io->buffer + ap->io->unread;
1404 m = ap->io->last - s;
1405 do
1406 {
1407 if (write(wfd, s, m) != m)
1408 error(ERROR_SYSTEM|3, "%s: seekable temporary %s write error", ap->name, state.tmp.file);
1409 z += m;
1410 } while ((m = read(ap->io->fd, s, state.buffersize)) > 0);
1411 close(wfd);
1412 close(ap->io->fd);
1413 ap->io->size = z;
1414 z = ap->io->count;
1415 ap->io->next = ap->io->last = s;
1416 ap->io->offset = ap->io->count = 0;
1417 if (ap->io->fd || (ap->io->fd = dup(rfd)) < 0)
1418 ap->io->fd = rfd;
1419 else
1420 close(rfd);
1421 bread(ap, NiL, z, z, 0);
1422 }
1423