Update bsdtar to 2.8.4

Use common code from lib/libarchive/libarchive_fe

Approved by:	kientzle
MFC after:	2 weeks
This commit is contained in:
Martin Matuska 2011-07-17 21:33:15 +00:00
parent 38abb26b5a
commit 2ad1419f1b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224153
36 changed files with 2646 additions and 2194 deletions

View File

@ -2,21 +2,24 @@
.include <bsd.own.mk>
PROG= bsdtar
BSDTAR_VERSION_STRING=2.8.3
BSDTAR_VERSION_STRING=2.8.4
SRCS= bsdtar.c \
cmdline.c \
err.c \
getdate.c \
line_reader.c \
matching.c \
pathmatch.c \
read.c \
subst.c \
tree.c \
util.c \
write.c
DPADD= ${LIBARCHIVE} ${LIBBZ2} ${LIBZ} ${LIBMD} ${LIBLZMA}
LDADD= -larchive -lbz2 -lz -lmd -llzma
.PATH: ${.CURDIR}/../../lib/libarchive/libarchive_fe
SRCS+= err.c \
line_reader.c \
matching.c \
pathmatch.c
DPADD= ${LIBARCHIVE} ${LIBBZ2} ${LIBZ} ${LIBMD} ${LIBLZMA} ${LIBBSDXML}
LDADD= -larchive -lbz2 -lz -lmd -llzma -lbsdxml
.if ${MK_OPENSSL} != "no"
DPADD+= ${LIBCRYPTO}
LDADD+= -lcrypto
@ -24,6 +27,7 @@ LDADD+= -lcrypto
CFLAGS+= -DBSDTAR_VERSION_STRING=\"${BSDTAR_VERSION_STRING}\"
CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\"
CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../../lib/libarchive
CFLAGS+= -I${.CURDIR}/../../lib/libarchive/libarchive_fe
SYMLINKS= bsdtar ${BINDIR}/tar
MLINKS= bsdtar.1 tar.1
DEBUG_FLAGS=-g

View File

@ -50,8 +50,8 @@
.Sh DESCRIPTION
.Nm
creates and manipulates streaming archive files.
This implementation can extract from tar, pax, cpio, zip, jar, ar,
xar, and ISO 9660 cdrom images and can create tar, pax, cpio, ar, zip,
This implementation can extract from tar, pax, cpio, zip, jar, ar, xar,
rpm and ISO 9660 cdrom images and can create tar, pax, cpio, ar, zip,
and shar archives.
.Pp
The first synopsis form shows a

View File

