1228753Smm/*-
2228753Smm * Copyright (c) 2003-2007 Tim Kientzle
3228753Smm * All rights reserved.
4228753Smm *
5228753Smm * Redistribution and use in source and binary forms, with or without
6228753Smm * modification, are permitted provided that the following conditions
7228753Smm * are met:
8228753Smm * 1. Redistributions of source code must retain the above copyright
9228753Smm *    notice, this list of conditions and the following disclaimer.
10228753Smm * 2. Redistributions in binary form must reproduce the above copyright
11228753Smm *    notice, this list of conditions and the following disclaimer in the
12228753Smm *    documentation and/or other materials provided with the distribution.
13228753Smm *
14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24228753Smm */
25228753Smm
26228753Smm#include "bsdtar_platform.h"
27228763Smm__FBSDID("$FreeBSD: stable/11/contrib/libarchive/tar/util.c 358088 2020-02-19 01:50:47Z mm $");
28228753Smm
29228753Smm#ifdef HAVE_SYS_STAT_H
30228753Smm#include <sys/stat.h>
31228753Smm#endif
32228753Smm#ifdef HAVE_SYS_TYPES_H
33228753Smm#include <sys/types.h>  /* Linux doesn't define mode_t, etc. in sys/stat.h. */
34228753Smm#endif
35228753Smm#include <ctype.h>
36228753Smm#ifdef HAVE_ERRNO_H
37228753Smm#include <errno.h>
38228753Smm#endif
39228753Smm#ifdef HAVE_IO_H
40228753Smm#include <io.h>
41228753Smm#endif
42228753Smm#ifdef HAVE_STDARG_H
43228753Smm#include <stdarg.h>
44228753Smm#endif
45228753Smm#ifdef HAVE_STDINT_H
46228753Smm#include <stdint.h>
47228753Smm#endif
48228753Smm#include <stdio.h>
49228753Smm#ifdef HAVE_STDLIB_H
50228753Smm#include <stdlib.h>
51228753Smm#endif
52228753Smm#ifdef HAVE_STRING_H
53228753Smm#include <string.h>
54228753Smm#endif
55228753Smm#ifdef HAVE_WCTYPE_H
56228753Smm#include <wctype.h>
57228753Smm#else
58228753Smm/* If we don't have wctype, we need to hack up some version of iswprint(). */
59232153Smm#define	iswprint isprint
60228753Smm#endif
61228753Smm
62228753Smm#include "bsdtar.h"
63228753Smm#include "err.h"
64299529Smm#include "passphrase.h"
65228753Smm
66228753Smmstatic size_t	bsdtar_expand_char(char *, size_t, char);
67228753Smmstatic const char *strip_components(const char *path, int elements);
68228753Smm
69228753Smm#if defined(_WIN32) && !defined(__CYGWIN__)
70232153Smm#define	read _read
71228753Smm#endif
72228753Smm
73228753Smm/* TODO:  Hack up a version of mbtowc for platforms with no wide
74228753Smm * character support at all.  I think the following might suffice,
75228753Smm * but it needs careful testing.
76228753Smm * #if !HAVE_MBTOWC
77232153Smm * #define	mbtowc(wcp, p, n) ((*wcp = *p), 1)
78228753Smm * #endif
79228753Smm */
80228753Smm
81228753Smm/*
82228753Smm * Print a string, taking care with any non-printable characters.
83228753Smm *
84228753Smm * Note that we use a stack-allocated buffer to receive the formatted
85228753Smm * string if we can.  This is partly performance (avoiding a call to
86228753Smm * malloc()), partly out of expedience (we have to call vsnprintf()
87228753Smm * before malloc() anyway to find out how big a buffer we need; we may
88228753Smm * as well point that first call at a small local buffer in case it
89228753Smm * works), but mostly for safety (so we can use this to print messages
90228753Smm * about out-of-memory conditions).
91228753Smm */
92228753Smm
93228753Smmvoid
94228753Smmsafe_fprintf(FILE *f, const char *fmt, ...)
95228753Smm{
96228753Smm	char fmtbuff_stack[256]; /* Place to format the printf() string. */
97228753Smm	char outbuff[256]; /* Buffer for outgoing characters. */
98228753Smm	char *fmtbuff_heap; /* If fmtbuff_stack is too small, we use malloc */
99228753Smm	char *fmtbuff;  /* Pointer to fmtbuff_stack or fmtbuff_heap. */
100228753Smm	int fmtbuff_length;
101228753Smm	int length, n;
102228753Smm	va_list ap;
103228753Smm	const char *p;
104228753Smm	unsigned i;
105228753Smm	wchar_t wc;
106228753Smm	char try_wc;
107228753Smm
108228753Smm	/* Use a stack-allocated buffer if we can, for speed and safety. */
109228753Smm	fmtbuff_heap = NULL;
110228753Smm	fmtbuff_length = sizeof(fmtbuff_stack);
111228753Smm	fmtbuff = fmtbuff_stack;
112228753Smm
113228753Smm	/* Try formatting into the stack buffer. */
114228753Smm	va_start(ap, fmt);
115228753Smm	length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
116228753Smm	va_end(ap);
117228753Smm
118228753Smm	/* If the result was too large, allocate a buffer on the heap. */
119232153Smm	while (length < 0 || length >= fmtbuff_length) {
120232153Smm		if (length >= fmtbuff_length)
121232153Smm			fmtbuff_length = length+1;
122232153Smm		else if (fmtbuff_length < 8192)
123232153Smm			fmtbuff_length *= 2;
124248616Smm		else if (fmtbuff_length < 1000000)
125248616Smm			fmtbuff_length += fmtbuff_length / 4;
126232153Smm		else {
127248616Smm			length = fmtbuff_length;
128248616Smm			fmtbuff_heap[length-1] = '\0';
129248616Smm			break;
130232153Smm		}
131232153Smm		free(fmtbuff_heap);
132228753Smm		fmtbuff_heap = malloc(fmtbuff_length);
133228753Smm
134228753Smm		/* Reformat the result into the heap buffer if we can. */
135228753Smm		if (fmtbuff_heap != NULL) {
136228753Smm			fmtbuff = fmtbuff_heap;
137228753Smm			va_start(ap, fmt);
138228753Smm			length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
139228753Smm			va_end(ap);
140228753Smm		} else {
141228753Smm			/* Leave fmtbuff pointing to the truncated
142228753Smm			 * string in fmtbuff_stack. */
143313570Smm			fmtbuff = fmtbuff_stack;
144228753Smm			length = sizeof(fmtbuff_stack) - 1;
145232153Smm			break;
146228753Smm		}
147228753Smm	}
148228753Smm
149228753Smm	/* Note: mbrtowc() has a cleaner API, but mbtowc() seems a bit
150228753Smm	 * more portable, so we use that here instead. */
151248616Smm	if (mbtowc(NULL, NULL, 1) == -1) { /* Reset the shift state. */
152248616Smm		/* mbtowc() should never fail in practice, but
153248616Smm		 * handle the theoretical error anyway. */
154248616Smm		free(fmtbuff_heap);
155248616Smm		return;
156248616Smm	}
157228753Smm
158228753Smm	/* Write data, expanding unprintable characters. */
159228753Smm	p = fmtbuff;
160228753Smm	i = 0;
161228753Smm	try_wc = 1;
162228753Smm	while (*p != '\0') {
163228753Smm
164228753Smm		/* Convert to wide char, test if the wide
165228753Smm		 * char is printable in the current locale. */
166228753Smm		if (try_wc && (n = mbtowc(&wc, p, length)) != -1) {
167228753Smm			length -= n;
168228753Smm			if (iswprint(wc) && wc != L'\\') {
169228753Smm				/* Printable, copy the bytes through. */
170228753Smm				while (n-- > 0)
171228753Smm					outbuff[i++] = *p++;
172228753Smm			} else {
173228753Smm				/* Not printable, format the bytes. */
174228753Smm				while (n-- > 0)
175228753Smm					i += (unsigned)bsdtar_expand_char(
176228753Smm					    outbuff, i, *p++);
177228753Smm			}
178228753Smm		} else {
179228753Smm			/* After any conversion failure, don't bother
180228753Smm			 * trying to convert the rest. */
181228753Smm			i += (unsigned)bsdtar_expand_char(outbuff, i, *p++);
182228753Smm			try_wc = 0;
183228753Smm		}
184228753Smm
185228753Smm		/* If our output buffer is full, dump it and keep going. */
186305188Smm		if (i > (sizeof(outbuff) - 128)) {
187228753Smm			outbuff[i] = '\0';
188228753Smm			fprintf(f, "%s", outbuff);
189228753Smm			i = 0;
190228753Smm		}
191228753Smm	}
192228753Smm	outbuff[i] = '\0';
193228753Smm	fprintf(f, "%s", outbuff);
194228753Smm
195228753Smm	/* If we allocated a heap-based formatting buffer, free it now. */
196248616Smm	free(fmtbuff_heap);
197228753Smm}
198228753Smm
199228753Smm/*
200228753Smm * Render an arbitrary sequence of bytes into printable ASCII characters.
201228753Smm */
202228753Smmstatic size_t
203228753Smmbsdtar_expand_char(char *buff, size_t offset, char c)
204228753Smm{
205228753Smm	size_t i = offset;
206228753Smm
207228753Smm	if (isprint((unsigned char)c) && c != '\\')
208228753Smm		buff[i++] = c;
209228753Smm	else {
210228753Smm		buff[i++] = '\\';
211228753Smm		switch (c) {
212228753Smm		case '\a': buff[i++] = 'a'; break;
213228753Smm		case '\b': buff[i++] = 'b'; break;
214228753Smm		case '\f': buff[i++] = 'f'; break;
215228753Smm		case '\n': buff[i++] = 'n'; break;
216228753Smm#if '\r' != '\n'
217228753Smm		/* On some platforms, \n and \r are the same. */
218228753Smm		case '\r': buff[i++] = 'r'; break;
219228753Smm#endif
220228753Smm		case '\t': buff[i++] = 't'; break;
221228753Smm		case '\v': buff[i++] = 'v'; break;
222228753Smm		case '\\': buff[i++] = '\\'; break;
223228753Smm		default:
224228753Smm			sprintf(buff + i, "%03o", 0xFF & (int)c);
225228753Smm			i += 3;
226228753Smm		}
227228753Smm	}
228228753Smm
229228753Smm	return (i - offset);
230228753Smm}
231228753Smm
232228753Smmint
233228753Smmyes(const char *fmt, ...)
234228753Smm{
235228753Smm	char buff[32];
236228753Smm	char *p;
237228753Smm	ssize_t l;
238228753Smm
239228753Smm	va_list ap;
240228753Smm	va_start(ap, fmt);
241228753Smm	vfprintf(stderr, fmt, ap);
242228753Smm	va_end(ap);
243228753Smm	fprintf(stderr, " (y/N)? ");
244228753Smm	fflush(stderr);
245228753Smm
246228753Smm	l = read(2, buff, sizeof(buff) - 1);
247228776Smm	if (l < 0) {
248228776Smm	  fprintf(stderr, "Keyboard read failed\n");
249228776Smm	  exit(1);
250228776Smm	}
251228776Smm	if (l == 0)
252228753Smm		return (0);
253228753Smm	buff[l] = 0;
254228753Smm
255228753Smm	for (p = buff; *p != '\0'; p++) {
256228753Smm		if (isspace((unsigned char)*p))
257228753Smm			continue;
258228753Smm		switch(*p) {
259228753Smm		case 'y': case 'Y':
260228753Smm			return (1);
261228753Smm		case 'n': case 'N':
262228753Smm			return (0);
263228753Smm		default:
264228753Smm			return (0);
265228753Smm		}
266228753Smm	}
267228753Smm
268228753Smm	return (0);
269228753Smm}
270228753Smm
271228753Smm/*-
272228753Smm * The logic here for -C <dir> attempts to avoid
273228753Smm * chdir() as long as possible.  For example:
274228753Smm * "-C /foo -C /bar file"          needs chdir("/bar") but not chdir("/foo")
275228753Smm * "-C /foo -C bar file"           needs chdir("/foo/bar")
276228753Smm * "-C /foo -C bar /file1"         does not need chdir()
277228753Smm * "-C /foo -C bar /file1 file2"   needs chdir("/foo/bar") before file2
278228753Smm *
279228753Smm * The only correct way to handle this is to record a "pending" chdir
280228753Smm * request and combine multiple requests intelligently until we
281228753Smm * need to process a non-absolute file.  set_chdir() adds the new dir
282228753Smm * to the pending list; do_chdir() actually executes any pending chdir.
283228753Smm *
284228753Smm * This way, programs that build tar command lines don't have to worry
285228753Smm * about -C with non-existent directories; such requests will only
286228753Smm * fail if the directory must be accessed.
287228753Smm *
288228753Smm */
289228753Smmvoid
290228753Smmset_chdir(struct bsdtar *bsdtar, const char *newdir)
291228753Smm{
292232153Smm#if defined(_WIN32) && !defined(__CYGWIN__)
293232153Smm	if (newdir[0] == '/' || newdir[0] == '\\' ||
294232153Smm	    /* Detect this type, for example, "C:\" or "C:/" */
295232153Smm	    (((newdir[0] >= 'a' && newdir[0] <= 'z') ||
296232153Smm	      (newdir[0] >= 'A' && newdir[0] <= 'Z')) &&
297232153Smm	    newdir[1] == ':' && (newdir[2] == '/' || newdir[2] == '\\'))) {
298232153Smm#else
299228753Smm	if (newdir[0] == '/') {
300232153Smm#endif
301228753Smm		/* The -C /foo -C /bar case; dump first one. */
302228753Smm		free(bsdtar->pending_chdir);
303228753Smm		bsdtar->pending_chdir = NULL;
304228753Smm	}
305228753Smm	if (bsdtar->pending_chdir == NULL)
306228753Smm		/* Easy case: no previously-saved dir. */
307228753Smm		bsdtar->pending_chdir = strdup(newdir);
308228753Smm	else {
309228753Smm		/* The -C /foo -C bar case; concatenate */
310228753Smm		char *old_pending = bsdtar->pending_chdir;
311228753Smm		size_t old_len = strlen(old_pending);
312228753Smm		bsdtar->pending_chdir = malloc(old_len + strlen(newdir) + 2);
313228753Smm		if (old_pending[old_len - 1] == '/')
314228753Smm			old_pending[old_len - 1] = '\0';
315228753Smm		if (bsdtar->pending_chdir != NULL)
316228753Smm			sprintf(bsdtar->pending_chdir, "%s/%s",
317228753Smm			    old_pending, newdir);
318228753Smm		free(old_pending);
319228753Smm	}
320228753Smm	if (bsdtar->pending_chdir == NULL)
321228753Smm		lafe_errc(1, errno, "No memory");
322228753Smm}
323228753Smm
324228753Smmvoid
325228753Smmdo_chdir(struct bsdtar *bsdtar)
326228753Smm{
327228753Smm	if (bsdtar->pending_chdir == NULL)
328228753Smm		return;
329228753Smm
330228753Smm	if (chdir(bsdtar->pending_chdir) != 0) {
331228753Smm		lafe_errc(1, 0, "could not chdir to '%s'\n",
332228753Smm		    bsdtar->pending_chdir);
333228753Smm	}
334228753Smm	free(bsdtar->pending_chdir);
335228753Smm	bsdtar->pending_chdir = NULL;
336228753Smm}
337228753Smm
338228753Smmstatic const char *
339228753Smmstrip_components(const char *p, int elements)
340228753Smm{
341228753Smm	/* Skip as many elements as necessary. */
342228753Smm	while (elements > 0) {
343228753Smm		switch (*p++) {
344228753Smm		case '/':
345228753Smm#if defined(_WIN32) && !defined(__CYGWIN__)
346228753Smm		case '\\': /* Support \ path sep on Windows ONLY. */
347228753Smm#endif
348228753Smm			elements--;
349228753Smm			break;
350228753Smm		case '\0':
351228753Smm			/* Path is too short, skip it. */
352228753Smm			return (NULL);
353228753Smm		}
354228753Smm	}
355228753Smm
356228753Smm	/* Skip any / characters.  This handles short paths that have
357228753Smm	 * additional / termination.  This also handles the case where
358228753Smm	 * the logic above stops in the middle of a duplicate //
359228753Smm	 * sequence (which would otherwise get converted to an
360228753Smm	 * absolute path). */
361228753Smm	for (;;) {
362228753Smm		switch (*p) {
363228753Smm		case '/':
364228753Smm#if defined(_WIN32) && !defined(__CYGWIN__)
365228753Smm		case '\\': /* Support \ path sep on Windows ONLY. */
366228753Smm#endif
367228753Smm			++p;
368228753Smm			break;
369228753Smm		case '\0':
370228753Smm			return (NULL);
371228753Smm		default:
372228753Smm			return (p);
373228753Smm		}
374228753Smm	}
375228753Smm}
376228753Smm
377299529Smmstatic void
378299529Smmwarn_strip_leading_char(struct bsdtar *bsdtar, const char *c)
379299529Smm{
380299529Smm	if (!bsdtar->warned_lead_slash) {
381299529Smm		lafe_warnc(0,
382299529Smm			   "Removing leading '%c' from member names",
383299529Smm			   c[0]);
384299529Smm		bsdtar->warned_lead_slash = 1;
385299529Smm	}
386299529Smm}
387299529Smm
388299529Smmstatic void
389299529Smmwarn_strip_drive_letter(struct bsdtar *bsdtar)
390299529Smm{
391299529Smm	if (!bsdtar->warned_lead_slash) {
392299529Smm		lafe_warnc(0,
393299529Smm			   "Removing leading drive letter from "
394299529Smm			   "member names");
395299529Smm		bsdtar->warned_lead_slash = 1;
396299529Smm	}
397299529Smm}
398299529Smm
399299529Smm/*
400299529Smm * Convert absolute path to non-absolute path by skipping leading
401299529Smm * absolute path prefixes.
402299529Smm */
403270661Saestatic const char*
404299529Smmstrip_absolute_path(struct bsdtar *bsdtar, const char *p)
405270661Sae{
406299529Smm	const char *rp;
407270661Sae
408299529Smm	/* Remove leading "//./" or "//?/" or "//?/UNC/"
409299529Smm	 * (absolute path prefixes used by Windows API) */
410299529Smm	if ((p[0] == '/' || p[0] == '\\') &&
411299529Smm	    (p[1] == '/' || p[1] == '\\') &&
412299529Smm	    (p[2] == '.' || p[2] == '?') &&
413299529Smm	    (p[3] == '/' || p[3] == '\\'))
414299529Smm	{
415299529Smm		if (p[2] == '?' &&
416299529Smm		    (p[4] == 'U' || p[4] == 'u') &&
417299529Smm		    (p[5] == 'N' || p[5] == 'n') &&
418299529Smm		    (p[6] == 'C' || p[6] == 'c') &&
419299529Smm		    (p[7] == '/' || p[7] == '\\'))
420299529Smm			p += 8;
421299529Smm		else
422299529Smm			p += 4;
423299529Smm		warn_strip_drive_letter(bsdtar);
424270661Sae	}
425299529Smm
426299529Smm	/* Remove multiple leading slashes and Windows drive letters. */
427299529Smm	do {
428299529Smm		rp = p;
429299529Smm		if (((p[0] >= 'a' && p[0] <= 'z') ||
430299529Smm		     (p[0] >= 'A' && p[0] <= 'Z')) &&
431299529Smm		    p[1] == ':') {
432299529Smm			p += 2;
433299529Smm			warn_strip_drive_letter(bsdtar);
434299529Smm		}
435299529Smm
436299529Smm		/* Remove leading "/../", "/./", "//", etc. */
437299529Smm		while (p[0] == '/' || p[0] == '\\') {
438299529Smm			if (p[1] == '.' &&
439299529Smm			    p[2] == '.' &&
440299529Smm			    (p[3] == '/' || p[3] == '\\')) {
441299529Smm				p += 3; /* Remove "/..", leave "/" for next pass. */
442299529Smm			} else if (p[1] == '.' &&
443299529Smm				   (p[2] == '/' || p[2] == '\\')) {
444299529Smm				p += 2; /* Remove "/.", leave "/" for next pass. */
445299529Smm			} else
446299529Smm				p += 1; /* Remove "/". */
447299529Smm			warn_strip_leading_char(bsdtar, rp);
448299529Smm		}
449299529Smm	} while (rp != p);
450299529Smm
451270661Sae	return (p);
452270661Sae}
453270661Sae
454228753Smm/*
455228753Smm * Handle --strip-components and any future path-rewriting options.
456228753Smm * Returns non-zero if the pathname should not be extracted.
457228753Smm *
458299529Smm * Note: The rewrites are applied uniformly to pathnames and hardlink
459299529Smm * names but not to symlink bodies.  This is deliberate: Symlink
460299529Smm * bodies are not necessarily filenames.  Even when they are, they
461299529Smm * need to be interpreted relative to the directory containing them,
462299529Smm * so simple rewrites like this are rarely appropriate.
463299529Smm *
464228753Smm * TODO: Support pax-style regex path rewrites.
465228753Smm */
466228753Smmint
467228753Smmedit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
468228753Smm{
469228753Smm	const char *name = archive_entry_pathname(entry);
470299529Smm	const char *original_name = name;
471299529Smm	const char *hardlinkname = archive_entry_hardlink(entry);
472299529Smm	const char *original_hardlinkname = hardlinkname;
473248616Smm#if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H)
474228753Smm	char *subst_name;
475228753Smm	int r;
476228753Smm
477299529Smm	/* Apply user-specified substitution to pathname. */
478232153Smm	r = apply_substitution(bsdtar, name, &subst_name, 0, 0);
479228753Smm	if (r == -1) {
480228753Smm		lafe_warnc(0, "Invalid substitution, skipping entry");
481228753Smm		return 1;
482228753Smm	}
483228753Smm	if (r == 1) {
484228753Smm		archive_entry_copy_pathname(entry, subst_name);
485228753Smm		if (*subst_name == '\0') {
486228753Smm			free(subst_name);
487228753Smm			return -1;
488228753Smm		} else
489228753Smm			free(subst_name);
490228753Smm		name = archive_entry_pathname(entry);
491299529Smm		original_name = name;
492228753Smm	}
493228753Smm
494299529Smm	/* Apply user-specified substitution to hardlink target. */
495299529Smm	if (hardlinkname != NULL) {
496299529Smm		r = apply_substitution(bsdtar, hardlinkname, &subst_name, 0, 1);
497228753Smm		if (r == -1) {
498228753Smm			lafe_warnc(0, "Invalid substitution, skipping entry");
499228753Smm			return 1;
500228753Smm		}
501228753Smm		if (r == 1) {
502228753Smm			archive_entry_copy_hardlink(entry, subst_name);
503228753Smm			free(subst_name);
504228753Smm		}
505299529Smm		hardlinkname = archive_entry_hardlink(entry);
506299529Smm		original_hardlinkname = hardlinkname;
507228753Smm	}
508299529Smm
509299529Smm	/* Apply user-specified substitution to symlink body. */
510228753Smm	if (archive_entry_symlink(entry) != NULL) {
511232153Smm		r = apply_substitution(bsdtar, archive_entry_symlink(entry), &subst_name, 1, 0);
512228753Smm		if (r == -1) {
513228753Smm			lafe_warnc(0, "Invalid substitution, skipping entry");
514228753Smm			return 1;
515228753Smm		}
516228753Smm		if (r == 1) {
517228753Smm			archive_entry_copy_symlink(entry, subst_name);
518228753Smm			free(subst_name);
519228753Smm		}
520228753Smm	}
521228753Smm#endif
522228753Smm
523228753Smm	/* Strip leading dir names as per --strip-components option. */
524228753Smm	if (bsdtar->strip_components > 0) {
525228753Smm		name = strip_components(name, bsdtar->strip_components);
526228753Smm		if (name == NULL)
527228753Smm			return (1);
528228753Smm
529299529Smm		if (hardlinkname != NULL) {
530299529Smm			hardlinkname = strip_components(hardlinkname,
531228753Smm			    bsdtar->strip_components);
532299529Smm			if (hardlinkname == NULL)
533228753Smm				return (1);
534228753Smm		}
535228753Smm	}
536228753Smm
537315432Smm	if ((bsdtar->flags & OPTFLAG_ABSOLUTE_PATHS) == 0) {
538299529Smm		/* By default, don't write or restore absolute pathnames. */
539299529Smm		name = strip_absolute_path(bsdtar, name);
540299529Smm		if (*name == '\0')
541228753Smm			name = ".";
542270661Sae
543299529Smm		if (hardlinkname != NULL) {
544299529Smm			hardlinkname = strip_absolute_path(bsdtar, hardlinkname);
545299529Smm			if (*hardlinkname == '\0')
546270661Sae				return (1);
547270661Sae		}
548228753Smm	} else {
549228753Smm		/* Strip redundant leading '/' characters. */
550228753Smm		while (name[0] == '/' && name[1] == '/')
551228753Smm			name++;
552228753Smm	}
553228753Smm
554299529Smm	/* Replace name in archive_entry. */
555299529Smm	if (name != original_name) {
556299529Smm		archive_entry_copy_pathname(entry, name);
557228753Smm	}
558299529Smm	if (hardlinkname != original_hardlinkname) {
559299529Smm		archive_entry_copy_hardlink(entry, hardlinkname);
560299529Smm	}
561228753Smm	return (0);
562228753Smm}
563228753Smm
564228753Smm/*
565228753Smm * It would be nice to just use printf() for formatting large numbers,
566228753Smm * but the compatibility problems are quite a headache.  Hence the
567228753Smm * following simple utility function.
568228753Smm */
569228753Smmconst char *
570228753Smmtar_i64toa(int64_t n0)
571228753Smm{
572228753Smm	static char buff[24];
573232153Smm	uint64_t n = n0 < 0 ? -n0 : n0;
574228753Smm	char *p = buff + sizeof(buff);
575228753Smm
576228753Smm	*--p = '\0';
577228753Smm	do {
578228753Smm		*--p = '0' + (int)(n % 10);
579232153Smm	} while (n /= 10);
580228753Smm	if (n0 < 0)
581228753Smm		*--p = '-';
582228753Smm	return p;
583228753Smm}
584228753Smm
585228753Smm/*
586228753Smm * Like strcmp(), but try to be a little more aware of the fact that
587228753Smm * we're comparing two paths.  Right now, it just handles leading
588228753Smm * "./" and trailing '/' specially, so that "a/b/" == "./a/b"
589228753Smm *
590228753Smm * TODO: Make this better, so that "./a//b/./c/" == "a/b/c"
591228753Smm * TODO: After this works, push it down into libarchive.
592228753Smm * TODO: Publish the path normalization routines in libarchive so
593228753Smm * that bsdtar can normalize paths and use fast strcmp() instead
594228753Smm * of this.
595228753Smm *
596228753Smm * Note: This is currently only used within write.c, so should
597228753Smm * not handle \ path separators.
598228753Smm */
599228753Smm
600228753Smmint
601228753Smmpathcmp(const char *a, const char *b)
602228753Smm{
603228753Smm	/* Skip leading './' */
604228753Smm	if (a[0] == '.' && a[1] == '/' && a[2] != '\0')
605228753Smm		a += 2;
606228753Smm	if (b[0] == '.' && b[1] == '/' && b[2] != '\0')
607228753Smm		b += 2;
608228753Smm	/* Find the first difference, or return (0) if none. */
609228753Smm	while (*a == *b) {
610228753Smm		if (*a == '\0')
611228753Smm			return (0);
612228753Smm		a++;
613228753Smm		b++;
614228753Smm	}
615228753Smm	/*
616228753Smm	 * If one ends in '/' and the other one doesn't,
617228753Smm	 * they're the same.
618228753Smm	 */
619228753Smm	if (a[0] == '/' && a[1] == '\0' && b[0] == '\0')
620228753Smm		return (0);
621228753Smm	if (a[0] == '\0' && b[0] == '/' && b[1] == '\0')
622228753Smm		return (0);
623228753Smm	/* They're really different, return the correct sign. */
624228753Smm	return (*(const unsigned char *)a - *(const unsigned char *)b);
625228753Smm}
626299529Smm
627299529Smm#define PPBUFF_SIZE 1024
628299529Smmconst char *
629299529Smmpassphrase_callback(struct archive *a, void *_client_data)
630299529Smm{
631299529Smm	struct bsdtar *bsdtar = (struct bsdtar *)_client_data;
632299529Smm	(void)a; /* UNUSED */
633299529Smm
634299529Smm	if (bsdtar->ppbuff == NULL) {
635299529Smm		bsdtar->ppbuff = malloc(PPBUFF_SIZE);
636299529Smm		if (bsdtar->ppbuff == NULL)
637299529Smm			lafe_errc(1, errno, "Out of memory");
638299529Smm	}
639299529Smm	return lafe_readpassphrase("Enter passphrase:",
640299529Smm		bsdtar->ppbuff, PPBUFF_SIZE);
641299529Smm}
642299529Smm
643299529Smmvoid
644299529Smmpassphrase_free(char *ppbuff)
645299529Smm{
646299529Smm	if (ppbuff != NULL) {
647299529Smm		memset(ppbuff, 0, PPBUFF_SIZE);
648299529Smm		free(ppbuff);
649299529Smm	}
650299529Smm}
651299529Smm
652299529Smm/*
653299529Smm * Display information about the current file.
654299529Smm *
655299529Smm * The format here roughly duplicates the output of 'ls -l'.
656299529Smm * This is based on SUSv2, where 'tar tv' is documented as
657299529Smm * listing additional information in an "unspecified format,"
658299529Smm * and 'pax -l' is documented as using the same format as 'ls -l'.
659299529Smm */
660299529Smmvoid
661299529Smmlist_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
662299529Smm{
663299529Smm	char			 tmp[100];
664299529Smm	size_t			 w;
665299529Smm	const char		*p;
666299529Smm	const char		*fmt;
667299529Smm	time_t			 tim;
668299529Smm	static time_t		 now;
669358088Smm	struct tm		*ltime;
670358088Smm#if defined(HAVE_LOCALTIME_R) || defined(HAVE__LOCALTIME64_S)
671358088Smm	struct tm		tmbuf;
672358088Smm#endif
673358088Smm#if defined(HAVE__LOCALTIME64_S)
674358088Smm	errno_t			terr;
675358088Smm	__time64_t		tmptime;
676358088Smm#endif
677299529Smm
678299529Smm	/*
679299529Smm	 * We avoid collecting the entire list in memory at once by
680299529Smm	 * listing things as we see them.  However, that also means we can't
681299529Smm	 * just pre-compute the field widths.  Instead, we start with guesses
682299529Smm	 * and just widen them as necessary.  These numbers are completely
683299529Smm	 * arbitrary.
684299529Smm	 */
685299529Smm	if (!bsdtar->u_width) {
686299529Smm		bsdtar->u_width = 6;
687299529Smm		bsdtar->gs_width = 13;
688299529Smm	}
689299529Smm	if (!now)
690299529Smm		time(&now);
691299529Smm	fprintf(out, "%s %d ",
692299529Smm	    archive_entry_strmode(entry),
693299529Smm	    archive_entry_nlink(entry));
694299529Smm
695299529Smm	/* Use uname if it's present, else uid. */
696299529Smm	p = archive_entry_uname(entry);
697299529Smm	if ((p == NULL) || (*p == '\0')) {
698299529Smm		sprintf(tmp, "%lu ",
699299529Smm		    (unsigned long)archive_entry_uid(entry));
700299529Smm		p = tmp;
701299529Smm	}
702299529Smm	w = strlen(p);
703299529Smm	if (w > bsdtar->u_width)
704299529Smm		bsdtar->u_width = w;
705299529Smm	fprintf(out, "%-*s ", (int)bsdtar->u_width, p);
706299529Smm
707299529Smm	/* Use gname if it's present, else gid. */
708299529Smm	p = archive_entry_gname(entry);
709299529Smm	if (p != NULL && p[0] != '\0') {
710299529Smm		fprintf(out, "%s", p);
711299529Smm		w = strlen(p);
712299529Smm	} else {
713299529Smm		sprintf(tmp, "%lu",
714299529Smm		    (unsigned long)archive_entry_gid(entry));
715299529Smm		w = strlen(tmp);
716299529Smm		fprintf(out, "%s", tmp);
717299529Smm	}
718299529Smm
719299529Smm	/*
720299529Smm	 * Print device number or file size, right-aligned so as to make
721299529Smm	 * total width of group and devnum/filesize fields be gs_width.
722299529Smm	 * If gs_width is too small, grow it.
723299529Smm	 */
724299529Smm	if (archive_entry_filetype(entry) == AE_IFCHR
725299529Smm	    || archive_entry_filetype(entry) == AE_IFBLK) {
726299529Smm		sprintf(tmp, "%lu,%lu",
727299529Smm		    (unsigned long)archive_entry_rdevmajor(entry),
728299529Smm		    (unsigned long)archive_entry_rdevminor(entry));
729299529Smm	} else {
730299529Smm		strcpy(tmp, tar_i64toa(archive_entry_size(entry)));
731299529Smm	}
732299529Smm	if (w + strlen(tmp) >= bsdtar->gs_width)
733299529Smm		bsdtar->gs_width = w+strlen(tmp)+1;
734299529Smm	fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp);
735299529Smm
736299529Smm	/* Format the time using 'ls -l' conventions. */
737299529Smm	tim = archive_entry_mtime(entry);
738299529Smm#define	HALF_YEAR (time_t)365 * 86400 / 2
739299529Smm#if defined(_WIN32) && !defined(__CYGWIN__)
740299529Smm#define	DAY_FMT  "%d"  /* Windows' strftime function does not support %e format. */
741299529Smm#else
742299529Smm#define	DAY_FMT  "%e"  /* Day number without leading zeros */
743299529Smm#endif
744299529Smm	if (tim < now - HALF_YEAR || tim > now + HALF_YEAR)
745299529Smm		fmt = bsdtar->day_first ? DAY_FMT " %b  %Y" : "%b " DAY_FMT "  %Y";
746299529Smm	else
747299529Smm		fmt = bsdtar->day_first ? DAY_FMT " %b %H:%M" : "%b " DAY_FMT " %H:%M";
748358088Smm#if defined(HAVE_LOCALTIME_R)
749358088Smm	ltime = localtime_r(&tim, &tmbuf);
750358088Smm#elif defined(HAVE__LOCALTIME64_S)
751358088Smm	tmptime = tim;
752358088Smm	terr = _localtime64_s(&tmbuf, &tmptime);
753358088Smm	if (terr)
754358088Smm		ltime = NULL;
755358088Smm	else
756358088Smm		ltime = &tmbuf;
757358088Smm#else
758358088Smm	ltime = localtime(&tim);
759358088Smm#endif
760358088Smm	strftime(tmp, sizeof(tmp), fmt, ltime);
761299529Smm	fprintf(out, " %s ", tmp);
762299529Smm	safe_fprintf(out, "%s", archive_entry_pathname(entry));
763299529Smm
764299529Smm	/* Extra information for links. */
765299529Smm	if (archive_entry_hardlink(entry)) /* Hard link */
766299529Smm		safe_fprintf(out, " link to %s",
767299529Smm		    archive_entry_hardlink(entry));
768299529Smm	else if (archive_entry_symlink(entry)) /* Symbolic link */
769299529Smm		safe_fprintf(out, " -> %s", archive_entry_symlink(entry));
770299529Smm}
771