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