@ -63,6 +63,9 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ZLIB_H
#include <zlib.h>
#endif
#include "bsdtar.h"
#include "err.h"
@ -86,6 +89,8 @@ __FBSDID("$FreeBSD$");
int _CRT_glob = 0; /* Disable broken CRT globbing. */
#endif
static struct bsdtar *_bsdtar;
#if defined(HAVE_SIGACTION) && (defined(SIGINFO) || defined(SIGUSR1))
static volatile int siginfo_occurred;
@ -139,7 +144,7 @@ main(int argc, char **argv)
* Use a pointer for consistency, but stack-allocated storage
* for ease of cleanup.
*/
bsdtar = &bsdtar_storage;
_bsdtar = bsdtar = &bsdtar_storage;
memset(bsdtar, 0, sizeof(*bsdtar));
bsdtar->fd = -1; /* Mark as "unused" */
option_o = 0;
@ -152,36 +157,36 @@ main(int argc, char **argv)
sa.sa_flags = 0;
#ifdef SIGINFO
if (sigaction(SIGINFO, &sa, NULL))
bsdtar_errc(1, errno, "sigaction(SIGINFO) failed");
lafe_errc(1, errno, "sigaction(SIGINFO) failed");
#endif
#ifdef SIGUSR1
/* ... and treat SIGUSR1 the same way as SIGINFO. */
if (sigaction(SIGUSR1, &sa, NULL))
bsdtar_errc(1, errno, "sigaction(SIGUSR1) failed");
lafe_errc(1, errno, "sigaction(SIGUSR1) failed");
#endif
}
#endif
/* Need bsdtar_progname before calling bsdtar_warnc. */
/* Need lafe_progname before calling lafe_warnc. */
if (*argv == NULL)
bsdtar_progname = "bsdtar";
lafe_progname = "bsdtar";
else {
#if defined(_WIN32) && !defined(__CYGWIN__)
bsdtar_progname = strrchr(*argv, '\\');
lafe_progname = strrchr(*argv, '\\');
#else
bsdtar_progname = strrchr(*argv, '/');
lafe_progname = strrchr(*argv, '/');
#endif
if (bsdtar_progname != NULL)
bsdtar_progname++;
if (lafe_progname != NULL)
lafe_progname++;
else
bsdtar_progname = *argv;
lafe_progname = *argv;
}
time(&now);
#if HAVE_SETLOCALE
if (setlocale(LC_ALL, "") == NULL)
bsdtar_warnc(0, "Failed to set default locale");
lafe_warnc(0, "Failed to set default locale");
#endif
#if defined(HAVE_NL_LANGINFO) && defined(HAVE_D_MD_ORDER)
bsdtar->day_first = (*nl_langinfo(D_MD_ORDER) == 'd');
@ -233,7 +238,7 @@ main(int argc, char **argv)
case 'b': /* SUSv2 */
t = atoi(bsdtar->optarg);
if (t <= 0 || t > 8192)
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Argument to -b is out of range (1..8192)");
bsdtar->bytes_per_block = 512 * t;
break;
@ -251,7 +256,7 @@ main(int argc, char **argv)
break;
case OPTION_EXCLUDE: /* GNU tar */
if (lafe_exclude(&bsdtar->matching, bsdtar->optarg))
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Couldn't exclude %s\n", bsdtar->optarg);
break;
case OPTION_FORMAT: /* GNU tar, others */
@ -297,20 +302,20 @@ main(int argc, char **argv)
* when transforming archives.
*/
if (lafe_include(&bsdtar->matching, bsdtar->optarg))
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Failed to add %s to inclusion list",
bsdtar->optarg);
break;
case 'j': /* GNU tar */
if (bsdtar->create_compression != '\0')
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Can't specify both -%c and -%c", opt,
bsdtar->create_compression);
bsdtar->create_compression = opt;
break;
case 'J': /* GNU tar 1.21 and later */
if (bsdtar->create_compression != '\0')
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Can't specify both -%c and -%c", opt,
bsdtar->create_compression);
bsdtar->create_compression = opt;
@ -330,7 +335,7 @@ main(int argc, char **argv)
break;
case OPTION_LZMA:
if (bsdtar->create_compression != '\0')
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Can't specify both -%c and -%c", opt,
bsdtar->create_compression);
bsdtar->create_compression = opt;
@ -355,7 +360,7 @@ main(int argc, char **argv)
{
struct stat st;
if (stat(bsdtar->optarg, &st) != 0)
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Can't open file %s", bsdtar->optarg);
bsdtar->newer_ctime_sec = st.st_ctime;
bsdtar->newer_ctime_nsec =
@ -369,7 +374,7 @@ main(int argc, char **argv)
{
struct stat st;
if (stat(bsdtar->optarg, &st) != 0)
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Can't open file %s", bsdtar->optarg);
bsdtar->newer_mtime_sec = st.st_mtime;
bsdtar->newer_mtime_nsec =
@ -440,7 +445,7 @@ main(int argc, char **argv)
#if HAVE_REGEX_H
add_substitution(bsdtar, bsdtar->optarg);
#else
bsdtar_warnc(0,
lafe_warnc(0,
"-s is not supported by this version of bsdtar");
usage();
#endif
@ -487,7 +492,7 @@ main(int argc, char **argv)
break;
case 'X': /* GNU tar */
if (lafe_exclude_from_file(&bsdtar->matching, bsdtar->optarg))
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"failed to process exclusions from file %s",
bsdtar->optarg);
break;
@ -496,21 +501,21 @@ main(int argc, char **argv)
break;
case 'y': /* FreeBSD version of GNU tar */
if (bsdtar->create_compression != '\0')
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Can't specify both -%c and -%c", opt,
bsdtar->create_compression);
bsdtar->create_compression = opt;
break;
case 'Z': /* GNU tar */
if (bsdtar->create_compression != '\0')
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Can't specify both -%c and -%c", opt,
bsdtar->create_compression);
bsdtar->create_compression = opt;
break;
case 'z': /* GNU tar, star, many others */
if (bsdtar->create_compression != '\0')
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Can't specify both -%c and -%c", opt,
bsdtar->create_compression);
bsdtar->create_compression = opt;
@ -535,7 +540,7 @@ main(int argc, char **argv)
/* Otherwise, a mode is required. */
if (bsdtar->mode == '\0')
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Must specify one of -c, -r, -t, -u, -x");
/* Check boolean options only permitted in certain modes. */
@ -615,7 +620,7 @@ main(int argc, char **argv)
#endif
if (bsdtar->return_value != 0)
bsdtar_warnc(0,
lafe_warnc(0,
"Error exit delayed from previous errors.");
return (bsdtar->return_value);
}
@ -624,7 +629,7 @@ static void
set_mode(struct bsdtar *bsdtar, char opt)
{
if (bsdtar->mode != '\0' && bsdtar->mode != opt)
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Can't specify both -%c and -%c", opt, bsdtar->mode);
bsdtar->mode = opt;
}
@ -636,7 +641,7 @@ static void
only_mode(struct bsdtar *bsdtar, const char *opt, const char *valid_modes)
{
if (strchr(valid_modes, bsdtar->mode) == NULL)
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Option %s is not permitted in mode -%c",
opt, bsdtar->mode);
}
@ -647,7 +652,7 @@ usage(void)
{
const char *p;
p = bsdtar_progname;
p = lafe_progname;
fprintf(stderr, "Usage:\n");
fprintf(stderr, " List: %s -tf <archive-filename>\n", p);
@ -707,7 +712,7 @@ long_help(void)
const char *prog;
const char *p;
prog = bsdtar_progname;
prog = lafe_progname;
fflush(stderr);

View File

@ -221,7 +221,7 @@ bsdtar_getopt(struct bsdtar *bsdtar)
if (p[1] == ':') {
bsdtar->optarg = *bsdtar->argv;
if (bsdtar->optarg == NULL) {
bsdtar_warnc(0,
lafe_warnc(0,
"Option %c requires an argument",
opt);
return ('?');
@ -288,7 +288,7 @@ bsdtar_getopt(struct bsdtar *bsdtar)
/* Otherwise, pick up the next word. */
opt_word = *bsdtar->argv;
if (opt_word == NULL) {
bsdtar_warnc(0,
lafe_warnc(0,
"Option -%c requires an argument",
opt);
return ('?');
@ -339,13 +339,13 @@ bsdtar_getopt(struct bsdtar *bsdtar)
/* Fail if there wasn't a unique match. */
if (match == NULL) {
bsdtar_warnc(0,
lafe_warnc(0,
"Option %s%s is not supported",
long_prefix, opt_word);
return ('?');
}
if (match2 != NULL) {
bsdtar_warnc(0,
lafe_warnc(0,
"Ambiguous option %s%s (matches --%s and --%s)",
long_prefix, opt_word, match->name, match2->name);
return ('?');
@ -357,7 +357,7 @@ bsdtar_getopt(struct bsdtar *bsdtar)
if (bsdtar->optarg == NULL) {
bsdtar->optarg = *bsdtar->argv;
if (bsdtar->optarg == NULL) {
bsdtar_warnc(0,
lafe_warnc(0,
"Option %s%s requires an argument",
long_prefix, match->name);
return ('?');
@ -368,7 +368,7 @@ bsdtar_getopt(struct bsdtar *bsdtar)
} else {
/* Argument forbidden: fail if there is one. */
if (bsdtar->optarg != NULL) {
bsdtar_warnc(0,
lafe_warnc(0,
"Option %s%s does not allow an argument",
long_prefix, match->name);
return ('?');

View File

@ -44,6 +44,7 @@
#undef HAVE_LIBACL
#define HAVE_LIBARCHIVE 1
#define HAVE_LIMITS_H 1
#define HAVE_LINK 1
#undef HAVE_LINUX_EXT2_FS_H
#undef HAVE_LINUX_FS_H
#define HAVE_LOCALE_H 1
@ -77,5 +78,5 @@
#define HAVE_TIME_H 1
#define HAVE_UNISTD_H 1
#define HAVE_WCTYPE_H 1
#define HAVE_WCSCMP 1
#undef HAVE_WINDOWS_H

View File

@ -1,74 +0,0 @@
/*-
* Copyright (c) 2003-2010 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "bsdtar_platform.h"
__FBSDID("$FreeBSD$");
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "err.h"
const char *bsdtar_progname;
static void
bsdtar_vwarnc(int code, const char *fmt, va_list ap)
{
fprintf(stderr, "%s: ", bsdtar_progname);
vfprintf(stderr, fmt, ap);
if (code != 0)
fprintf(stderr, ": %s", strerror(code));
fprintf(stderr, "\n");
}
void
bsdtar_warnc(int code, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
bsdtar_vwarnc(code, fmt, ap);
va_end(ap);
}
void
bsdtar_errc(int eval, int code, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
bsdtar_vwarnc(code, fmt, ap);
va_end(ap);
exit(eval);
}

View File

@ -1,171 +0,0 @@
/*-
* Copyright (c) 2008 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "bsdtar_platform.h"
__FBSDID("$FreeBSD$");
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "err.h"
#include "line_reader.h"
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__)
#define strdup _strdup
#endif
/*
* Read lines from file and do something with each one. If option_null
* is set, lines are terminated with zero bytes; otherwise, they're
* terminated with newlines.
*
* This uses a self-sizing buffer to handle arbitrarily-long lines.
*/
struct lafe_line_reader {
FILE *f;
char *buff, *buff_end, *line_start, *line_end, *p;
char *pathname;
size_t buff_length;
int nullSeparator; /* Lines separated by null, not CR/CRLF/etc. */
int ret;
};
struct lafe_line_reader *
lafe_line_reader(const char *pathname, int nullSeparator)
{
struct lafe_line_reader *lr;
lr = calloc(1, sizeof(*lr));
if (lr == NULL)
bsdtar_errc(1, ENOMEM, "Can't open %s", pathname);
lr->nullSeparator = nullSeparator;
lr->pathname = strdup(pathname);
if (strcmp(pathname, "-") == 0)
lr->f = stdin;
else
lr->f = fopen(pathname, "r");
if (lr->f == NULL)
bsdtar_errc(1, errno, "Couldn't open %s", pathname);
lr->buff_length = 8192;
lr->buff = malloc(lr->buff_length);
if (lr->buff == NULL)
bsdtar_errc(1, ENOMEM, "Can't read %s", pathname);
lr->line_start = lr->line_end = lr->buff_end = lr->buff;
return (lr);
}
const char *
lafe_line_reader_next(struct lafe_line_reader *lr)
{
size_t bytes_wanted, bytes_read, new_buff_size;
char *line_start, *p;
for (;;) {
/* If there's a line in the buffer, return it immediately. */
while (lr->line_end < lr->buff_end) {
if (lr->nullSeparator) {
if (*lr->line_end == '\0') {
line_start = lr->line_start;
lr->line_start = lr->line_end + 1;
lr->line_end = lr->line_start;
return (line_start);
}
} else if (*lr->line_end == '\x0a' || *lr->line_end == '\x0d') {
*lr->line_end = '\0';
line_start = lr->line_start;
lr->line_start = lr->line_end + 1;
lr->line_end = lr->line_start;
if (line_start[0] != '\0')
return (line_start);
}
lr->line_end++;
}
/* If we're at end-of-file, process the final data. */
if (lr->f == NULL) {
/* If there's more text, return one last line. */
if (lr->line_end > lr->line_start) {
*lr->line_end = '\0';
line_start = lr->line_start;
lr->line_start = lr->line_end + 1;
lr->line_end = lr->line_start;
return (line_start);
}
/* Otherwise, we're done. */
return (NULL);
}
/* Buffer only has part of a line. */
if (lr->line_start > lr->buff) {
/* Move a leftover fractional line to the beginning. */
memmove(lr->buff, lr->line_start,
lr->buff_end - lr->line_start);
lr->buff_end -= lr->line_start - lr->buff;
lr->line_end -= lr->line_start - lr->buff;
lr->line_start = lr->buff;
} else {
/* Line is too big; enlarge the buffer. */
new_buff_size = lr->buff_length * 2;
if (new_buff_size <= lr->buff_length)
bsdtar_errc(1, ENOMEM,
"Line too long in %s", lr->pathname);
lr->buff_length = new_buff_size;
p = realloc(lr->buff, new_buff_size);
if (p == NULL)
bsdtar_errc(1, ENOMEM,
"Line too long in %s", lr->pathname);
lr->buff_end = p + (lr->buff_end - lr->buff);
lr->line_end = p + (lr->line_end - lr->buff);
lr->line_start = lr->buff = p;
}
/* Get some more data into the buffer. */
bytes_wanted = lr->buff + lr->buff_length - lr->buff_end;
bytes_read = fread(lr->buff_end, 1, bytes_wanted, lr->f);
lr->buff_end += bytes_read;
if (ferror(lr->f))
bsdtar_errc(1, errno, "Can't read %s", lr->pathname);
if (feof(lr->f)) {
if (lr->f != stdin)
fclose(lr->f);
lr->f = NULL;
}
}
}
void
lafe_line_reader_free(struct lafe_line_reader *lr)
{
free(lr->buff);
free(lr->pathname);
free(lr);
}

View File

@ -1,37 +0,0 @@
/*-
* Copyright (c) 2009 Joerg Sonnenberger
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef LAFE_LINE_READER_H
#define LAFE_LINE_READER_H
struct lafe_line_reader;
struct lafe_line_reader *lafe_line_reader(const char *, int nullSeparator);
const char *lafe_line_reader_next(struct lafe_line_reader *);
void lafe_line_reader_free(struct lafe_line_reader *);
#endif

View File

@ -1,281 +0,0 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "bsdtar_platform.h"
__FBSDID("$FreeBSD$");
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "err.h"
#include "line_reader.h"
#include "matching.h"
#include "pathmatch.h"
struct match {
struct match *next;
int matches;
char pattern[1];
};
struct lafe_matching {
struct match *exclusions;
int exclusions_count;
struct match *inclusions;
int inclusions_count;
int inclusions_unmatched_count;
};
static void add_pattern(struct match **list, const char *pattern);
static void initialize_matching(struct lafe_matching **);
static int match_exclusion(struct match *, const char *pathname);
static int match_inclusion(struct match *, const char *pathname);
/*
* The matching logic here needs to be re-thought. I started out to
* try to mimic gtar's matching logic, but it's not entirely
* consistent. In particular 'tar -t' and 'tar -x' interpret patterns
* on the command line as anchored, but --exclude doesn't.
*/
/*
* Utility functions to manage exclusion/inclusion patterns
*/
int
lafe_exclude(struct lafe_matching **matching, const char *pattern)
{
if (*matching == NULL)
initialize_matching(matching);
add_pattern(&((*matching)->exclusions), pattern);
(*matching)->exclusions_count++;
return (0);
}
int
lafe_exclude_from_file(struct lafe_matching **matching, const char *pathname)
{
struct lafe_line_reader *lr;
const char *p;
int ret = 0;
lr = lafe_line_reader(pathname, 0);
while ((p = lafe_line_reader_next(lr)) != NULL) {
if (lafe_exclude(matching, p) != 0)
ret = -1;
}
lafe_line_reader_free(lr);
return (ret);
}
int
lafe_include(struct lafe_matching **matching, const char *pattern)
{
if (*matching == NULL)
initialize_matching(matching);
add_pattern(&((*matching)->inclusions), pattern);
(*matching)->inclusions_count++;
(*matching)->inclusions_unmatched_count++;
return (0);
}
int
lafe_include_from_file(struct lafe_matching **matching, const char *pathname,
int nullSeparator)
{
struct lafe_line_reader *lr;
const char *p;
int ret = 0;
lr = lafe_line_reader(pathname, nullSeparator);
while ((p = lafe_line_reader_next(lr)) != NULL) {
if (lafe_include(matching, p) != 0)
ret = -1;
}
lafe_line_reader_free(lr);
return (ret);
}
static void
add_pattern(struct match **list, const char *pattern)
{
struct match *match;
size_t len;
len = strlen(pattern);
match = malloc(sizeof(*match) + len + 1);
if (match == NULL)
bsdtar_errc(1, errno, "Out of memory");
strcpy(match->pattern, pattern);
/* Both "foo/" and "foo" should match "foo/bar". */
if (len && match->pattern[len - 1] == '/')
match->pattern[strlen(match->pattern)-1] = '\0';
match->next = *list;
*list = match;
match->matches = 0;
}
int
lafe_excluded(struct lafe_matching *matching, const char *pathname)
{
struct match *match;
struct match *matched;
if (matching == NULL)
return (0);
/* Mark off any unmatched inclusions. */
/* In particular, if a filename does appear in the archive and
* is explicitly included and excluded, then we don't report
* it as missing even though we don't extract it.
*/
matched = NULL;
for (match = matching->inclusions; match != NULL; match = match->next){
if (match->matches == 0
&& match_inclusion(match, pathname)) {
matching->inclusions_unmatched_count--;
match->matches++;
matched = match;
}
}
/* Exclusions take priority */
for (match = matching->exclusions; match != NULL; match = match->next){
if (match_exclusion(match, pathname))
return (1);
}
/* It's not excluded and we found an inclusion above, so it's included. */
if (matched != NULL)
return (0);
/* We didn't find an unmatched inclusion, check the remaining ones. */
for (match = matching->inclusions; match != NULL; match = match->next){
/* We looked at previously-unmatched inclusions already. */
if (match->matches > 0
&& match_inclusion(match, pathname)) {
match->matches++;
return (0);
}
}
/* If there were inclusions, default is to exclude. */
if (matching->inclusions != NULL)
return (1);
/* No explicit inclusions, default is to match. */
return (0);
}
/*
* This is a little odd, but it matches the default behavior of
* gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar'
*
*/
static int
match_exclusion(struct match *match, const char *pathname)
{
return (lafe_pathmatch(match->pattern,
pathname,
PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END));
}
/*
* Again, mimic gtar: inclusions are always anchored (have to match
* the beginning of the path) even though exclusions are not anchored.
*/
static int
match_inclusion(struct match *match, const char *pathname)
{
return (lafe_pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END));
}
void
lafe_cleanup_exclusions(struct lafe_matching **matching)
{
struct match *p, *q;
if (*matching == NULL)
return;
for (p = (*matching)->inclusions; p != NULL; ) {
q = p;
p = p->next;
free(q);
}
for (p = (*matching)->exclusions; p != NULL; ) {
q = p;
p = p->next;
free(q);
}
free(*matching);
*matching = NULL;
}
static void
initialize_matching(struct lafe_matching **matching)
{
*matching = calloc(sizeof(**matching), 1);
if (*matching == NULL)
bsdtar_errc(1, errno, "No memory");
}
int
lafe_unmatched_inclusions(struct lafe_matching *matching)
{
if (matching == NULL)
return (0);
return (matching->inclusions_unmatched_count);
}
int
lafe_unmatched_inclusions_warn(struct lafe_matching *matching, const char *msg)
{
struct match *p;
if (matching == NULL)
return (0);
for (p = matching->inclusions; p != NULL; p = p->next) {
if (p->matches == 0)
bsdtar_warnc(0, "%s: %s", p->pattern, msg);
}
return (matching->inclusions_unmatched_count);
}

View File

@ -1,46 +0,0 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef MATCHING_H
#define MATCHING_H
struct lafe_matching;
int lafe_exclude(struct lafe_matching **matching, const char *pattern);
int lafe_exclude_from_file(struct lafe_matching **matching,
const char *pathname);
int lafe_include(struct lafe_matching **matching, const char *pattern);
int lafe_include_from_file(struct lafe_matching **matching,
const char *pathname, int nullSeparator);
int lafe_excluded(struct lafe_matching *, const char *pathname);
void lafe_cleanup_exclusions(struct lafe_matching **);
int lafe_unmatched_inclusions(struct lafe_matching *);
int lafe_unmatched_inclusions_warn(struct lafe_matching *, const char *msg);
#endif

View File

@ -1,255 +0,0 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "bsdtar_platform.h"
__FBSDID("$FreeBSD$");
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "pathmatch.h"
/*
* Check whether a character 'c' is matched by a list specification [...]:
* * Leading '!' or '^' negates the class.
* * <char>-<char> is a range of characters
* * \<char> removes any special meaning for <char>
*
* Some interesting boundary cases:
* a-d-e is one range (a-d) followed by two single characters - and e.
* \a-\d is same as a-d
* a\-d is three single characters: a, d, -
* Trailing - is not special (so [a-] is two characters a and -).
* Initial - is not special ([a-] is same as [-a] is same as [\\-a])
* This function never sees a trailing \.
* [] always fails
* [!] always succeeds
*/
static int
pm_list(const char *start, const char *end, const char c, int flags)
{
const char *p = start;
char rangeStart = '\0', nextRangeStart;
int match = 1, nomatch = 0;
/* This will be used soon... */
(void)flags; /* UNUSED */
/* If this is a negated class, return success for nomatch. */
if ((*p == '!' || *p == '^') && p < end) {
match = 0;
nomatch = 1;
++p;
}
while (p < end) {
nextRangeStart = '\0';
switch (*p) {
case '-':
/* Trailing or initial '-' is not special. */
if ((rangeStart == '\0') || (p == end - 1)) {
if (*p == c)
return (match);
} else {
char rangeEnd = *++p;
if (rangeEnd == '\\')
rangeEnd = *++p;
if ((rangeStart <= c) && (c <= rangeEnd))
return (match);
}
break;
case '\\':
++p;
/* Fall through */
default:
if (*p == c)
return (match);
nextRangeStart = *p; /* Possible start of range. */
}
rangeStart = nextRangeStart;
++p;
}
return (nomatch);
}
/*
* If s is pointing to "./", ".//", "./././" or the like, skip it.
*/
static const char *
pm_slashskip(const char *s) {
while ((*s == '/')
|| (s[0] == '.' && s[1] == '/')
|| (s[0] == '.' && s[1] == '\0'))
++s;
return (s);
}
static int
pm(const char *p, const char *s, int flags)
{
const char *end;
/*
* Ignore leading './', './/', '././', etc.
*/
if (s[0] == '.' && s[1] == '/')
s = pm_slashskip(s + 1);
if (p[0] == '.' && p[1] == '/')
p = pm_slashskip(p + 1);
for (;;) {
switch (*p) {
case '\0':
if (s[0] == '/') {
if (flags & PATHMATCH_NO_ANCHOR_END)
return (1);
/* "dir" == "dir/" == "dir/." */
s = pm_slashskip(s);
}
return (*s == '\0');
case '?':
/* ? always succeds, unless we hit end of 's' */
if (*s == '\0')
return (0);
break;
case '*':
/* "*" == "**" == "***" ... */
while (*p == '*')
++p;
/* Trailing '*' always succeeds. */
if (*p == '\0')
return (1);
while (*s) {
if (lafe_pathmatch(p, s, flags))
return (1);
++s;
}
return (0);
case '[':
/*
* Find the end of the [...] character class,
* ignoring \] that might occur within the class.
*/
end = p + 1;
while (*end != '\0' && *end != ']') {
if (*end == '\\' && end[1] != '\0')
++end;
++end;
}
if (*end == ']') {
/* We found [...], try to match it. */
if (!pm_list(p + 1, end, *s, flags))
return (0);
p = end; /* Jump to trailing ']' char. */
break;
} else
/* No final ']', so just match '['. */
if (*p != *s)
return (0);
break;
case '\\':
/* Trailing '\\' matches itself. */
if (p[1] == '\0') {
if (*s != '\\')
return (0);
} else {
++p;
if (*p != *s)
return (0);
}
break;
case '/':
if (*s != '/' && *s != '\0')
return (0);
/* Note: pattern "/\./" won't match "/";
* pm_slashskip() correctly stops at backslash. */
p = pm_slashskip(p);
s = pm_slashskip(s);
if (*p == '\0' && (flags & PATHMATCH_NO_ANCHOR_END))
return (1);
--p; /* Counteract the increment below. */
--s;
break;
case '$':
/* '$' is special only at end of pattern and only
* if PATHMATCH_NO_ANCHOR_END is specified. */
if (p[1] == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)){
/* "dir" == "dir/" == "dir/." */
return (*pm_slashskip(s) == '\0');
}
/* Otherwise, '$' is not special. */
/* FALL THROUGH */
default:
if (*p != *s)
return (0);
break;
}
++p;
++s;
}
}
/* Main entry point. */
int
lafe_pathmatch(const char *p, const char *s, int flags)
{
/* Empty pattern only matches the empty string. */
if (p == NULL || *p == '\0')
return (s == NULL || *s == '\0');
/* Leading '^' anchors the start of the pattern. */
if (*p == '^') {
++p;
flags &= ~PATHMATCH_NO_ANCHOR_START;
}
if (*p == '/' && *s != '/')
return (0);
/* Certain patterns and file names anchor implicitly. */
if (*p == '*' || *p == '/' || *p == '/') {
while (*p == '/')
++p;
while (*s == '/')
++s;
return (pm(p, s, flags));
}
/* If start is unanchored, try to match start of each path element. */
if (flags & PATHMATCH_NO_ANCHOR_START) {
for ( ; s != NULL; s = strchr(s, '/')) {
if (*s == '/')
s++;
if (pm(p, s, flags))
return (1);
}
return (0);
}
/* Default: Match from beginning. */
return (pm(p, s, flags));
}

View File

@ -1,42 +0,0 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef LAFE_PATHMATCH_H
#define LAFE_PATHMATCH_H
/* Don't anchor at beginning unless the pattern starts with "^" */
#define PATHMATCH_NO_ANCHOR_START 1
/* Don't anchor at end unless the pattern ends with "$" */
#define PATHMATCH_NO_ANCHOR_END 2
/* Note that "^" and "$" are not special unless you set the corresponding
* flag above. */
int lafe_pathmatch(const char *p, const char *s, int flags);
#endif

View File

@ -23,7 +23,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "bsdtar_platform.h"
#include "lafe_platform.h"
__FBSDID("$FreeBSD$");
#ifdef HAVE_SYS_TYPES_H
@ -160,11 +160,11 @@ read_archive(struct bsdtar *bsdtar, char mode)
archive_read_support_compression_all(a);
archive_read_support_format_all(a);
if (ARCHIVE_OK != archive_read_set_options(a, bsdtar->option_options))
bsdtar_errc(1, 0, "%s", archive_error_string(a));
lafe_errc(1, 0, "%s", archive_error_string(a));
if (archive_read_open_file(a, bsdtar->filename,
bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block :
DEFAULT_BYTES_PER_BLOCK))
bsdtar_errc(1, 0, "Error opening archive: %s",
lafe_errc(1, 0, "Error opening archive: %s",
archive_error_string(a));
do_chdir(bsdtar);
@ -180,9 +180,9 @@ read_archive(struct bsdtar *bsdtar, char mode)
if (mode == 'x' && bsdtar->option_chroot) {
#if HAVE_CHROOT
if (chroot(".") != 0)
bsdtar_errc(1, errno, "Can't chroot to \".\"");
lafe_errc(1, errno, "Can't chroot to \".\"");
#else
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"chroot isn't supported on this platform");
#endif
}
@ -198,12 +198,12 @@ read_archive(struct bsdtar *bsdtar, char mode)
if (r == ARCHIVE_EOF)
break;
if (r < ARCHIVE_OK)
bsdtar_warnc(0, "%s", archive_error_string(a));
lafe_warnc(0, "%s", archive_error_string(a));
if (r <= ARCHIVE_WARN)
bsdtar->return_value = 1;
if (r == ARCHIVE_RETRY) {
/* Retryable error: try again */
bsdtar_warnc(0, "Retrying...");
lafe_warnc(0, "Retrying...");
continue;
}
if (r == ARCHIVE_FATAL)
@ -267,17 +267,17 @@ read_archive(struct bsdtar *bsdtar, char mode)
r = archive_read_data_skip(a);
if (r == ARCHIVE_WARN) {
fprintf(out, "\n");
bsdtar_warnc(0, "%s",
lafe_warnc(0, "%s",
archive_error_string(a));
}
if (r == ARCHIVE_RETRY) {
fprintf(out, "\n");
bsdtar_warnc(0, "%s",
lafe_warnc(0, "%s",
archive_error_string(a));
}
if (r == ARCHIVE_FATAL) {
fprintf(out, "\n");
bsdtar_warnc(0, "%s",
lafe_warnc(0, "%s",
archive_error_string(a));
bsdtar->return_value = 1;
break;
@ -329,7 +329,7 @@ read_archive(struct bsdtar *bsdtar, char mode)
r = archive_read_close(a);
if (r != ARCHIVE_OK)
bsdtar_warnc(0, "%s", archive_error_string(a));
lafe_warnc(0, "%s", archive_error_string(a));
if (r <= ARCHIVE_WARN)
bsdtar->return_value = 1;

View File

@ -58,7 +58,7 @@ init_substitution(struct bsdtar *bsdtar)
bsdtar->substitution = subst = malloc(sizeof(*subst));
if (subst == NULL)
bsdtar_errc(1, errno, "Out of memory");
lafe_errc(1, errno, "Out of memory");
subst->first_rule = subst->last_rule = NULL;
}
@ -78,7 +78,7 @@ add_substitution(struct bsdtar *bsdtar, const char *rule_text)
rule = malloc(sizeof(*rule));
if (rule == NULL)
bsdtar_errc(1, errno, "Out of memory");
lafe_errc(1, errno, "Out of memory");
rule->next = NULL;
if (subst->last_rule == NULL)
@ -88,32 +88,32 @@ add_substitution(struct bsdtar *bsdtar, const char *rule_text)
subst->last_rule = rule;
if (*rule_text == '\0')
bsdtar_errc(1, 0, "Empty replacement string");
lafe_errc(1, 0, "Empty replacement string");
end_pattern = strchr(rule_text + 1, *rule_text);
if (end_pattern == NULL)
bsdtar_errc(1, 0, "Invalid replacement string");
lafe_errc(1, 0, "Invalid replacement string");
pattern = malloc(end_pattern - rule_text);
if (pattern == NULL)
bsdtar_errc(1, errno, "Out of memory");
lafe_errc(1, errno, "Out of memory");
memcpy(pattern, rule_text + 1, end_pattern - rule_text - 1);
pattern[end_pattern - rule_text - 1] = '\0';
if ((r = regcomp(&rule->re, pattern, REG_BASIC)) != 0) {
char buf[80];
regerror(r, &rule->re, buf, sizeof(buf));
bsdtar_errc(1, 0, "Invalid regular expression: %s", buf);
lafe_errc(1, 0, "Invalid regular expression: %s", buf);
}
free(pattern);
start_subst = end_pattern + 1;
end_pattern = strchr(start_subst, *rule_text);
if (end_pattern == NULL)
bsdtar_errc(1, 0, "Invalid replacement string");
lafe_errc(1, 0, "Invalid replacement string");
rule->result = malloc(end_pattern - start_subst + 1);
if (rule->result == NULL)
bsdtar_errc(1, errno, "Out of memory");
lafe_errc(1, errno, "Out of memory");
memcpy(rule->result, start_subst, end_pattern - start_subst);
rule->result[end_pattern - start_subst] = '\0';
@ -136,7 +136,7 @@ add_substitution(struct bsdtar *bsdtar, const char *rule_text)
rule->symlink = 1;
break;
default:
bsdtar_errc(1, 0, "Invalid replacement flag %c", *end_pattern);
lafe_errc(1, 0, "Invalid replacement flag %c", *end_pattern);
}
}
}
@ -154,7 +154,7 @@ realloc_strncat(char **str, const char *append, size_t len)
new_str = malloc(old_len + len + 1);
if (new_str == NULL)
bsdtar_errc(1, errno, "Out of memory");
lafe_errc(1, errno, "Out of memory");
memcpy(new_str, *str, old_len);
memcpy(new_str + old_len, append, len);
new_str[old_len + len] = '\0';
@ -175,7 +175,7 @@ realloc_strcat(char **str, const char *append)
new_str = malloc(old_len + strlen(append) + 1);
if (new_str == NULL)
bsdtar_errc(1, errno, "Out of memory");
lafe_errc(1, errno, "Out of memory");
memcpy(new_str, *str, old_len);
strcpy(new_str + old_len, append);
free(*str);

View File

@ -6,16 +6,18 @@ TAR_SRCDIR=${.CURDIR}/..
# Some tar sources are pulled in for white-box tests
TAR_SRCS= \
../getdate.c
getdate.c
TESTS= \
test_0.c \
test_basic.c \
test_copy.c \
test_empty_mtree.c \
test_getdate.c \
test_help.c \
test_option_T.c \
test_option_T_upper.c \
test_option_q.c \
test_option_r.c \
test_option_s.c \
test_patterns.c \
test_stdio.c \

File diff suppressed because it is too large Load Diff

View File

@ -45,37 +45,82 @@
#error Oops: No config.h and no pre-built configuration in test.h.
#endif
#if !defined(_WIN32) || defined(__CYGWIN__)
#include <dirent.h>
#else
#define dirent direct
#include "../bsdtar_windows.h"
#include <direct.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> /* Windows requires this before sys/stat.h */
#include <sys/stat.h>
#if !defined(_WIN32) || defined(__CYGWIN__)
#include <unistd.h>
#endif
#include <wchar.h>
#ifdef USE_DMALLOC
#include <dmalloc.h>
#endif
#ifdef __FreeBSD__
#include <sys/cdefs.h> /* For __FBSDID */
#else
/* Some non-FreeBSD platforms such as newlib-derived ones like
* cygwin, have __FBSDID, so this definition must be guarded.
*/
#ifndef __FBSDID
#define __FBSDID(a) /* null */
#if HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifdef HAVE_DIRECT_H
#include <direct.h>
#define dirent direct
#endif
#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_IO_H
#include <io.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <wchar.h>
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
/*
* System-specific tweaks. We really want to minimize these
* as much as possible, since they make it harder to understand
* the mainline code.
*/
/* Windows (including Visual Studio and MinGW but not Cygwin) */
#if defined(_WIN32) && !defined(__CYGWIN__)
#include "../bsdtar_windows.h"
#if !defined(__BORLANDC__)
#define strdup _strdup
#endif
#define LOCALE_DE "deu"
#else
#define LOCALE_DE "de_DE.UTF-8"
#endif
/* Visual Studio */
#ifdef _MSC_VER
#define snprintf sprintf_s
#endif
/* Cygwin */
#if defined(__CYGWIN__)
/* Cygwin-1.7.x is lazy about populating nlinks, so don't
* expect it to be accurate. */
# define NLINKS_INACCURATE_FOR_DIRS
#endif
#if defined(__HAIKU__) || defined(__QNXNTO__)
/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */
#include <stdint.h>
#endif
/* Get a real definition for __FBSDID if we can */
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
/* If not, define it so as to avoid dangling semicolons. */
#ifndef __FBSDID
#define __FBSDID(a) struct _undefined_hack
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
/*
@ -85,41 +130,83 @@
#define DEFINE_TEST(name) void name(void); void name(void)
/* An implementation of the standard assert() macro */
#define assert(e) test_assert(__FILE__, __LINE__, (e), #e, NULL)
#define assert(e) assertion_assert(__FILE__, __LINE__, (e), #e, NULL)
/* chdir() and error if it fails */
#define assertChdir(path) \
assertion_chdir(__FILE__, __LINE__, path)
/* Assert two integers are the same. Reports value of each one if not. */
#define assertEqualInt(v1,v2) \
test_assert_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
#define assertEqualInt(v1,v2) \
assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
/* Assert two strings are the same. Reports value of each one if not. */
#define assertEqualString(v1,v2) \
test_assert_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
/* As above, but v1 and v2 are wchar_t * */
#define assertEqualWString(v1,v2) \
test_assert_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
/* As above, but raw blocks of bytes. */
#define assertEqualMem(v1, v2, l) \
test_assert_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL)
assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL)
/* Assert two files are the same; allow printf-style expansion of second name.
* See below for comments about variable arguments here...
*/
#define assertEqualFile \
test_setup(__FILE__, __LINE__);test_assert_equal_file
assertion_setup(__FILE__, __LINE__);assertion_equal_file
/* Assert that a file is empty; supports printf-style arguments. */
#define assertEmptyFile \
test_setup(__FILE__, __LINE__);test_assert_empty_file
assertion_setup(__FILE__, __LINE__);assertion_empty_file
/* Assert that a file is not empty; supports printf-style arguments. */
#define assertNonEmptyFile \
test_setup(__FILE__, __LINE__);test_assert_non_empty_file
assertion_setup(__FILE__, __LINE__);assertion_non_empty_file
#define assertFileAtime(pathname, sec, nsec) \
assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec)
#define assertFileAtimeRecent(pathname) \
assertion_file_atime_recent(__FILE__, __LINE__, pathname)
#define assertFileBirthtime(pathname, sec, nsec) \
assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec)
#define assertFileBirthtimeRecent(pathname) \
assertion_file_birthtime_recent(__FILE__, __LINE__, pathname)
/* Assert that a file exists; supports printf-style arguments. */
#define assertFileExists \
test_setup(__FILE__, __LINE__);test_assert_file_exists
assertion_setup(__FILE__, __LINE__);assertion_file_exists
/* Assert that a file exists; supports printf-style arguments. */
#define assertFileNotExists \
test_setup(__FILE__, __LINE__);test_assert_file_not_exists
assertion_setup(__FILE__, __LINE__);assertion_file_not_exists
/* Assert that file contents match a string; supports printf-style arguments. */
#define assertFileContents \
test_setup(__FILE__, __LINE__);test_assert_file_contents
assertion_setup(__FILE__, __LINE__);assertion_file_contents
#define assertFileMtime(pathname, sec, nsec) \
assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec)
#define assertFileMtimeRecent(pathname) \
assertion_file_mtime_recent(__FILE__, __LINE__, pathname)
#define assertFileNLinks(pathname, nlinks) \
assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks)
#define assertFileSize(pathname, size) \
assertion_file_size(__FILE__, __LINE__, pathname, size)
#define assertTextFileContents \
assertion_setup(__FILE__, __LINE__);assertion_text_file_contents
#define assertFileContainsLinesAnyOrder(pathname, lines) \
assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines)
#define assertIsDir(pathname, mode) \
assertion_is_dir(__FILE__, __LINE__, pathname, mode)
#define assertIsHardlink(path1, path2) \
assertion_is_hardlink(__FILE__, __LINE__, path1, path2)
#define assertIsNotHardlink(path1, path2) \
assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2)
#define assertIsReg(pathname, mode) \
assertion_is_reg(__FILE__, __LINE__, pathname, mode)
#define assertIsSymlink(pathname, contents) \
assertion_is_symlink(__FILE__, __LINE__, pathname, contents)
/* Create a directory, report error if it fails. */
#define assertMakeDir(dirname, mode) \
assertion_make_dir(__FILE__, __LINE__, dirname, mode)
#define assertMakeFile(path, mode, contents) \
assertion_make_file(__FILE__, __LINE__, path, mode, contents)
#define assertMakeHardlink(newfile, oldfile) \
assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile)
#define assertMakeSymlink(newfile, linkto) \
assertion_make_symlink(__FILE__, __LINE__, newfile, linkto)
#define assertUmask(mask) \
assertion_umask(__FILE__, __LINE__, mask)
/*
* This would be simple with C99 variadic macros, but I don't want to
@ -128,27 +215,61 @@
* but effective.
*/
#define skipping \
test_setup(__FILE__, __LINE__);test_skipping
assertion_setup(__FILE__, __LINE__);test_skipping
/* Function declarations. These are defined in test_utility.c. */
void failure(const char *fmt, ...);
void test_setup(const char *, int);
int assertion_assert(const char *, int, int, const char *, void *);
int assertion_chdir(const char *, int, const char *);
int assertion_empty_file(const char *, ...);
int assertion_equal_file(const char *, const char *, ...);
int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *);
int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *);
int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *);
int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
int assertion_file_atime(const char *, int, const char *, long, long);
int assertion_file_atime_recent(const char *, int, const char *);
int assertion_file_birthtime(const char *, int, const char *, long, long);
int assertion_file_birthtime_recent(const char *, int, const char *);
int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **);
int assertion_file_contents(const void *, int, const char *, ...);
int assertion_file_exists(const char *, ...);
int assertion_file_mtime(const char *, int, const char *, long, long);
int assertion_file_mtime_recent(const char *, int, const char *);
int assertion_file_nlinks(const char *, int, const char *, int);
int assertion_file_not_exists(const char *, ...);
int assertion_file_size(const char *, int, const char *, long);
int assertion_is_dir(const char *, int, const char *, int);
int assertion_is_hardlink(const char *, int, const char *, const char *);
int assertion_is_not_hardlink(const char *, int, const char *, const char *);
int assertion_is_reg(const char *, int, const char *, int);
int assertion_is_symlink(const char *, int, const char *, const char *);
int assertion_make_dir(const char *, int, const char *, int);
int assertion_make_file(const char *, int, const char *, int, const char *);
int assertion_make_hardlink(const char *, int, const char *newpath, const char *);
int assertion_make_symlink(const char *, int, const char *newpath, const char *);
int assertion_non_empty_file(const char *, ...);
int assertion_text_file_contents(const char *buff, const char *f);
int assertion_umask(const char *, int, int);
void assertion_setup(const char *, int);
void test_skipping(const char *fmt, ...);
int test_assert(const char *, int, int, const char *, void *);
int test_assert_empty_file(const char *, ...);
int test_assert_non_empty_file(const char *, ...);
int test_assert_equal_file(const char *, const char *, ...);
int test_assert_equal_int(const char *, int, int, const char *, int, const char *, void *);
int test_assert_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *);
int test_assert_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
int test_assert_equal_mem(const char *, int, const char *, const char *, const char *, const char *, size_t, const char *, void *);
int test_assert_file_contents(const void *, int, const char *, ...);
int test_assert_file_exists(const char *, ...);
int test_assert_file_not_exists(const char *, ...);
/* Like sprintf, then system() */
int systemf(const char * fmt, ...);
/* Delay until time() returns a value after this. */
void sleepUntilAfter(time_t);
/* Return true if this platform can create symlinks. */
int canSymlink(void);
/* Return true if this platform can run the "gzip" program. */
int canGzip(void);
/* Return true if this platform can run the "gunzip" program. */
int canGunzip(void);
/* Suck file into string allocated via malloc(). Call free() when done. */
/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
char *slurpfile(size_t *, const char *fmt, ...);
@ -161,4 +282,7 @@ void extract_reference_file(const char *);
*/
/* Pathname of exe to be tested. */
const char *testprogfile;
/* Name of exe to use in printf-formatted command strings. */
/* On Windows, this includes leading/trailing quotes. */
const char *testprog;

