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