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