View File

@ -40,7 +40,7 @@ DEFINE_TEST(test_0)
struct stat st;
failure("File %s does not exist?!", testprog);
if (!assertEqualInt(0, stat(testprog, &st)))
if (!assertEqualInt(0, stat(testprogfile, &st)))
exit(1);
failure("%s is not executable?!", testprog);

View File

@ -30,24 +30,16 @@ static void
basic_tar(const char *target, const char *pack_options,
const char *unpack_options, const char *flist)
{
struct stat st, st2;
#if !defined(_WIN32) || defined(__CYGWIN__)
char buff[128];
#endif
int r;
assertEqualInt(0, mkdir(target, 0775));
assertMakeDir(target, 0775);
/* Use the tar program to create an archive. */
#if !defined(_WIN32) || defined(__CYGWIN__)
r = systemf("%s cf - %s `cat %s` >%s/archive 2>%s/pack.err", testprog, pack_options, flist, target, target);
#else
r = systemf("%s cf - %s %s >%s/archive 2>%s/pack.err", testprog, pack_options, flist, target, target);
#endif
failure("Error invoking %s cf -", testprog, pack_options);
assertEqualInt(r, 0);
chdir(target);
assertChdir(target);
/* Verify that nothing went to stderr. */
assertEmptyFile("pack.err");
@ -67,119 +59,57 @@ basic_tar(const char *target, const char *pack_options,
*/
/* Regular file with 2 links. */
r = lstat("file", &st);
failure("Failed to stat file %s/file, errno=%d", target, errno);
assertEqualInt(r, 0);
if (r == 0) {
assert(S_ISREG(st.st_mode));
#if !defined(_WIN32) || defined(__CYGWIN__)
assertEqualInt(0644, st.st_mode & 0777);
#else
assertEqualInt(0600, st.st_mode & 0700);
#endif
assertEqualInt(10, st.st_size);
failure("file %s/file", target);
assertEqualInt(2, st.st_nlink);
}
assertIsReg("file", -1);
assertFileSize("file", 10);
failure("%s", target);
assertFileNLinks("file", 2);
/* Another name for the same file. */
r = lstat("linkfile", &st2);
failure("Failed to stat file %s/linkfile, errno=%d", target, errno);
assertEqualInt(r, 0);
if (r == 0) {
assert(S_ISREG(st2.st_mode));
#if !defined(_WIN32) || defined(__CYGWIN__)
assertEqualInt(0644, st2.st_mode & 0777);
#else
assertEqualInt(0600, st2.st_mode & 0700);
#endif
assertEqualInt(10, st2.st_size);
failure("file %s/linkfile", target);
assertEqualInt(2, st2.st_nlink);
/* Verify that the two are really hardlinked. */
assertEqualInt(st.st_dev, st2.st_dev);
failure("%s/linkfile and %s/file aren't really hardlinks", target, target);
assertEqualInt(st.st_ino, st2.st_ino);
}
assertIsReg("linkfile", -1);
assertFileSize("linkfile", 10);
assertFileNLinks("linkfile", 2);
assertIsHardlink("file", "linkfile");
#if !defined(_WIN32) || defined(__CYGWIN__)
/* Symlink */
r = lstat("symlink", &st);
failure("Failed to stat file %s/symlink, errno=%d", target, errno);
assertEqualInt(r, 0);
if (r == 0) {
failure("symlink should be a symlink; actual mode is %o",
st.st_mode);
assert(S_ISLNK(st.st_mode));
if (S_ISLNK(st.st_mode)) {
r = readlink("symlink", buff, sizeof(buff));
assertEqualInt(r, 4);
buff[r] = '\0';
assertEqualString(buff, "file");
}
}
#endif
if (canSymlink())
assertIsSymlink("symlink", "file");
/* dir */
r = lstat("dir", &st);
if (r == 0) {
assertEqualInt(r, 0);
assert(S_ISDIR(st.st_mode));
#if !defined(_WIN32) || defined(__CYGWIN__)
assertEqualInt(0775, st.st_mode & 0777);
#else
assertEqualInt(0700, st.st_mode & 0700);
#endif
}
chdir("..");
assertIsDir("dir", 0775);
assertChdir("..");
}
DEFINE_TEST(test_basic)
{
int fd;
int filelist;
int oldumask;
FILE *f;
const char *flist;
oldumask = umask(0);
/*
* Create an assortment of files on disk.
*/
filelist = open("filelist", O_CREAT | O_WRONLY, 0644);
assertUmask(0);
/* File with 10 bytes content. */
fd = open("file", O_CREAT | O_WRONLY, 0644);
assert(fd >= 0);
assertEqualInt(10, write(fd, "123456789", 10));
close(fd);
write(filelist, "file\n", 5);
f = fopen("file", "wb");
assert(f != NULL);
assertEqualInt(10, fwrite("123456789", 1, 10, f));
fclose(f);
/* hardlink to above file. */
assertEqualInt(0, link("file", "linkfile"));
write(filelist, "linkfile\n", 9);
assertMakeHardlink("linkfile", "file");
assertIsHardlink("file", "linkfile");
/* Symlink to above file. */
assertEqualInt(0, symlink("file", "symlink"));
write(filelist, "symlink\n", 8);
if (canSymlink())
assertMakeSymlink("symlink", "file");
/* Directory. */
assertEqualInt(0, mkdir("dir", 0775));
write(filelist, "dir\n", 4);
/* All done. */
close(filelist);
assertMakeDir("dir", 0775);
#if !defined(_WIN32) || defined(__CYGWIN__)
flist = "filelist";
#else
flist = "file linkfile symlink dir";
#endif
if (canSymlink())
flist = "file linkfile symlink dir";
else
flist = "file linkfile dir";
/* Archive/dearchive with a variety of options. */
basic_tar("copy", "", "", flist);
/* tar doesn't handle cpio symlinks correctly */
/* basic_tar("copy_odc", "--format=odc", ""); */
basic_tar("copy_ustar", "--format=ustar", "", flist);
umask(oldumask);
}

View File

@ -25,7 +25,108 @@
#include "test.h"
__FBSDID("$FreeBSD$");
#define LOOP_MAX 170
#if defined(__CYGWIN__)
# include <limits.h>
# include <sys/cygwin.h>
#endif
/*
* Try to figure out how deep we can go in our tests. Assumes that
* the first call to this function has the longest starting cwd (which
* is currently "<testdir>/original"). This is mostly to work around
* limits in our Win32 support.
*
* Background: On Posix systems, PATH_MAX is merely a limit on the
* length of the string passed into a system call. By repeatedly
* calling chdir(), you can work with arbitrarily long paths on such
* systems. In contrast, Win32 APIs apply PATH_MAX limits to the full
* absolute path, so the permissible length of a system call argument
* varies with the cwd. Some APIs actually enforce limits
* significantly less than PATH_MAX to ensure that you can create
* files within the current working directory. The Win32 limits also
* apply to Cygwin before 1.7.
*
* Someday, I want to convert the Win32 support to use newer
* wide-character paths with '\\?\' prefix, which has a 32k PATH_MAX
* instead of the rather anemic 260 character limit of the older
* system calls. Then we can drop this mess (unless we want to
* continue to special-case Cygwin 1.5 and earlier).
*/
static int
compute_loop_max(void)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
static int LOOP_MAX = 0;
char buf[MAX_PATH];
size_t cwdlen;
if (LOOP_MAX == 0) {
assert(_getcwd(buf, MAX_PATH) != NULL);
cwdlen = strlen(buf);
/* 12 characters = length of 8.3 filename */
/* 4 characters = length of "/../" used in symlink tests */
/* 1 character = length of extra "/" separator */
LOOP_MAX = MAX_PATH - (int)cwdlen - 12 - 4 - 1;
}
return LOOP_MAX;
#elif defined(__CYGWIN__) && !defined(HAVE_CYGWIN_CONV_PATH)
static int LOOP_MAX = 0;
if (LOOP_MAX == 0) {
char wbuf[PATH_MAX];
char pbuf[PATH_MAX];
size_t wcwdlen;
size_t pcwdlen;
size_t cwdlen;
assert(getcwd(pbuf, PATH_MAX) != NULL);
pcwdlen = strlen(pbuf);
cygwin_conv_to_full_win32_path(pbuf, wbuf);
wcwdlen = strlen(wbuf);
cwdlen = ((wcwdlen > pcwdlen) ? wcwdlen : pcwdlen);
/* Cygwin helper needs an extra few characters. */
LOOP_MAX = PATH_MAX - (int)cwdlen - 12 - 4 - 4;
}
return LOOP_MAX;
#else
/* cygwin-1.7 ends up here, along with "normal" unix */
return 200; /* restore pre-r278 depth */
#endif
}
/* filenames[i] is a distinctive filename of length i. */
/* To simplify interpreting failures, each filename ends with a
* decimal integer which is the length of the filename. E.g., A
* filename ending in "_92" is 92 characters long. To detect errors
* which drop or misplace characters, the filenames use a repeating
* "abcdefghijklmnopqrstuvwxyz..." pattern. */
static char *filenames[201];
static void
compute_filenames(void)
{
char buff[250];
size_t i,j;
filenames[0] = strdup("");
filenames[1] = strdup("1");
filenames[2] = strdup("a2");
for (i = 3; i < sizeof(filenames)/sizeof(filenames[0]); ++i) {
/* Fill with "abcdefghij..." */
for (j = 0; j < i; ++j)
buff[j] = 'a' + (j % 26);
buff[j--] = '\0';
/* Work from the end to fill in the number portion. */
buff[j--] = '0' + (i % 10);
if (i > 9) {
buff[j--] = '0' + ((i / 10) % 10);
if (i > 99)
buff[j--] = '0' + (i / 100);
}
buff[j] = '_';
/* Guard against obvious screwups in the above code. */
assertEqualInt(strlen(buff), i);
filenames[i] = strdup(buff);
}
}
static void
create_tree(void)
@ -33,217 +134,145 @@ create_tree(void)
char buff[260];
char buff2[260];
int i;
int fd;
int LOOP_MAX;
assertEqualInt(0, mkdir("original", 0775));
chdir("original");
assertEqualInt(0, mkdir("f", 0775));
assertEqualInt(0, mkdir("l", 0775));
assertEqualInt(0, mkdir("m", 0775));
assertEqualInt(0, mkdir("s", 0775));
assertEqualInt(0, mkdir("d", 0775));
compute_filenames();
for (i = 0; i < LOOP_MAX; i++) {
buff[0] = 'f';
buff[1] = '/';
/* Create a file named "f/abcdef..." */
buff[i + 2] = 'a' + (i % 26);
buff[i + 3] = '\0';
fd = open(buff, O_CREAT | O_WRONLY, 0644);
assert(fd >= 0);
assertEqualInt(i + 3, write(fd, buff, strlen(buff)));
close(fd);
/* Create a link named "l/abcdef..." to the above. */
strcpy(buff2, buff);
buff2[0] = 'l';
assertEqualInt(0, link(buff, buff2));
/* Create a link named "m/abcdef..." to the above. */
strcpy(buff2, buff);
buff2[0] = 'm';
assertEqualInt(0, link(buff, buff2));
#if !defined(_WIN32) || defined(__CYGWIN__)
/* Create a symlink named "s/abcdef..." to the above. */
strcpy(buff2 + 3, buff);
buff[0] = 's';
buff2[0] = '.';
buff2[1] = '.';
buff2[2] = '/';
assertEqualInt(0, symlink(buff2, buff));
#else
skipping("create a symlink to the above");
#endif
/* Create a dir named "d/abcdef...". */
buff[0] = 'd';
assertEqualInt(0, mkdir(buff, 0775));
/* Log that we'll be omitting some checks. */
if (!canSymlink()) {
skipping("Symlink checks");
}
chdir("..");
assertMakeDir("original", 0775);
assertEqualInt(0, chdir("original"));
LOOP_MAX = compute_loop_max();
assertMakeDir("f", 0775);
assertMakeDir("l", 0775);
assertMakeDir("m", 0775);
assertMakeDir("s", 0775);
assertMakeDir("d", 0775);
for (i = 1; i < LOOP_MAX; i++) {
failure("Internal sanity check failed: i = %d", i);
assert(filenames[i] != NULL);
sprintf(buff, "f/%s", filenames[i]);
assertMakeFile(buff, 0777, buff);
/* Create a link named "l/abcdef..." to the above. */
sprintf(buff2, "l/%s", filenames[i]);
assertMakeHardlink(buff2, buff);
/* Create a link named "m/abcdef..." to the above. */
sprintf(buff2, "m/%s", filenames[i]);
assertMakeHardlink(buff2, buff);
if (canSymlink()) {
/* Create a symlink named "s/abcdef..." to the above. */
sprintf(buff, "s/%s", filenames[i]);
sprintf(buff2, "../f/%s", filenames[i]);
failure("buff=\"%s\" buff2=\"%s\"", buff, buff2);
assertMakeSymlink(buff, buff2);
}
/* Create a dir named "d/abcdef...". */
buff[0] = 'd';
failure("buff=\"%s\"", buff);
assertMakeDir(buff, 0775);
}
assertEqualInt(0, chdir(".."));
}
#define LIMIT_NONE 0
#define LIMIT_USTAR 1
#define LIMIT_NONE 200
#define LIMIT_USTAR 100
static void
verify_tree(int limit)
verify_tree(size_t limit)
{
struct stat st, st2;
char filename[260];
char name1[260];
char name2[260];
char contents[260];
int i, j, r;
int fd;
int len;
const char *p, *dp;
DIR *d;
struct dirent *de;
size_t i, LOOP_MAX;
LOOP_MAX = compute_loop_max();
/* Generate the names we know should be there and verify them. */
for (i = 1; i < LOOP_MAX; i++) {
/* Generate a base name of the correct length. */
for (j = 0; j < i; ++j)
filename[j] = 'a' + (j % 26);
#if 0
for (n = i; n > 0; n /= 10)
filename[--j] = '0' + (n % 10);
#endif
filename[i] = '\0';
/* Verify a file named "f/abcdef..." */
strcpy(name1, "f/");
strcat(name1, filename);
if (limit != LIMIT_USTAR || strlen(filename) <= 100) {
fd = open(name1, O_RDONLY);
failure("Couldn't open \"%s\": %s",
name1, strerror(errno));
if (assert(fd >= 0)) {
len = read(fd, contents, i + 10);
close(fd);
assertEqualInt(len, i + 2);
/* Verify contents of 'contents' */
contents[len] = '\0';
failure("Each test file contains its own name");
assertEqualString(name1, contents);
/* stat() for dev/ino for next check */
assertEqualInt(0, lstat(name1, &st));
}
sprintf(name1, "f/%s", filenames[i]);
if (i <= limit) {
assertFileExists(name1);
assertFileContents(name1, strlen(name1), name1);
}
/*
* ustar allows 100 chars for links, and we have
* "original/" as part of the name, so the link
* names here can't exceed 91 chars.
*/
strcpy(name2, "l/");
strcat(name2, filename);
if (limit != LIMIT_USTAR || strlen(name2) <= 100) {
sprintf(name2, "l/%s", filenames[i]);
if (i + 2 <= limit) {
/* Verify hardlink "l/abcdef..." */
assertEqualInt(0, (r = lstat(name2, &st2)));
if (r == 0) {
assertEqualInt(st2.st_dev, st.st_dev);
assertEqualInt(st2.st_ino, st.st_ino);
}
/* Verify hardlink "m_abcdef..." */
assertIsHardlink(name1, name2);
/* Verify hardlink "m/abcdef..." */
name2[0] = 'm';
assertEqualInt(0, (r = lstat(name2, &st2)));
if (r == 0) {
assertEqualInt(st2.st_dev, st.st_dev);
assertEqualInt(st2.st_ino, st.st_ino);
assertIsHardlink(name1, name2);
}
if (canSymlink()) {
/* Verify symlink "s/abcdef..." */
sprintf(name1, "s/%s", filenames[i]);
sprintf(name2, "../f/%s", filenames[i]);
if (strlen(name2) <= limit)
assertIsSymlink(name1, name2);
}
/* Verify dir "d/abcdef...". */
sprintf(name1, "d/%s", filenames[i]);
if (i + 1 <= limit) { /* +1 for trailing slash */
if (assertIsDir(name1, -1)) {
/* TODO: opendir/readdir this
* directory and make sure
* it's empty.
*/
}
}
}
#if !defined(_WIN32) || defined(__CYGWIN__)
/*
* Symlink text doesn't include the 'original/' prefix,
* so the limit here is 100 characters.
*/
/* Verify symlink "s/abcdef..." */
strcpy(name2, "../s/");
strcat(name2, filename);
if (limit != LIMIT_USTAR || strlen(name2) <= 100) {
/* This is a symlink. */
failure("Couldn't stat %s (length %d)",
filename, strlen(filename));
if (assertEqualInt(0, lstat(name2 + 3, &st2))) {
assert(S_ISLNK(st2.st_mode));
/* This is a symlink to the file above. */
failure("Couldn't stat %s", name2 + 3);
if (assertEqualInt(0, stat(name2 + 3, &st2))) {
assertEqualInt(st2.st_dev, st.st_dev);
assertEqualInt(st2.st_ino, st.st_ino);
{
const char *dp;
/* Now make sure nothing is there that shouldn't be. */
for (dp = "dflms"; *dp != '\0'; ++dp) {
DIR *d;
struct dirent *de;
char dir[2];
dir[0] = *dp; dir[1] = '\0';
d = opendir(dir);
failure("Unable to open dir '%s'", dir);
if (!assert(d != NULL))
continue;
while ((de = readdir(d)) != NULL) {
char *p = de->d_name;
if (p[0] == '.')
continue;
switch(dp[0]) {
case 'l': case 'm': case 'd':
failure("strlen(p)=%d", strlen(p));
assert(strlen(p) < limit);
assertEqualString(p,
filenames[strlen(p)]);
break;
case 'f': case 's':
failure("strlen(p)=%d", strlen(p));
assert(strlen(p) < limit + 1);
assertEqualString(p,
filenames[strlen(p)]);
break;
default:
failure("File %s shouldn't be here", p);
assert(0);
}
}
closedir(d);
}
#else
skipping("verify symlink");
}
#endif
/* Verify dir "d/abcdef...". */
strcpy(name1, "d/");
strcat(name1, filename);
if (limit != LIMIT_USTAR || strlen(filename) < 100) {
/* This is a dir. */
failure("Couldn't stat %s (length %d)",
name1, strlen(filename));
if (assertEqualInt(0, lstat(name1, &st2))) {
if (assert(S_ISDIR(st2.st_mode))) {
/* TODO: opendir/readdir this
* directory and make sure
* it's empty.
*/
}
}
}
}
/* Now make sure nothing is there that shouldn't be. */
for (dp = "dflms"; *dp != '\0'; ++dp) {
char dir[2];
dir[0] = *dp; dir[1] = '\0';
d = opendir(dir);
failure("Unable to open dir '%s'", dir);
if (!assert(d != NULL))
continue;
while ((de = readdir(d)) != NULL) {
p = de->d_name;
switch(dp[0]) {
case 'l': case 'm':
if (limit == LIMIT_USTAR) {
failure("strlen(p) = %d", strlen(p));
assert(strlen(p) <= 100);
}
case 'd':
if (limit == LIMIT_USTAR) {
failure("strlen(p)=%d", strlen(p));
assert(strlen(p) < 100);
}
case 'f': case 's':
if (limit == LIMIT_USTAR) {
failure("strlen(p)=%d", strlen(p));
assert(strlen(p) < 101);
}
/* Our files have very particular filename patterns. */
if (p[0] != '.' || (p[1] != '.' && p[1] != '\0')) {
for (i = 0; p[i] != '\0' && i < LOOP_MAX; i++) {
failure("i=%d, p[i]='%c' 'a'+(i%%26)='%c'", i, p[i], 'a' + (i % 26));
assertEqualInt(p[i], 'a' + (i % 26));
}
assert(p[i] == '\0');
}
break;
case '.':
assert(p[1] == '\0' || (p[1] == '.' && p[2] == '\0'));
break;
default:
failure("File %s shouldn't be here", p);
assert(0);
}
}
closedir(d);
}
}
static void
@ -251,7 +280,13 @@ copy_basic(void)
{
int r;
assertEqualInt(0, mkdir("plain", 0775));
/* NOTE: for proper operation on cygwin-1.5 and windows, the
* length of the name of the directory below, "plain", must be
* less than or equal to the lengthe of the name of the original
* directory, "original" This restriction derives from the
* extremely limited pathname lengths on those platforms.
*/
assertMakeDir("plain", 0775);
assertEqualInt(0, chdir("plain"));
/*
@ -287,7 +322,13 @@ copy_ustar(void)
const char *target = "ustar";
int r;
assertEqualInt(0, mkdir(target, 0775));
/* NOTE: for proper operation on cygwin-1.5 and windows, the
* length of the name of the directory below, "ustar", must be
* less than or equal to the lengthe of the name of the original
* directory, "original" This restriction derives from the
* extremely limited pathname lengths on those platforms.
*/
assertMakeDir(target, 0775);
assertEqualInt(0, chdir(target));
/*
@ -314,17 +355,13 @@ copy_ustar(void)
assertEmptyFile("unpack.err");
assertEmptyFile("unpack.out");
chdir("original");
verify_tree(LIMIT_USTAR);
chdir("../..");
assertEqualInt(0, chdir("../.."));
}
DEFINE_TEST(test_copy)
{
int oldumask;
oldumask = umask(0);
assertUmask(0);
create_tree(); /* Create sample files in "original" dir. */
/* Test simple "tar -c | tar -x" pipeline copy. */
@ -332,6 +369,4 @@ DEFINE_TEST(test_copy)
/* Same, but constrain to ustar format. */
copy_ustar();
umask(oldumask);
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2009 Joerg Sonnenberger
* Copyright (c) 2003-2009 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -21,23 +21,25 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#include "test.h"
__FBSDID("$FreeBSD$");
#ifndef LAFE_ERR_H
#define LAFE_ERR_H
/*
* Regression test: We used to get a bogus error message when we
* asked tar to copy entries out of an empty archive. See
* Issue 51 on libarchive.googlecode.com for details.
*/
DEFINE_TEST(test_empty_mtree)
{
int r;
#if defined(__GNUC__) && (__GNUC__ > 2 || \
(__GNUC__ == 2 && __GNUC_MINOR__ >= 5))
#define __LA_DEAD __attribute__((__noreturn__))
#else
#define __LA_DEAD
#endif
assertMakeFile("test1.mtree", 0777, "#mtree\n");
extern const char *bsdtar_progname;
void bsdtar_warnc(int code, const char *fmt, ...);
void bsdtar_errc(int eval, int code, const char *fmt, ...) __LA_DEAD;
#endif
r = systemf("%s cf test1.tar @test1.mtree >test1.out 2>test1.err",
testprog);
failure("Error invoking %s cf", testprog);
assertEqualInt(r, 0);
assertEmptyFile("test1.out");
assertEmptyFile("test1.err");
}

View File

@ -51,6 +51,7 @@ DEFINE_TEST(test_help)
/* Exercise --help option. */
r = systemf("%s --help >help.stdout 2>help.stderr", testprog);
assertEqualInt(r, 0);
failure("--help should generate nothing to stderr.");
assertEmptyFile("help.stderr");
/* Help message should start with name of program. */
@ -67,6 +68,7 @@ DEFINE_TEST(test_help)
/* -h option should generate the same output. */
r = systemf("%s -h >h.stdout 2>h.stderr", testprog);
assertEqualInt(r, 0);
failure("-h should generate nothing to stderr.");
assertEmptyFile("h.stderr");
failure("stdout should be same for -h and --help");
@ -74,6 +76,7 @@ DEFINE_TEST(test_help)
/* -W help should be another synonym. */
r = systemf("%s -W help >Whelp.stdout 2>Whelp.stderr", testprog);
assertEqualInt(r, 0);
failure("-W help should generate nothing to stderr.");
assertEmptyFile("Whelp.stderr");
failure("stdout should be same for -W help and --help");

View File

@ -26,110 +26,144 @@
__FBSDID("$FreeBSD$");
static int
touch(const char *fn)
touch(const char *fn, int fail)
{
int fd = open(fn, O_RDWR | O_CREAT, 0644);
failure("Couldn't create file '%s', fd=%d, errno=%d (%s)\n",
fn, fd, errno, strerror(errno));
if (!assert(fd > 0))
return (0); /* Failure. */
close(fd);
FILE *f = fopen(fn, "w");
if (fail) {
failure("Couldn't create file '%s', errno=%d (%s)\n",
fn, errno, strerror(errno));
if (!assert(f != NULL))
return (0); /* Failure. */
} else {
if (f == NULL)
return (0); /* Soft failure. */
}
fclose(f);
return (1); /* Success */
}
DEFINE_TEST(test_option_T)
DEFINE_TEST(test_option_T_upper)
{
FILE *f;
int r;
struct stat st;
int gnarlyFilesSupported;
/* Create a simple dir hierarchy; bail if anything fails. */
if (!assertEqualInt(0, mkdir("d1", 0755))) return;
if (!assertEqualInt(0, mkdir("d1/d2", 0755))) return;
if (!touch("d1/f1")) return;
if (!touch("d1/f2")) return;
if (!touch("d1/d2/f3")) return;
if (!touch("d1/d2/f4")) return;
if (!touch("d1/d2/f5")) return;
/* Create a simple dir heirarchy; bail if anything fails. */
if (!assertMakeDir("d1", 0755)) return;
if (!assertMakeDir("d1/d2", 0755)) return;
if (!touch("f", 1)) return;
if (!touch("d1/f1", 1)) return;
if (!touch("d1/f2", 1)) return;
if (!touch("d1/d2/f3", 1)) return;
if (!touch("d1/d2/f4", 1)) return;
if (!touch("d1/d2/f5", 1)) return;
if (!touch("d1/d2/f6", 1)) return;
/* Some platforms don't permit such things; just skip it. */
gnarlyFilesSupported = touch("d1/d2/f\x0a", 0);
/* Populate a file list */
f = fopen("filelist", "w+");
if (!assert(f != NULL))
return;
fprintf(f, "d1/f1\n");
fprintf(f, "d1/d2/f4\n");
/* Use a variety of text line endings. */
fprintf(f, "f\x0d"); /* CR */
fprintf(f, "d1/f1\x0d\x0a"); /* CRLF */
fprintf(f, "d1/d2/f4\x0a"); /* NL */
fprintf(f, "d1/d2/f6"); /* EOF */
fclose(f);
/* Populate a second file list */
f = fopen("filelist2", "w+");
if (!assert(f != NULL))
return;
fprintf(f, "d1/d2/f3\n");
fprintf(f, "d1/d2/f5\n");
/* Use null-terminated names. */
fprintf(f, "d1/d2/f3");
fwrite("\0", 1, 1, f);
fprintf(f, "d1/d2/f5");
fwrite("\0", 1, 1, f);
if (gnarlyFilesSupported) {
fprintf(f, "d1/d2/f\x0a");
fwrite("\0", 1, 1, f);
}
fclose(f);
/* Use -c -T to archive up the files. */
r = systemf("%s -c -f test1.tar -T filelist > test1.out 2> test1.err",
testprog);
failure("Failure here probably means that tar can't archive zero-length files without reading them");
assert(r == 0);
assertEmptyFile("test1.out");
assertEmptyFile("test1.err");
/* Use -x -T to dearchive the files */
if (!assertEqualInt(0, mkdir("test1", 0755))) return;
if (!assertMakeDir("test1", 0755)) return;
systemf("%s -x -f test1.tar -T filelist -C test1"
" > test1b.out 2> test1b.err", testprog);
assertEmptyFile("test1b.out");
assertEmptyFile("test1b.err");
/* Verify the files were extracted. */
assertFileExists("test1/f");
assertFileExists("test1/d1/f1");
assertFileNotExists("test1/d1/f2");
assertFileNotExists("test1/d1/d2/f3");
assertFileExists("test1/d1/d2/f4");
assertFileNotExists("test1/d1/d2/f5");
assertFileExists("test1/d1/d2/f6");
if (gnarlyFilesSupported) {
assertFileNotExists("test1/d1/d2/f\x0a");
}
/* Use -r -T to add more files to the archive. */
systemf("%s -r -f test1.tar -T filelist2 > test2.out 2> test2.err",
systemf("%s -r -f test1.tar --null -T filelist2 > test2.out 2> test2.err",
testprog);
assertEmptyFile("test2.out");
assertEmptyFile("test2.err");
/* Use -x without -T to dearchive the files (ensure -r worked) */
if (!assertEqualInt(0, mkdir("test3", 0755))) return;
if (!assertMakeDir("test3", 0755)) return;
systemf("%s -x -f test1.tar -C test3"
" > test3.out 2> test3.err", testprog);
assertEmptyFile("test3.out");
assertEmptyFile("test3.err");
/* Verify the files were extracted.*/
assertFileExists("test3/f");
assertFileExists("test3/d1/f1");
assertFileNotExists("test3/d1/f2");
assertFileExists("test3/d1/d2/f3");
assertFileExists("test3/d1/d2/f4");
assertFileExists("test3/d1/d2/f5");
assertFileExists("test3/d1/d2/f6");
if (gnarlyFilesSupported) {
assertFileExists("test3/d1/d2/f\x0a");
}
/* Use -x -T to dearchive the files (verify -x -T together) */
if (!assertEqualInt(0, mkdir("test2", 0755))) return;
if (!assertMakeDir("test2", 0755)) return;
systemf("%s -x -f test1.tar -T filelist -C test2"
" > test2b.out 2> test2b.err", testprog);
assertEmptyFile("test2b.out");
assertEmptyFile("test2b.err");
/* Verify the files were extracted.*/
assertFileExists("test2/f");
assertFileExists("test2/d1/f1");
assertFileNotExists("test2/d1/f2");
assertFileNotExists("test2/d1/d2/f3");
assertFileExists("test2/d1/d2/f4");
assertFileNotExists("test2/d1/d2/f5");
assertFileExists("test2/d1/d2/f6");
if (gnarlyFilesSupported) {
assertFileNotExists("test2/d1/d2/f\x0a");
}
assertEqualInt(0, mkdir("test4", 0755));
assertEqualInt(0, mkdir("test4_out", 0755));
assertEqualInt(0, mkdir("test4_out2", 0755));
assertEqualInt(0, mkdir("test4/d1", 0755));
assertEqualInt(1, touch("test4/d1/foo"));
assertMakeDir("test4", 0755);
assertMakeDir("test4_out", 0755);
assertMakeDir("test4_out2", 0755);
assertMakeDir("test4/d1", 0755);
assertEqualInt(1, touch("test4/d1/foo", 0));
/* Does bsdtar support -s option ? */
systemf("%s -cf - -s /foo/bar/ test4/d1/foo > NUL 2> check.err",
systemf("%s -cf - -s /foo/bar/ test4/d1/foo > check.out 2> check.err",
testprog);
assertEqualInt(0, stat("check.err", &st));
if (st.st_size == 0) {
@ -148,6 +182,7 @@ DEFINE_TEST(test_option_T)
} else {
skipping("bsdtar does not support -s option on this platform");
}
/* TODO: Include some use of -C directory-changing within the filelist. */
/* I'm pretty sure -C within the filelist is broken on extract. */
}

View File

@ -27,7 +27,8 @@ __FBSDID("$FreeBSD$");
DEFINE_TEST(test_option_q)
{
int fd;
FILE *f;
int r;
/*
* Create an archive with several different versions of the
@ -39,38 +40,38 @@ DEFINE_TEST(test_option_q)
* what we use to build up the test archive.
*/
fd = open("foo", O_CREAT | O_WRONLY, 0644);
assert(fd >= 0);
assertEqualInt(4, write(fd, "foo1", 4));
close(fd);
f = fopen("foo", "w");
assert(f != NULL);
fprintf(f, "foo1");
fclose(f);
assertEqualInt(0, systemf("%s -cf archive.tar foo", testprog));
fd = open("foo", O_TRUNC | O_WRONLY, 0644);
assert(fd >= 0);
assertEqualInt(4, write(fd, "foo2", 4));
close(fd);
f = fopen("foo", "w");
assert(f != NULL);
fprintf(f, "foo2");
fclose(f);
assertEqualInt(0, systemf("%s -rf archive.tar foo", testprog));
fd = open("bar", O_CREAT | O_WRONLY, 0644);
assert(fd >= 0);
assertEqualInt(4, write(fd, "bar1", 4));
close(fd);
f = fopen("bar", "w");
assert(f != NULL);
fprintf(f, "bar1");
fclose(f);
assertEqualInt(0, systemf("%s -rf archive.tar bar", testprog));
fd = open("foo", O_TRUNC | O_WRONLY, 0644);
assert(fd >= 0);
assertEqualInt(4, write(fd, "foo3", 4));
close(fd);
f = fopen("foo", "w");
assert(f != NULL);
fprintf(f, "foo3");
fclose(f);
assertEqualInt(0, systemf("%s -rf archive.tar foo", testprog));
fd = open("bar", O_TRUNC | O_WRONLY, 0644);
assert(fd >= 0);
assertEqualInt(4, write(fd, "bar2", 4));
close(fd);
f = fopen("bar", "w");
assert(f != NULL);
fprintf(f, "bar2");
fclose(f);
assertEqualInt(0, systemf("%s -rf archive.tar bar", testprog));
@ -80,46 +81,49 @@ DEFINE_TEST(test_option_q)
*/
/* Test 1: -q foo should only extract the first foo. */
assertEqualInt(0, mkdir("test1", 0755));
assertEqualInt(0, chdir("test1"));
assertEqualInt(0,
systemf("%s -xf ../archive.tar -q foo >test.out 2>test.err",
testprog));
assertMakeDir("test1", 0755);
assertChdir("test1");
r = systemf("%s -xf ../archive.tar -q foo >test.out 2>test.err",
testprog);
failure("Fatal error trying to use -q option");
if (!assertEqualInt(0, r))
return;
assertFileContents("foo1", 4, "foo");
assertEmptyFile("test.out");
assertEmptyFile("test.err");
assertEqualInt(0, chdir(".."));
assertChdir("..");
/* Test 2: -q foo bar should extract up to the first bar. */
assertEqualInt(0, mkdir("test2", 0755));
assertEqualInt(0, chdir("test2"));
assertMakeDir("test2", 0755);
assertChdir("test2");
assertEqualInt(0,
systemf("%s -xf ../archive.tar -q foo bar >test.out 2>test.err", testprog));
assertFileContents("foo2", 4, "foo");
assertFileContents("bar1", 4, "bar");
assertEmptyFile("test.out");
assertEmptyFile("test.err");
assertEqualInt(0, chdir(".."));
assertChdir("..");
/* Test 3: Same as test 2, but use --fast-read spelling. */
assertEqualInt(0, mkdir("test3", 0755));
assertEqualInt(0, chdir("test3"));
assertMakeDir("test3", 0755);
assertChdir("test3");
assertEqualInt(0,
systemf("%s -xf ../archive.tar --fast-read foo bar >test.out 2>test.err", testprog));
assertFileContents("foo2", 4, "foo");
assertFileContents("bar1", 4, "bar");
assertEmptyFile("test.out");
assertEmptyFile("test.err");
assertEqualInt(0, chdir(".."));
assertChdir("..");
/* Test 4: Without -q, should extract everything. */
assertEqualInt(0, mkdir("test4", 0755));
assertEqualInt(0, chdir("test4"));
assertMakeDir("test4", 0755);
assertChdir("test4");
assertEqualInt(0,
systemf("%s -xf ../archive.tar foo bar >test.out 2>test.err", testprog));
assertFileContents("foo3", 4, "foo");
assertFileContents("bar2", 4, "bar");
assertEmptyFile("test.out");
assertEmptyFile("test.err");
assertEqualInt(0, chdir(".."));
assertChdir("..");
}

View File

@ -0,0 +1,117 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
/*
* Also see test_option_q for additional validation of -r support.
*/
DEFINE_TEST(test_option_r)
{
char buff[15];
char *p0, *p1;
size_t s;
FILE *f;
int r;
/* Create a file */
f = fopen("f1", "w");
if (!assert(f != NULL))
return;
assertEqualInt(3, fwrite("abc", 1, 3, f));
fclose(f);
/* Archive that one file. */
r = systemf("%s cf archive.tar --format=ustar f1 >step1.out 2>step1.err", testprog);
failure("Error invoking %s cf archive.tar f1", testprog);
assertEqualInt(r, 0);
/* Verify that nothing went to stdout or stderr. */
assertEmptyFile("step1.out");
assertEmptyFile("step1.err");
/* Do some basic validation of the constructed archive. */
p0 = slurpfile(&s, "archive.tar");
if (!assert(p0 != NULL))
return;
if (!assert(s >= 2048)) {
free(p0);
return;
}
assertEqualMem(p0 + 0, "f1", 3);
assertEqualMem(p0 + 512, "abc", 3);
assertEqualMem(p0 + 1024, "\0\0\0\0\0\0\0\0", 8);
assertEqualMem(p0 + 1536, "\0\0\0\0\0\0\0\0", 8);
/* Edit that file */
f = fopen("f1", "w");
if (!assert(f != NULL))
return;
assertEqualInt(3, fwrite("123", 1, 3, f));
fclose(f);
/* Update the archive. */
r = systemf("%s rf archive.tar --format=ustar f1 >step2.out 2>step2.err", testprog);
failure("Error invoking %s rf archive.tar f1", testprog);
assertEqualInt(r, 0);
/* Verify that nothing went to stdout or stderr. */
assertEmptyFile("step2.out");
assertEmptyFile("step2.err");
/* Do some basic validation of the constructed archive. */
p1 = slurpfile(&s, "archive.tar");
if (!assert(p1 != NULL)) {
free(p0);
return;
}
assert(s >= 3072);
/* Verify first entry is unchanged. */
assertEqualMem(p0, p1, 1024);
/* Verify that second entry is correct. */
assertEqualMem(p1 + 1024, "f1", 3);
assertEqualMem(p1 + 1536, "123", 3);
/* Verify end-of-archive marker. */
assertEqualMem(p1 + 2048, "\0\0\0\0\0\0\0\0", 8);
assertEqualMem(p1 + 2560, "\0\0\0\0\0\0\0\0", 8);
free(p0);
free(p1);
/* Unpack both items */
assertMakeDir("step3", 0775);
assertChdir("step3");
r = systemf("%s xf ../archive.tar", testprog);
failure("Error invoking %s xf archive.tar", testprog);
assertEqualInt(r, 0);
/* Verify that the second one overwrote the first. */
f = fopen("f1", "r");
if (assert(f != NULL)) {
assertEqualInt(3, fread(buff, 1, 3, f));
assertEqualMem(buff, "123", 3);
fclose(f);
}
}

View File

@ -28,15 +28,15 @@ __FBSDID("$FreeBSD$");
static int
mkfile(const char *fn, const char *contents)
{
int fd = open(fn, O_RDWR | O_CREAT, 0644);
failure("Couldn't create file '%s', fd=%d, errno=%d (%s)\n",
fn, fd, errno, strerror(errno));
if (!assert(fd > 0))
FILE *f = fopen(fn, "w");
failure("Couldn't create file '%s', errno=%d (%s)\n",
fn, errno, strerror(errno));
if (!assert(f != NULL))
return (1); /* Failure. */
if (contents != NULL)
assertEqualInt(strlen(contents),
write(fd, contents, strlen(contents)));
assertEqualInt(0, close(fd));
fwrite(contents, 1, strlen(contents), f));
assertEqualInt(0, fclose(f));
return (0); /* Success */
}
@ -44,9 +44,9 @@ DEFINE_TEST(test_option_s)
{
struct stat st;
/* Create a sample file hierarchy. */
assertEqualInt(0, mkdir("in", 0755));
assertEqualInt(0, mkdir("in/d1", 0755));
/* Create a sample file heirarchy. */
assertMakeDir("in", 0755);
assertMakeDir("in/d1", 0755);
assertEqualInt(0, mkfile("in/d1/foo", "foo"));
assertEqualInt(0, mkfile("in/d1/bar", "bar"));
@ -55,14 +55,15 @@ DEFINE_TEST(test_option_s)
testprog);
assertEqualInt(0, stat("check.err", &st));
if (st.st_size != 0) {
skipping("bsdtar does not support -s option on this platform");
skipping("%s does not support -s option on this platform",
testprog);
return;
}
/*
* Test 1: Filename substitution when creating archives.
*/
assertEqualInt(0, mkdir("test1", 0755));
assertMakeDir("test1", 0755);
systemf("%s -cf - -s /foo/bar/ in/d1/foo | %s -xf - -C test1",
testprog, testprog);
assertFileContents("foo", 3, "test1/in/d1/bar");
@ -74,7 +75,7 @@ DEFINE_TEST(test_option_s)
/*
* Test 2: Basic substitution when extracting archive.
*/
assertEqualInt(0, mkdir("test2", 0755));
assertMakeDir("test2", 0755);
systemf("%s -cf - in/d1/foo | %s -xf - -s /foo/bar/ -C test2",
testprog, testprog);
assertFileContents("foo", 3, "test2/in/d1/bar");
@ -89,7 +90,7 @@ DEFINE_TEST(test_option_s)
/*
* Test 4: Multiple substitutions when extracting archive.
*/
assertEqualInt(0, mkdir("test4", 0755));
assertMakeDir("test4", 0755);
systemf("%s -cf - in/d1/foo in/d1/bar | %s -xf - -s /foo/bar/ -s }bar}baz} -C test4",
testprog, testprog);
assertFileContents("foo", 3, "test4/in/d1/bar");
@ -98,7 +99,7 @@ DEFINE_TEST(test_option_s)
/*
* Test 5: Name-switching substitutions when extracting archive.
*/
assertEqualInt(0, mkdir("test5", 0755));
assertMakeDir("test5", 0755);
systemf("%s -cf - in/d1/foo in/d1/bar | %s -xf - -s /foo/bar/ -s }bar}foo} -C test5",
testprog, testprog);
assertFileContents("foo", 3, "test5/in/d1/bar");

View File

@ -28,11 +28,17 @@ __FBSDID("$FreeBSD$");
DEFINE_TEST(test_patterns)
{
int fd, r;
FILE *f;
int r;
const char *reffile2 = "test_patterns_2.tar";
const char *reffile3 = "test_patterns_3.tar";
const char *reffile4 = "test_patterns_4.tar";
const char *p;
const char *tar2aExpected[] = {
"/tmp/foo/bar/",
"/tmp/foo/bar/baz",
NULL
};
/*
* Test basic command-line pattern handling.
@ -44,12 +50,12 @@ DEFINE_TEST(test_patterns)
*
* John Baldwin reported this problem in PR bin/121598
*/
fd = open("foo", O_CREAT | O_WRONLY, 0644);
assert(fd >= 0);
close(fd);
f = fopen("foo", "w");
assert(f != NULL);
fclose(f);
r = systemf("%s cfv tar1.tgz foo > tar1a.out 2> tar1a.err", testprog);
assertEqualInt(r, 0);
r = systemf("%s xfv tar1.tgz foo bar > tar1b.out 2> tar1b.err", testprog);
r = systemf("%s xv --no-same-owner -f tar1.tgz foo bar > tar1b.out 2> tar1b.err", testprog);
failure("tar should return non-zero because a file was given on the command line that's not in the archive");
assert(r != 0);
@ -61,12 +67,7 @@ DEFINE_TEST(test_patterns)
r = systemf("%s tf %s /tmp/foo/bar > tar2a.out 2> tar2a.err",
testprog, reffile2);
assertEqualInt(r, 0);
#if !defined(_WIN32) || defined(__CYGWIN__)
p = "/tmp/foo/bar/\n/tmp/foo/bar/baz\n";
#else
p = "/tmp/foo/bar/\r\n/tmp/foo/bar/baz\r\n";
#endif
assertFileContents(p, strlen(p), "tar2a.out");
assertFileContainsLinesAnyOrder("tar2a.out", tar2aExpected);
assertEmptyFile("tar2a.err");
/*
@ -75,7 +76,7 @@ DEFINE_TEST(test_patterns)
extract_reference_file(reffile3);
/* Test 3a: Pattern tmp/foo/bar should not match /tmp/foo/bar */
r = systemf("%s xf %s tmp/foo/bar > tar3a.out 2> tar3a.err",
r = systemf("%s x --no-same-owner -f %s tmp/foo/bar > tar3a.out 2> tar3a.err",
testprog, reffile3);
assert(r != 0);
assertEmptyFile("tar3a.out");
@ -83,26 +84,26 @@ DEFINE_TEST(test_patterns)
/* Test 3b: Pattern /tmp/foo/baz should not match tmp/foo/baz */
assertNonEmptyFile("tar3a.err");
/* Again, with the '/' */
r = systemf("%s xf %s /tmp/foo/baz > tar3b.out 2> tar3b.err",
r = systemf("%s x --no-same-owner -f %s /tmp/foo/baz > tar3b.out 2> tar3b.err",
testprog, reffile3);
assert(r != 0);
assertEmptyFile("tar3b.out");
assertNonEmptyFile("tar3b.err");
/* Test 3c: ./tmp/foo/bar should not match /tmp/foo/bar */
r = systemf("%s xf %s ./tmp/foo/bar > tar3c.out 2> tar3c.err",
r = systemf("%s x --no-same-owner -f %s ./tmp/foo/bar > tar3c.out 2> tar3c.err",
testprog, reffile3);
assert(r != 0);
assertEmptyFile("tar3c.out");
assertNonEmptyFile("tar3c.err");
/* Test 3d: ./tmp/foo/baz should match tmp/foo/baz */
r = systemf("%s xf %s ./tmp/foo/baz > tar3d.out 2> tar3d.err",
r = systemf("%s x --no-same-owner -f %s ./tmp/foo/baz > tar3d.out 2> tar3d.err",
testprog, reffile3);
assertEqualInt(r, 0);
assertEmptyFile("tar3d.out");
assertEmptyFile("tar3d.err");
assertEqualInt(0, access("tmp/foo/baz/bar", F_OK));
assertFileExists("tmp/foo/baz/bar");
/*
* Test 4 archive has some entries starting with windows drive letters
@ -110,7 +111,7 @@ DEFINE_TEST(test_patterns)
*/
extract_reference_file(reffile4);
r = systemf("%s xf %s -C tmp > tar4.out 2> tar4.err",
r = systemf("%s x --no-same-owner -f %s -C tmp > tar4.out 2> tar4.err",
testprog, reffile4);
assert(r != 0);
assertEmptyFile("tar4.out");
@ -167,16 +168,16 @@ DEFINE_TEST(test_patterns)
* c:../..\file43
* \/?\UnC\../file54
*/
assertEqualInt(-1, access(filex, F_OK));
assertFileNotExists(filex);
filex = file_c;
xsize = sizeof(file_c);
filex[xsize-3] = '0' + r / 10;
filex[xsize-2] = '0' + r % 10;
assertEqualInt(-1, access(filex, F_OK));
assertFileNotExists(filex);
break;
default:
/* Extracted patterns. */
assertEqualInt(0, access(filex, F_OK));
assertFileExists(filex);
break;
}
}

View File

@ -1,4 +1,5 @@
$FreeBSD$
begin 644 test_patterns_2.tar
M+W1M<"]F;V\O````````````````````````````````````````````````
M````````````````````````````````````````````````````````````

View File

@ -1,4 +1,5 @@
$FreeBSD$
begin 644 test_patterns_3.tar
M+W1M<"]F;V\O8F%R+P``````````````````````````````````````````
M````````````````````````````````````````````````````````````

View File

@ -1,4 +1,5 @@
$FreeBSD$
begin 644 test_patterns_4.tar
M+V9I;&4P,0``````````````````````````````````````````````````
M````````````````````````````````````````````````````````````

View File

@ -27,27 +27,27 @@ __FBSDID("$FreeBSD$");
DEFINE_TEST(test_stdio)
{
int fd;
int filelist;
int oldumask;
FILE *filelist;
char *p;
size_t s;
int r;
oldumask = umask(0);
assertUmask(0);
/*
* Create a couple of files on disk.
*/
filelist = open("filelist", O_CREAT | O_WRONLY, 0644);
/* File */
fd = open("f", O_CREAT | O_WRONLY, 0644);
assert(fd >= 0);
write(fd, "f\n", 2);
close(fd);
write(filelist, "f\n", 2);
assertMakeFile("f", 0755, "abc");
/* Link to above file. */
assertEqualInt(0, link("f", "l"));
write(filelist, "l\n", 2);
close(filelist);
assertMakeHardlink("l", "f");
/* Create file list (text mode here) */
filelist = fopen("filelist", "w");
assert(filelist != NULL);
fprintf(filelist, "f\n");
fprintf(filelist, "l\n");
fclose(filelist);
/*
* Archive/dearchive with a variety of options, verifying
@ -111,7 +111,10 @@ DEFINE_TEST(test_stdio)
/* 'xvOf' should generate list on stderr, file contents on stdout. */
r = systemf("%s xvOf archive >xvOf.out 2>xvOf.err", testprog);
assertEqualInt(r, 0);
/* TODO: Verify xvOf.out */
/* Verify xvOf.out is the file contents */
p = slurpfile(&s, "xvOf.out");
assert(s = 3);
assertEqualMem(p, "abc", 3);
/* TODO: Verify xvf.err */
/* 'xvf -' should generate list on stderr, empty stdout. */
@ -119,6 +122,4 @@ DEFINE_TEST(test_stdio)
assertEqualInt(r, 0);
assertEmptyFile("xvf-.out");
/* TODO: Verify xvf-.err */
umask(oldumask);
}

View File

@ -28,50 +28,49 @@ __FBSDID("$FreeBSD$");
static int
touch(const char *fn)
{
int fd = open(fn, O_RDWR | O_CREAT, 0644);
failure("Couldn't create file '%s', fd=%d, errno=%d (%s)\n",
fn, fd, errno, strerror(errno));
if (!assert(fd > 0))
FILE *f = fopen(fn, "w");
failure("Couldn't create file '%s', errno=%d (%s)\n",
fn, errno, strerror(errno));
if (!assert(f != NULL))
return (0); /* Failure. */
close(fd);
fclose(f);
return (1); /* Success */
}
DEFINE_TEST(test_strip_components)
{
struct stat st;
assertEqualInt(0, mkdir("d0", 0755));
assertEqualInt(0, chdir("d0"));
assertEqualInt(0, mkdir("d1", 0755));
assertEqualInt(0, mkdir("d1/d2", 0755));
assertEqualInt(0, mkdir("d1/d2/d3", 0755));
assertMakeDir("d0", 0755);
assertChdir("d0");
assertMakeDir("d1", 0755);
assertMakeDir("d1/d2", 0755);
assertMakeDir("d1/d2/d3", 0755);
assertEqualInt(1, touch("d1/d2/f1"));
assertEqualInt(0, link("d1/d2/f1", "l1"));
assertEqualInt(0, link("d1/d2/f1", "d1/l2"));
assertEqualInt(0, symlink("d1/d2/f1", "s1"));
assertEqualInt(0, symlink("d2/f1", "d1/s2"));
assertEqualInt(0, chdir(".."));
assertMakeHardlink("l1", "d1/d2/f1");
assertMakeHardlink("d1/l2", "d1/d2/f1");
if (canSymlink()) {
assertMakeSymlink("s1", "d1/d2/f1");
assertMakeSymlink("d1/s2", "d2/f1");
}
assertChdir("..");
assertEqualInt(0, systemf("%s -cf test.tar d0", testprog));
assertEqualInt(0, mkdir("target", 0755));
assertMakeDir("target", 0755);
assertEqualInt(0, systemf("%s -x -C target --strip-components 2 "
"-f test.tar", testprog));
failure("d0/ is too short and should not get restored");
assertEqualInt(-1, lstat("target/d0", &st));
assertFileNotExists("target/d0");
failure("d0/d1/ is too short and should not get restored");
assertEqualInt(-1, lstat("target/d1", &st));
assertFileNotExists("target/d1");
failure("d0/d1/s2 is a symlink to something that won't be extracted");
#if !defined(_WIN32) || defined(__CYGWIN__)
assertEqualInt(-1, stat("target/s2", &st));
#else
skipping("symlink with stat()");
#endif
assertEqualInt(0, lstat("target/s2", &st));
/* If platform supports symlinks, target/s2 is a broken symlink. */
/* If platform does not support symlink, target/s2 doesn't exist. */
assertFileNotExists("target/s2");
if (canSymlink())
assertIsSymlink("target/s2", "d2/f1");
failure("d0/d1/d2 should be extracted");
assertEqualInt(0, lstat("target/d2", &st));
assertIsDir("target/d2", -1);
/*
* This next is a complicated case. d0/l1, d0/d1/l2, and
@ -102,9 +101,9 @@ DEFINE_TEST(test_strip_components)
* parallel tests for cpio and newc formats.
*/
failure("d0/l1 is too short and should not get restored");
assertEqualInt(-1, lstat("target/l1", &st));
assertFileNotExists("target/l1");
failure("d0/d1/l2 is a hardlink to file whose name was too short");
assertEqualInt(-1, lstat("target/l2", &st));
assertFileNotExists("target/l2");
failure("d0/d1/d2/f1 is a hardlink to file whose name was too short");
assertEqualInt(-1, lstat("target/d2/f1", &st));
assertFileNotExists("target/d2/f1");
}

View File

@ -32,40 +32,36 @@ __FBSDID("$FreeBSD$");
*/
static int
mkfile(const char *name, int mode, const char *contents, ssize_t size)
mkfile(const char *name, int mode, const char *contents, size_t size)
{
int fd = open(name, O_CREAT | O_WRONLY, mode);
if (fd < 0)
FILE *f = fopen(name, "wb");
size_t written;
(void)mode; /* UNUSED */
if (f == NULL)
return (-1);
if (size != write(fd, contents, size)) {
close(fd);
written = fwrite(contents, 1, size, f);
fclose(f);
if (size != written)
return (-1);
}
close(fd);
return (0);
}
DEFINE_TEST(test_symlink_dir)
{
struct stat st;
#if !defined(_WIN32) || defined(__CYGWIN__)
struct stat st2;
#endif
int oldumask;
assertUmask(0);
oldumask = umask(0);
assertEqualInt(0, mkdir("source", 0755));
assertMakeDir("source", 0755);
assertEqualInt(0, mkfile("source/file", 0755, "a", 1));
assertEqualInt(0, mkfile("source/file2", 0755, "ab", 2));
assertEqualInt(0, mkdir("source/dir", 0755));
assertEqualInt(0, mkdir("source/dir/d", 0755));
assertMakeDir("source/dir", 0755);
assertMakeDir("source/dir/d", 0755);
assertEqualInt(0, mkfile("source/dir/f", 0755, "abc", 3));
assertEqualInt(0, mkdir("source/dir2", 0755));
assertEqualInt(0, mkdir("source/dir2/d2", 0755));
assertMakeDir("source/dir2", 0755);
assertMakeDir("source/dir2/d2", 0755);
assertEqualInt(0, mkfile("source/dir2/f2", 0755, "abcd", 4));
assertEqualInt(0, mkdir("source/dir3", 0755));
assertEqualInt(0, mkdir("source/dir3/d3", 0755));
assertMakeDir("source/dir3", 0755);
assertMakeDir("source/dir3/d3", 0755);
assertEqualInt(0, mkfile("source/dir3/f3", 0755, "abcde", 5));
assertEqualInt(0,
@ -75,119 +71,90 @@ DEFINE_TEST(test_symlink_dir)
/*
* Extract with -x and without -P.
*/
assertEqualInt(0, mkdir("dest1", 0755));
/* "dir" is a symlink to an existing "real_dir" */
assertEqualInt(0, mkdir("dest1/real_dir", 0755));
#if !defined(_WIN32) || defined(__CYGWIN__)
assertEqualInt(0, symlink("real_dir", "dest1/dir"));
/* "dir2" is a symlink to a non-existing "real_dir2" */
assertEqualInt(0, symlink("real_dir2", "dest1/dir2"));
#else
skipping("symlink does not work on this platform");
#endif
assertMakeDir("dest1", 0755);
/* "dir" is a symlink to an existing "dest1/real_dir" */
assertMakeDir("dest1/real_dir", 0755);
if (canSymlink()) {
assertMakeSymlink("dest1/dir", "real_dir");
/* "dir2" is a symlink to a non-existing "real_dir2" */
assertMakeSymlink("dest1/dir2", "real_dir2");
} else {
skipping("some symlink checks");
}
/* "dir3" is a symlink to an existing "non_dir3" */
assertEqualInt(0, mkfile("dest1/non_dir3", 0755, "abcdef", 6));
assertEqualInt(0, symlink("non_dir3", "dest1/dir3"));
if (canSymlink())
assertMakeSymlink("dest1/dir3", "non_dir3");
/* "file" is a symlink to existing "real_file" */
assertEqualInt(0, mkfile("dest1/real_file", 0755, "abcdefg", 7));
assertEqualInt(0, symlink("real_file", "dest1/file"));
#if !defined(_WIN32) || defined(__CYGWIN__)
/* "file2" is a symlink to non-existing "real_file2" */
assertEqualInt(0, symlink("real_file2", "dest1/file2"));
#else
skipping("symlink does not work on this platform");
#endif
if (canSymlink()) {
assertMakeSymlink("dest1/file", "real_file");
/* "file2" is a symlink to non-existing "real_file2" */
assertMakeSymlink("dest1/file2", "real_file2");
}
assertEqualInt(0, systemf("%s -xf test.tar -C dest1", testprog));
/* dest1/dir symlink should be removed */
assertEqualInt(0, lstat("dest1/dir", &st));
/* dest1/dir symlink should be replaced */
failure("symlink to dir was followed when it shouldn't be");
assert(S_ISDIR(st.st_mode));
/* dest1/dir2 symlink should be removed */
assertEqualInt(0, lstat("dest1/dir2", &st));
assertIsDir("dest1/dir", -1);
/* dest1/dir2 symlink should be replaced */
failure("Broken symlink wasn't replaced with dir");
assert(S_ISDIR(st.st_mode));
/* dest1/dir3 symlink should be removed */
assertEqualInt(0, lstat("dest1/dir3", &st));
assertIsDir("dest1/dir2", -1);
/* dest1/dir3 symlink should be replaced */
failure("Symlink to non-dir wasn't replaced with dir");
assert(S_ISDIR(st.st_mode));
/* dest1/file symlink should be removed */
assertEqualInt(0, lstat("dest1/file", &st));
failure("Symlink to existing file should be removed");
assert(S_ISREG(st.st_mode));
/* dest1/file2 symlink should be removed */
assertEqualInt(0, lstat("dest1/file2", &st));
failure("Symlink to non-existing file should be removed");
assert(S_ISREG(st.st_mode));
assertIsDir("dest1/dir3", -1);
/* dest1/file symlink should be replaced */
failure("Symlink to existing file should be replaced");
assertIsReg("dest1/file", -1);
/* dest1/file2 symlink should be replaced */
failure("Symlink to non-existing file should be replaced");
assertIsReg("dest1/file2", -1);
/*
* Extract with both -x and -P
*/
assertEqualInt(0, mkdir("dest2", 0755));
assertMakeDir("dest2", 0755);
/* "dir" is a symlink to existing "real_dir" */
assertEqualInt(0, mkdir("dest2/real_dir", 0755));
#if !defined(_WIN32) || defined(__CYGWIN__)
assertEqualInt(0, symlink("real_dir", "dest2/dir"));
assertMakeDir("dest2/real_dir", 0755);
if (canSymlink())
assertMakeSymlink("dest2/dir", "real_dir");
/* "dir2" is a symlink to a non-existing "real_dir2" */
assertEqualInt(0, symlink("real_dir2", "dest2/dir2"));
#else
skipping("symlink does not work on this platform");
#endif
if (canSymlink())
assertMakeSymlink("dest2/dir2", "real_dir2");
/* "dir3" is a symlink to an existing "non_dir3" */
assertEqualInt(0, mkfile("dest2/non_dir3", 0755, "abcdefgh", 8));
assertEqualInt(0, symlink("non_dir3", "dest2/dir3"));
if (canSymlink())
assertMakeSymlink("dest2/dir3", "non_dir3");
/* "file" is a symlink to existing "real_file" */
assertEqualInt(0, mkfile("dest2/real_file", 0755, "abcdefghi", 9));
assertEqualInt(0, symlink("real_file", "dest2/file"));
#if !defined(_WIN32) || defined(__CYGWIN__)
if (canSymlink())
assertMakeSymlink("dest2/file", "real_file");
/* "file2" is a symlink to non-existing "real_file2" */
assertEqualInt(0, symlink("real_file2", "dest2/file2"));
#else
skipping("symlink does not work on this platform");
#endif
if (canSymlink())
assertMakeSymlink("dest2/file2", "real_file2");
assertEqualInt(0, systemf("%s -xPf test.tar -C dest2", testprog));
/* dest2/dir symlink should be followed */
assertEqualInt(0, lstat("dest2/dir", &st));
failure("tar -xP removed symlink instead of following it");
#if !defined(_WIN32) || defined(__CYGWIN__)
if (assert(S_ISLNK(st.st_mode))) {
/* Only verify what the symlink points to if it
* really is a symlink. */
failure("The symlink should point to a directory");
assertEqualInt(0, stat("dest2/dir", &st));
assert(S_ISDIR(st.st_mode));
failure("The pre-existing directory should still be there");
assertEqualInt(0, lstat("dest2/real_dir", &st2));
assert(S_ISDIR(st2.st_mode));
assertEqualInt(st.st_dev, st2.st_dev);
failure("symlink should still point to the existing directory");
assertEqualInt(st.st_ino, st2.st_ino);
if (canSymlink()) {
assertIsSymlink("dest2/dir", "real_dir");
assertIsDir("dest2/real_dir", -1);
}
#else
skipping("symlink does not work on this platform");
#endif
/* Contents of 'dir' should be restored */
assertEqualInt(0, lstat("dest2/dir/d", &st));
assert(S_ISDIR(st.st_mode));
assertEqualInt(0, lstat("dest2/dir/f", &st));
assert(S_ISREG(st.st_mode));
assertEqualInt(3, st.st_size);
assertIsDir("dest2/dir/d", -1);
assertIsReg("dest2/dir/f", -1);
assertFileSize("dest2/dir/f", 3);
/* dest2/dir2 symlink should be removed */
assertEqualInt(0, lstat("dest2/dir2", &st));
failure("Broken symlink wasn't replaced with dir");
assert(S_ISDIR(st.st_mode));
assertIsDir("dest2/dir2", -1);
/* dest2/dir3 symlink should be removed */
assertEqualInt(0, lstat("dest2/dir3", &st));
failure("Symlink to non-dir wasn't replaced with dir");
assert(S_ISDIR(st.st_mode));
assertIsDir("dest2/dir3", -1);
/* dest2/file symlink should be removed;
* even -P shouldn't follow symlinks for files */
assertEqualInt(0, lstat("dest2/file", &st));
failure("Symlink to existing file should be removed");
assert(S_ISREG(st.st_mode));
assertIsReg("dest2/file", -1);
/* dest2/file2 symlink should be removed */
assertEqualInt(0, lstat("dest2/file2", &st));
failure("Symlink to non-existing file should be removed");
assert(S_ISREG(st.st_mode));
assertIsReg("dest2/file2", -1);
}

View File

@ -52,7 +52,8 @@ DEFINE_TEST(test_version)
/* Version message should start with name of program, then space. */
assert(s > 6);
failure("Version must start with 'bsdtar': ``%s''", p);
assertEqualMem(q, "bsdtar ", 7);
if (!assertEqualMem(q, "bsdtar ", 7))
return;
q += 7; s -= 7;
/* Version number is a series of digits and periods. */
while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {

View File

@ -293,7 +293,7 @@ set_chdir(struct bsdtar *bsdtar, const char *newdir)
free(old_pending);
}
if (bsdtar->pending_chdir == NULL)
bsdtar_errc(1, errno, "No memory");
lafe_errc(1, errno, "No memory");
}
void
@ -303,7 +303,7 @@ do_chdir(struct bsdtar *bsdtar)
return;
if (chdir(bsdtar->pending_chdir) != 0) {
bsdtar_errc(1, 0, "could not chdir to '%s'\n",
lafe_errc(1, 0, "could not chdir to '%s'\n",
bsdtar->pending_chdir);
}
free(bsdtar->pending_chdir);
@ -367,7 +367,7 @@ edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
#if HAVE_REGEX_H
r = apply_substitution(bsdtar, name, &subst_name, 0);
if (r == -1) {
bsdtar_warnc(0, "Invalid substitution, skipping entry");
lafe_warnc(0, "Invalid substitution, skipping entry");
return 1;
}
if (r == 1) {
@ -383,7 +383,7 @@ edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
if (archive_entry_hardlink(entry)) {
r = apply_substitution(bsdtar, archive_entry_hardlink(entry), &subst_name, 1);
if (r == -1) {
bsdtar_warnc(0, "Invalid substitution, skipping entry");
lafe_warnc(0, "Invalid substitution, skipping entry");
return 1;
}
if (r == 1) {
@ -394,7 +394,7 @@ edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
if (archive_entry_symlink(entry) != NULL) {
r = apply_substitution(bsdtar, archive_entry_symlink(entry), &subst_name, 1);
if (r == -1) {
bsdtar_warnc(0, "Invalid substitution, skipping entry");
lafe_warnc(0, "Invalid substitution, skipping entry");
return 1;
}
if (r == 1) {
@ -468,11 +468,11 @@ edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
if (p != name && !bsdtar->warned_lead_slash) {
/* Generate a warning the first time this happens. */
if (slashonly)
bsdtar_warnc(0,
lafe_warnc(0,
"Removing leading '%c' from member names",
name[0]);
else
bsdtar_warnc(0,
lafe_warnc(0,
"Removing leading drive letter from "
"member names");
bsdtar->warned_lead_slash = 1;

View File

@ -169,7 +169,7 @@ tar_mode_c(struct bsdtar *bsdtar)
int r;
if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL)
bsdtar_errc(1, 0, "no files or directories specified");
lafe_errc(1, 0, "no files or directories specified");
a = archive_write_new();
@ -223,21 +223,21 @@ tar_mode_c(struct bsdtar *bsdtar)
r = archive_write_set_compression_compress(a);
break;
default:
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Unrecognized compression option -%c",
bsdtar->create_compression);
}
if (r != ARCHIVE_OK) {
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Unsupported compression option -%c",
bsdtar->create_compression);
}
}
if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options))
bsdtar_errc(1, 0, "%s", archive_error_string(a));
lafe_errc(1, 0, "%s", archive_error_string(a));
if (ARCHIVE_OK != archive_write_open_file(a, bsdtar->filename))
bsdtar_errc(1, 0, "%s", archive_error_string(a));
lafe_errc(1, 0, "%s", archive_error_string(a));
write_archive(a, bsdtar);
}
@ -265,7 +265,7 @@ tar_mode_r(struct bsdtar *bsdtar)
bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY, 0666);
#endif
if (bsdtar->fd < 0)
bsdtar_errc(1, errno,
lafe_errc(1, errno,
"Cannot open %s", bsdtar->filename);
a = archive_read_new();
@ -274,14 +274,14 @@ tar_mode_r(struct bsdtar *bsdtar)
archive_read_support_format_gnutar(a);
r = archive_read_open_fd(a, bsdtar->fd, 10240);
if (r != ARCHIVE_OK)
bsdtar_errc(1, archive_errno(a),
lafe_errc(1, archive_errno(a),
"Can't read archive %s: %s", bsdtar->filename,
archive_error_string(a));
while (0 == archive_read_next_header(a, &entry)) {
if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) {
archive_read_finish(a);
close(bsdtar->fd);
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Cannot append to compressed archive.");
}
/* Keep going until we hit end-of-archive */
@ -310,7 +310,7 @@ tar_mode_r(struct bsdtar *bsdtar)
format &= ARCHIVE_FORMAT_BASE_MASK;
if (format != (int)(archive_format(a) & ARCHIVE_FORMAT_BASE_MASK)
&& format != ARCHIVE_FORMAT_EMPTY) {
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Format %s is incompatible with the archive %s.",
bsdtar->create_format, bsdtar->filename);
}
@ -327,11 +327,11 @@ tar_mode_r(struct bsdtar *bsdtar)
archive_write_set_format(a, format);
}
if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0)
bsdtar_errc(1, errno, "Could not seek to archive end");
lafe_errc(1, errno, "Could not seek to archive end");
if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options))
bsdtar_errc(1, 0, "%s", archive_error_string(a));
lafe_errc(1, 0, "%s", archive_error_string(a));
if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd))
bsdtar_errc(1, 0, "%s", archive_error_string(a));
lafe_errc(1, 0, "%s", archive_error_string(a));
write_archive(a, bsdtar); /* XXX check return val XXX */
@ -359,7 +359,7 @@ tar_mode_u(struct bsdtar *bsdtar)
bsdtar->fd = open(bsdtar->filename, O_RDWR | O_BINARY);
if (bsdtar->fd < 0)
bsdtar_errc(1, errno,
lafe_errc(1, errno,
"Cannot open %s", bsdtar->filename);
a = archive_read_new();
@ -369,7 +369,7 @@ tar_mode_u(struct bsdtar *bsdtar)
if (archive_read_open_fd(a, bsdtar->fd,
bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block :
DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Can't open %s: %s", bsdtar->filename,
archive_error_string(a));
}
@ -379,7 +379,7 @@ tar_mode_u(struct bsdtar *bsdtar)
if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) {
archive_read_finish(a);
close(bsdtar->fd);
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Cannot append to compressed archive.");
}
add_dir_list(bsdtar, archive_entry_pathname(entry),
@ -410,11 +410,11 @@ tar_mode_u(struct bsdtar *bsdtar)
} else
archive_write_set_bytes_per_block(a, DEFAULT_BYTES_PER_BLOCK);
if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0)
bsdtar_errc(1, errno, "Could not seek to archive end");
lafe_errc(1, errno, "Could not seek to archive end");
if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options))
bsdtar_errc(1, 0, "%s", archive_error_string(a));
lafe_errc(1, 0, "%s", archive_error_string(a));
if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd))
bsdtar_errc(1, 0, "%s", archive_error_string(a));
lafe_errc(1, 0, "%s", archive_error_string(a));
write_archive(a, bsdtar);
@ -442,14 +442,14 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
/* Allocate a buffer for file data. */
if ((bsdtar->buff = malloc(FILEDATABUFLEN)) == NULL)
bsdtar_errc(1, 0, "cannot allocate memory");
lafe_errc(1, 0, "cannot allocate memory");
if ((bsdtar->resolver = archive_entry_linkresolver_new()) == NULL)
bsdtar_errc(1, 0, "cannot create link resolver");
lafe_errc(1, 0, "cannot create link resolver");
archive_entry_linkresolver_set_strategy(bsdtar->resolver,
archive_format(a));
if ((bsdtar->diskreader = archive_read_disk_new()) == NULL)
bsdtar_errc(1, 0, "Cannot create read_disk object");
lafe_errc(1, 0, "Cannot create read_disk object");
archive_read_disk_set_standard_lookup(bsdtar->diskreader);
if (bsdtar->names_from_file != NULL)
@ -463,7 +463,7 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
bsdtar->argv++;
arg = *bsdtar->argv;
if (arg == NULL) {
bsdtar_warnc(0, "%s",
lafe_warnc(0, "%s",
"Missing argument for -C");
bsdtar->return_value = 1;
goto cleanup;
@ -493,7 +493,7 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
}
if (archive_write_close(a)) {
bsdtar_warnc(0, "%s", archive_error_string(a));
lafe_warnc(0, "%s", archive_error_string(a));
bsdtar->return_value = 1;
}
@ -543,7 +543,7 @@ archive_names_from_file(struct bsdtar *bsdtar, struct archive *a)
}
lafe_line_reader_free(lr);
if (bsdtar->next_line_is_dir)
bsdtar_errc(1, errno,
lafe_errc(1, errno,
"Unexpected end of filename list; "
"directory expected after -C");
}
@ -569,7 +569,7 @@ append_archive_filename(struct bsdtar *bsdtar, struct archive *a,
archive_read_support_format_all(ina);
archive_read_support_compression_all(ina);
if (archive_read_open_file(ina, filename, 10240)) {
bsdtar_warnc(0, "%s", archive_error_string(ina));
lafe_warnc(0, "%s", archive_error_string(ina));
bsdtar->return_value = 1;
return (0);
}
@ -577,7 +577,7 @@ append_archive_filename(struct bsdtar *bsdtar, struct archive *a,
rc = append_archive(bsdtar, a, ina);
if (rc != ARCHIVE_OK) {
bsdtar_warnc(0, "Error reading archive %s: %s",
lafe_warnc(0, "Error reading archive %s: %s",
filename, archive_error_string(ina));
bsdtar->return_value = 1;
}
@ -610,7 +610,7 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
e = archive_write_header(a, in_entry);
if (e != ARCHIVE_OK) {
if (!bsdtar->verbose)
bsdtar_warnc(0, "%s: %s",
lafe_warnc(0, "%s: %s",
archive_entry_pathname(in_entry),
archive_error_string(a));
else
@ -651,7 +651,7 @@ copy_file_data(struct bsdtar *bsdtar, struct archive *a,
bytes_written = archive_write_data(a, bsdtar->buff,
bytes_read);
if (bytes_written < bytes_read) {
bsdtar_warnc(0, "%s", archive_error_string(a));
lafe_warnc(0, "%s", archive_error_string(a));
return (-1);
}
progress += bytes_written;
@ -678,7 +678,7 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
tree = tree_open(path);
if (!tree) {
bsdtar_warnc(errno, "%s: Cannot open", path);
lafe_warnc(errno, "%s: Cannot open", path);
bsdtar->return_value = 1;
return;
}
@ -691,11 +691,11 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
int descend;
if (tree_ret == TREE_ERROR_FATAL)
bsdtar_errc(1, tree_errno(tree),
lafe_errc(1, tree_errno(tree),
"%s: Unable to continue traversing directory tree",
name);
if (tree_ret == TREE_ERROR_DIR) {
bsdtar_warnc(errno,
lafe_warnc(errno,
"%s: Couldn't visit directory", name);
bsdtar->return_value = 1;
}
@ -715,7 +715,7 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
lst = tree_current_lstat(tree);
if (lst == NULL) {
/* Couldn't lstat(); must not exist. */
bsdtar_warnc(errno, "%s: Cannot stat", name);
lafe_warnc(errno, "%s: Cannot stat", name);
/* Return error if files disappear during traverse. */
bsdtar->return_value = 1;
continue;
@ -834,7 +834,7 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
r = archive_read_disk_entry_from_file(bsdtar->diskreader,
entry, -1, st);
if (r != ARCHIVE_OK)
bsdtar_warnc(archive_errno(bsdtar->diskreader),
lafe_warnc(archive_errno(bsdtar->diskreader),
"%s", archive_error_string(bsdtar->diskreader));
if (r < ARCHIVE_WARN)
continue;
@ -929,7 +929,7 @@ write_entry_backend(struct bsdtar *bsdtar, struct archive *a,
if (fd == -1) {
bsdtar->return_value = 1;
if (!bsdtar->verbose)
bsdtar_warnc(errno,
lafe_warnc(errno,
"%s: could not open file", pathname);
else
fprintf(stderr, ": %s", strerror(errno));
@ -940,7 +940,7 @@ write_entry_backend(struct bsdtar *bsdtar, struct archive *a,
e = archive_write_header(a, entry);
if (e != ARCHIVE_OK) {
if (!bsdtar->verbose)
bsdtar_warnc(0, "%s: %s",
lafe_warnc(0, "%s: %s",
archive_entry_pathname(entry),
archive_error_string(a));
else
@ -1016,12 +1016,12 @@ write_file_data(struct bsdtar *bsdtar, struct archive *a,
bytes_read);
if (bytes_written < 0) {
/* Write failed; this is bad */
bsdtar_warnc(0, "%s", archive_error_string(a));
lafe_warnc(0, "%s", archive_error_string(a));
return (-1);
}
if (bytes_written < bytes_read) {
/* Write was truncated; warn but continue. */
bsdtar_warnc(0,
lafe_warnc(0,
"%s: Truncated write; file may have grown while being archived.",
archive_entry_pathname(entry));
return (0);
@ -1030,7 +1030,7 @@ write_file_data(struct bsdtar *bsdtar, struct archive *a,
bytes_read = read(fd, bsdtar->buff, FILEDATABUFLEN);
}
if (bytes_read < 0) {
bsdtar_warnc(errno,
lafe_warnc(errno,
"%s: Read error",
archive_entry_pathname(entry));
bsdtar->return_value = 1;
@ -1112,11 +1112,11 @@ add_dir_list(struct bsdtar *bsdtar, const char *path,
p = malloc(sizeof(*p));
if (p == NULL)
bsdtar_errc(1, ENOMEM, "Can't read archive directory");
lafe_errc(1, ENOMEM, "Can't read archive directory");
p->name = strdup(path);
if (p->name == NULL)
bsdtar_errc(1, ENOMEM, "Can't read archive directory");
lafe_errc(1, ENOMEM, "Can't read archive directory");
p->mtime_sec = mtime_sec;
p->mtime_nsec = mtime_nsec;
p->next = NULL;
@ -1134,26 +1134,26 @@ test_for_append(struct bsdtar *bsdtar)
struct stat s;
if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL)
bsdtar_errc(1, 0, "no files or directories specified");
lafe_errc(1, 0, "no files or directories specified");
if (bsdtar->filename == NULL)
bsdtar_errc(1, 0, "Cannot append to stdout.");
lafe_errc(1, 0, "Cannot append to stdout.");
if (bsdtar->create_compression != 0)
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Cannot append to %s with compression", bsdtar->filename);
if (stat(bsdtar->filename, &s) != 0)
return;
if (!S_ISREG(s.st_mode) && !S_ISBLK(s.st_mode))
bsdtar_errc(1, 0,
lafe_errc(1, 0,
"Cannot append to %s: not a regular file.",
bsdtar->filename);
/* Is this an appropriate check here on Windows? */
/*
if (GetFileType(handle) != FILE_TYPE_DISK)
bsdtar_errc(1, 0, "Cannot append");
lafe_errc(1, 0, "Cannot append");
*/
}