2
* Copyright (c) 2003-2004 Tim Kientzle
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer
10
* in this position and unchanged.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
#include "bsdtar_platform.h"
28
__FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.14 2006/03/21 17:03:51 kientzle Exp $");
31
#include <sys/types.h> /* Linux doesn't define mode_t, etc. in sys/stat.h. */
41
static void bsdtar_vwarnc(struct bsdtar *, int code,
42
const char *fmt, va_list ap);
45
* Print a string, taking care with any non-printable characters.
49
safe_fprintf(FILE *f, const char *fmt, ...)
61
/* Use a stack-allocated buffer if we can, for speed and safety. */
63
buff_length = sizeof(buff_stack);
67
length = vsnprintf(buff, buff_length, fmt, ap);
69
/* If the result is too large, allocate a buffer on the heap. */
70
if (length >= buff_length) {
71
buff_length = length+1;
72
buff_heap = malloc(buff_length);
73
/* Failsafe: use the truncated string if malloc fails. */
74
if (buff_heap != NULL) {
77
length = vsnprintf(buff, buff_length, fmt, ap);
82
/* Write data, expanding unprintable characters. */
86
unsigned char c = *p++;
88
if (isprint(c) && c != '\\')
91
copy_buff[i++] = '\\';
93
case '\a': copy_buff[i++] = 'a'; break;
94
case '\b': copy_buff[i++] = 'b'; break;
95
case '\f': copy_buff[i++] = 'f'; break;
96
case '\n': copy_buff[i++] = 'n'; break;
98
/* On some platforms, \n and \r are the same. */
99
case '\r': copy_buff[i++] = 'r'; break;
101
case '\t': copy_buff[i++] = 't'; break;
102
case '\v': copy_buff[i++] = 'v'; break;
103
case '\\': copy_buff[i++] = '\\'; break;
105
sprintf(copy_buff + i, "%03o", c);
110
/* If our temp buffer is full, dump it and keep going. */
111
if (i > (sizeof(copy_buff) - 8)) {
112
copy_buff[i++] = '\0';
113
fprintf(f, "%s", copy_buff);
117
copy_buff[i++] = '\0';
118
fprintf(f, "%s", copy_buff);
120
/* If we allocated a heap-based buffer, free it now. */
121
if (buff_heap != NULL)
126
bsdtar_vwarnc(struct bsdtar *bsdtar, int code, const char *fmt, va_list ap)
128
fprintf(stderr, "%s: ", bsdtar->progname);
129
vfprintf(stderr, fmt, ap);
131
fprintf(stderr, ": %s", strerror(code));
132
fprintf(stderr, "\n");
136
bsdtar_warnc(struct bsdtar *bsdtar, int code, const char *fmt, ...)
141
bsdtar_vwarnc(bsdtar, code, fmt, ap);
146
bsdtar_errc(struct bsdtar *bsdtar, int eval, int code, const char *fmt, ...)
151
bsdtar_vwarnc(bsdtar, code, fmt, ap);
157
yes(const char *fmt, ...)
165
vfprintf(stderr, fmt, ap);
167
fprintf(stderr, " (y/N)? ");
170
l = read(2, buff, sizeof(buff));
175
for (p = buff; *p != '\0'; p++) {
176
if (isspace(0xff & (int)*p))
192
bsdtar_strmode(struct archive_entry *entry, char *bp)
194
static const char *perms = "?rwxrwxrwx ";
195
static const mode_t permbits[] =
196
{ S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP,
197
S_IROTH, S_IWOTH, S_IXOTH };
201
/* Fill in a default string, then selectively override. */
204
mode = archive_entry_mode(entry);
205
switch (mode & S_IFMT) {
206
case S_IFREG: bp[0] = '-'; break;
207
case S_IFBLK: bp[0] = 'b'; break;
208
case S_IFCHR: bp[0] = 'c'; break;
209
case S_IFDIR: bp[0] = 'd'; break;
210
case S_IFLNK: bp[0] = 'l'; break;
211
case S_IFSOCK: bp[0] = 's'; break;
213
case S_IFIFO: bp[0] = 'p'; break;
216
case S_IFWHT: bp[0] = 'w'; break;
220
for (i = 0; i < 9; i++)
221
if (!(mode & permbits[i]))
224
if (mode & S_ISUID) {
225
if (mode & S_IXUSR) bp[3] = 's';
228
if (mode & S_ISGID) {
229
if (mode & S_IXGRP) bp[6] = 's';
232
if (mode & S_ISVTX) {
233
if (mode & S_IXOTH) bp[9] = 't';
236
if (archive_entry_acl_count(entry, ARCHIVE_ENTRY_ACL_TYPE_ACCESS))
242
* Read lines from file and do something with each one. If option_null
243
* is set, lines are terminated with zero bytes; otherwise, they're
244
* terminated with newlines.
246
* This uses a self-sizing buffer to handle arbitrarily-long lines.
247
* If the "process" function returns non-zero for any line, this
248
* function will return non-zero after attempting to process all
252
process_lines(struct bsdtar *bsdtar, const char *pathname,
253
int (*process)(struct bsdtar *, const char *))
256
char *buff, *buff_end, *line_start, *line_end, *p;
257
size_t buff_length, bytes_read, bytes_wanted;
261
separator = bsdtar->option_null ? '\0' : '\n';
264
if (strcmp(pathname, "-") == 0)
267
f = fopen(pathname, "r");
269
bsdtar_errc(bsdtar, 1, errno, "Couldn't open %s", pathname);
271
buff = malloc(buff_length);
273
bsdtar_errc(bsdtar, 1, ENOMEM, "Can't read %s", pathname);
274
line_start = line_end = buff_end = buff;
276
/* Get some more data into the buffer. */
277
bytes_wanted = buff + buff_length - buff_end;
278
bytes_read = fread(buff_end, 1, bytes_wanted, f);
279
buff_end += bytes_read;
280
/* Process all complete lines in the buffer. */
281
while (line_end < buff_end) {
282
if (*line_end == separator) {
284
if ((*process)(bsdtar, line_start) != 0)
286
line_start = line_end + 1;
287
line_end = line_start;
294
bsdtar_errc(bsdtar, 1, errno,
295
"Can't read %s", pathname);
296
if (line_start > buff) {
297
/* Move a leftover fractional line to the beginning. */
298
memmove(buff, line_start, buff_end - line_start);
299
buff_end -= line_start - buff;
300
line_end -= line_start - buff;
303
/* Line is too big; enlarge the buffer. */
304
p = realloc(buff, buff_length *= 2);
306
bsdtar_errc(bsdtar, 1, ENOMEM,
307
"Line too long in %s", pathname);
308
buff_end = p + (buff_end - buff);
309
line_end = p + (line_end - buff);
310
line_start = buff = p;
313
/* At end-of-file, handle the final line. */
314
if (line_end > line_start) {
316
if ((*process)(bsdtar, line_start) != 0)
326
* The logic here for -C <dir> attempts to avoid
327
* chdir() as long as possible. For example:
328
* "-C /foo -C /bar file" needs chdir("/bar") but not chdir("/foo")
329
* "-C /foo -C bar file" needs chdir("/foo/bar")
330
* "-C /foo -C bar /file1" does not need chdir()
331
* "-C /foo -C bar /file1 file2" needs chdir("/foo/bar") before file2
333
* The only correct way to handle this is to record a "pending" chdir
334
* request and combine multiple requests intelligently until we
335
* need to process a non-absolute file. set_chdir() adds the new dir
336
* to the pending list; do_chdir() actually executes any pending chdir.
338
* This way, programs that build tar command lines don't have to worry
339
* about -C with non-existent directories; such requests will only
340
* fail if the directory must be accessed.
343
set_chdir(struct bsdtar *bsdtar, const char *newdir)
345
if (newdir[0] == '/') {
346
/* The -C /foo -C /bar case; dump first one. */
347
free(bsdtar->pending_chdir);
348
bsdtar->pending_chdir = NULL;
350
if (bsdtar->pending_chdir == NULL)
351
/* Easy case: no previously-saved dir. */
352
bsdtar->pending_chdir = strdup(newdir);
354
/* The -C /foo -C bar case; concatenate */
355
char *old_pending = bsdtar->pending_chdir;
356
size_t old_len = strlen(old_pending);
357
bsdtar->pending_chdir = malloc(old_len + strlen(newdir) + 2);
358
if (old_pending[old_len - 1] == '/')
359
old_pending[old_len - 1] = '\0';
360
if (bsdtar->pending_chdir != NULL)
361
sprintf(bsdtar->pending_chdir, "%s/%s",
362
old_pending, newdir);
365
if (bsdtar->pending_chdir == NULL)
366
bsdtar_errc(bsdtar, 1, errno, "No memory");
370
do_chdir(struct bsdtar *bsdtar)
372
if (bsdtar->pending_chdir == NULL)
375
if (chdir(bsdtar->pending_chdir) != 0) {
376
bsdtar_errc(bsdtar, 1, 0, "could not chdir to '%s'\n",
377
bsdtar->pending_chdir);
379
free(bsdtar->pending_chdir);
380
bsdtar->pending_chdir = NULL;
384
* Handle --strip-components and any future path-rewriting options.
385
* Returns non-zero if the pathname should not be extracted.
388
edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
390
const char *name = archive_entry_pathname(entry);
392
/* Strip leading dir names as per --strip-components option. */
393
if (bsdtar->strip_components > 0) {
394
int r = bsdtar->strip_components;
395
const char *p = name;
404
/* Path is too short, skip it. */
410
/* Strip redundant "./" from start of filename. */
411
if (name[0] == '.' && name[1] == '/' && name[2] != '\0')
414
/* Strip redundant leading '/' characters. */
415
while (name[0] == '/' && name[1] == '/')
418
/* Strip leading '/' unless user has asked us not to. */
419
if (name[0] == '/' && !bsdtar->option_absolute_paths) {
420
/* Generate a warning the first time this happens. */
421
if (!bsdtar->warned_lead_slash) {
422
bsdtar_warnc(bsdtar, 0,
423
"Removing leading '/' from member names");
424
bsdtar->warned_lead_slash = 1;
427
/* Special case: Stripping leading '/' from "/" yields ".". */
432
/* Safely replace name in archive_entry. */
433
if (name != archive_entry_pathname(entry)) {
434
char *q = strdup(name);
435
archive_entry_copy_pathname(entry, q);