aboutsummaryrefslogtreecommitdiff
path: root/contrib/libarchive/tar
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libarchive/tar')
-rw-r--r--contrib/libarchive/tar/bsdtar.174
-rw-r--r--contrib/libarchive/tar/bsdtar.c35
-rw-r--r--contrib/libarchive/tar/bsdtar.h12
-rw-r--r--contrib/libarchive/tar/cmdline.c2
-rw-r--r--contrib/libarchive/tar/subst.c1
-rw-r--r--contrib/libarchive/tar/test/test_list_item.c63
-rw-r--r--contrib/libarchive/tar/test/test_list_item.tar.uu169
-rw-r--r--contrib/libarchive/tar/test/test_option_C_mtree.c4
-rw-r--r--contrib/libarchive/tar/test/test_option_P_upper.c (renamed from contrib/libarchive/tar/test/test_option_P.c)0
-rw-r--r--contrib/libarchive/tar/test/test_option_ignore_zeros.c4
-rw-r--r--contrib/libarchive/tar/test/test_option_mtime.c82
-rw-r--r--contrib/libarchive/tar/test/test_option_s.c14
-rw-r--r--contrib/libarchive/tar/test/test_stdio.c48
-rw-r--r--contrib/libarchive/tar/util.c57
-rw-r--r--contrib/libarchive/tar/write.c4
15 files changed, 520 insertions, 49 deletions
diff --git a/contrib/libarchive/tar/bsdtar.1 b/contrib/libarchive/tar/bsdtar.1
index 7a7b0d5d9fb1..0062789e27e9 100644
--- a/contrib/libarchive/tar/bsdtar.1
+++ b/contrib/libarchive/tar/bsdtar.1
@@ -32,19 +32,22 @@
.Nm
creates and manipulates streaming archive files.
This implementation can extract from tar, pax, cpio, zip, jar, ar, xar,
-rpm, 7-zip, and ISO 9660 cdrom images and can create tar, pax, cpio, ar, zip,
-7-zip, and shar archives.
+rar, rpm, 7-zip, and ISO 9660 cdrom images and can create tar, pax,
+cpio, ar, zip, 7-zip, and shar archives.
.Pp
The first synopsis form shows a
.Dq bundled
option word.
This usage is provided for compatibility with historical implementations.
-See COMPATIBILITY below for details.
+See
+.Sx COMPATIBILITY
+below for details.
.Pp
The other synopsis forms show the preferred usage.
The first option to
.Nm
is a mode indicator from the following list:
+.Pp
.Bl -tag -compact -width indent
.It Fl c
Create a new archive containing the specified items.
@@ -109,16 +112,22 @@ all operating modes.
The specified archive is opened and the entries
in it will be appended to the current archive.
As a simple example,
+.Pp
.Dl Nm Fl c Fl f Pa - Pa newfile Cm @ Ns Pa original.tar
+.Pp
writes a new archive to standard output containing a file
.Pa newfile
and all of the entries from
.Pa original.tar .
In contrast,
+.Pp
.Dl Nm Fl c Fl f Pa - Pa newfile Pa original.tar
+.Pp
creates a new archive with only two entries.
Similarly,
+.Pp
.Dl Nm Fl czf Pa - Fl Fl format Cm pax Cm @ Ns Pa -
+.Pp
reads an archive from standard input (whose format will be determined
automatically) and converts it into a gzip-compressed
pax-format archive on stdout.
@@ -130,19 +139,29 @@ can be used to convert archives from one format to another.
Use the archive suffix to decide a set of the format and
the compressions.
As a simple example,
+.Pp
.Dl Nm Fl a Fl cf Pa archive.tgz source.c source.h
+.Pp
creates a new archive with restricted pax format and gzip compression,
+.Pp
.Dl Nm Fl a Fl cf Pa archive.tar.bz2.uu source.c source.h
+.Pp
creates a new archive with restricted pax format and bzip2 compression
and uuencode compression,
+.Pp
.Dl Nm Fl a Fl cf Pa archive.zip source.c source.h
+.Pp
creates a new archive with zip format,
+.Pp
.Dl Nm Fl a Fl jcf Pa archive.tgz source.c source.h
+.Pp
ignores the
.Dq -j
option, and creates a new archive with restricted pax format
and gzip compression,
+.Pp
.Dl Nm Fl a Fl jcf Pa archive.xxx source.c source.h
+.Pp
if it is unknown suffix or no suffix, creates a new archive with
restricted pax format and bzip2 compression.
.It Fl Fl acls
@@ -177,6 +196,11 @@ but before extracting entries from the archive.
to the current directory after processing any
.Fl C
options and before extracting any files.
+.It Fl Fl clamp-mtime
+(use with
+.Fl Fl mtime )
+Only set the modification time if the file is newer than the date specified in
+.Fl Fl mtime .
.It Fl Fl clear-nochange-fflags
(x mode only)
Before removing file system objects to replace them, clear platform-specific
@@ -295,7 +319,9 @@ The
.Fl Fl include
option is especially useful when filtering archives.
For example, the command
+.Pp
.Dl Nm Fl c Fl f Pa new.tar Fl Fl include='*foo*' Cm @ Ns Pa old.tgz
+.Pp
creates a new archive
.Pa new.tar
containing only the entries from
@@ -393,7 +419,11 @@ and the default behavior in c, r, and u modes or if
.Nm
is run in x mode as root.
Currently supported only for pax formats
-(including "pax restricted", the default tar format for bsdtar.)
+.Po including "pax restricted", the default tar format for
+.Nm bsdtar Pc
+.It Fl Fl mtime Ar date
+(c, r, u modes only)
+Set the modification times of added files to the specified date.
.It Fl n , Fl Fl norecurse , Fl Fl no-recursion
Do not operate recursively on the content of directories.
.It Fl Fl newer Ar date
@@ -450,7 +480,7 @@ and the default behavior if
.Nm
is run as non-root in x mode.
.It Fl Fl no-mac-metadata
-(x mode only)
+(c, r, u and x mode only)
Mac OS X specific.
Do not archive or extract ACLs and extended file attributes
using
@@ -556,6 +586,7 @@ keywords and values.
These are passed to the modules that handle particular
formats to control how those formats will behave.
Each option has one of the following forms:
+.Pp
.Bl -tag -compact -width indent
.It Ar key=value
The key will be set to the specified value in every module that supports it.
@@ -579,6 +610,7 @@ and for extract and list modes in
.Xr archive_read_set_options 3 .
.Pp
Examples of supported options:
+.Pp
.Bl -tag -compact -width indent
.It Cm iso9660:joliet
Support Joliet extensions.
@@ -738,6 +770,7 @@ This option is comparable to the
.Fl i , Fl Fl ignore-zeros
option of GNU tar.
.El
+.Pp
If a provided option is not supported by any module, that
is a fatal error.
.It Fl P , Fl Fl absolute-paths
@@ -910,7 +943,9 @@ This flag also causes
.Nm
to remove intervening directory symlinks instead of
reporting an error.
-See the SECURITY section below for more details.
+See the
+.Sx SECURITY
+section below for more details.
.It Fl Fl uid Ar id
Use the provided user id number and ignore the user
name from the archive.
@@ -1048,24 +1083,31 @@ that contains two files
.Ar source.c
and
.Ar source.h :
+.Pp
.Dl Nm Fl czf Pa file.tar.gz Pa source.c Pa source.h
.Pp
To view a detailed table of contents for this
archive:
+.Pp
.Dl Nm Fl tvf Pa file.tar.gz
.Pp
To extract all entries from the archive on
the default tape drive:
+.Pp
.Dl Nm Fl x
.Pp
To examine the contents of an ISO 9660 cdrom image:
+.Pp
.Dl Nm Fl tf Pa image.iso
.Pp
To move file hierarchies, invoke
.Nm
as
+.Pp
.Dl Nm Fl cf Pa - Fl C Pa srcdir \&. | Nm Fl xpf Pa - Fl C Pa destdir
+.Pp
or more traditionally
+.Pp
.Dl cd srcdir \&; Nm Fl cf Pa - \&. | ( cd destdir \&; Nm Fl xpf Pa - )
.Pp
In create mode, the list of files and directories to be archived
@@ -1074,7 +1116,9 @@ can also include directory change instructions of the form
and archive inclusions of the form
.Cm @ Ns Pa archive-file .
For example, the command line
+.Pp
.Dl Nm Fl c Fl f Pa new.tar Pa foo1 Cm @ Ns Pa old.tgz Cm -C Ns Pa /tmp Pa foo2
+.Pp
will create a new archive
.Pa new.tar .
.Nm
@@ -1122,9 +1166,13 @@ For example, you can generate mtree output which only contains
and
.Cm uid
keywords:
+.Pp
.Dl Nm Fl cf Pa file.tar Fl Fl format=mtree Fl Fl options='!all,type,time,uid' Pa dir
+.Pp
or you can set the compression level used by gzip or xz compression:
+.Pp
.Dl Nm Fl czf Pa file.tar Fl Fl options='compression-level=9' .
+.Pp
For more details, see the explanation of the
.Fn archive_read_set_options
and
@@ -1142,7 +1190,9 @@ Arguments follow as separate words.
The order of the arguments must match the order
of the corresponding characters in the bundled command word.
For example,
+.Pp
.Dl Nm Cm tbf 32 Pa file.tar
+.Pp
specifies three flags
.Cm t ,
.Cm b ,
@@ -1240,10 +1290,13 @@ is specified,
.Nm
will refuse to extract the entry.
.El
+.Pp
To protect yourself, you should be wary of any archives that
come from untrusted sources.
You should examine the contents of an archive with
+.Pp
.Dl Nm Fl tf Pa filename
+.Pp
before extraction.
You should use the
.Fl k
@@ -1294,7 +1347,7 @@ command appeared in Seventh Edition Unix, which was released in January, 1979.
There have been numerous other implementations,
many of which extended the file format.
John Gilmore's
-.Nm pdtar
+.Sy pdtar
public-domain implementation (circa November, 1987)
was quite influential, and formed the basis of GNU tar.
GNU tar was included as the standard system tar
@@ -1347,8 +1400,11 @@ although they still extract it correctly.
The compression and decompression is implemented internally, so
there may be insignificant differences between the compressed output
generated by
+.Pp
.Dl Nm Fl czf Pa - file
+.Pp
and that generated by
+.Pp
.Dl Nm Fl cf Pa - file | Nm gzip
.Pp
The default should be to read and write archives to the standard I/O paths,
@@ -1393,5 +1449,5 @@ There is not yet any support for multi-volume archives.
Converting between dissimilar archive formats (such as tar and cpio) using the
.Cm @ Ns Pa -
convention can cause hard link information to be lost.
-(This is a consequence of the incompatible ways that different archive
-formats store hardlink information.)
+This is a consequence of the incompatible ways that different archive
+formats store hardlink information.
diff --git a/contrib/libarchive/tar/bsdtar.c b/contrib/libarchive/tar/bsdtar.c
index 439093ded76a..53ac135f0129 100644
--- a/contrib/libarchive/tar/bsdtar.c
+++ b/contrib/libarchive/tar/bsdtar.c
@@ -7,6 +7,9 @@
#include "bsdtar_platform.h"
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
@@ -101,7 +104,7 @@ need_report(void)
static __LA_NORETURN void long_help(void);
static void only_mode(struct bsdtar *, const char *opt,
const char *valid);
-static void set_mode(struct bsdtar *, char opt);
+static void set_mode(struct bsdtar *, int opt);
static __LA_NORETURN void version(void);
/* A basic set of security flags to request from libarchive. */
@@ -136,13 +139,14 @@ main(int argc, char **argv)
{
struct bsdtar *bsdtar, bsdtar_storage;
int opt, t;
- char compression, compression2;
+ int compression, compression2;
const char *compression_name, *compression2_name;
const char *compress_program;
char *tptr, *uptr;
char possible_help_request;
char buff[16];
long l;
+ time_t now;
/*
* Use a pointer for consistency, but stack-allocated storage
@@ -157,6 +161,7 @@ main(int argc, char **argv)
compression = compression2 = '\0';
compression_name = compression2_name = NULL;
compress_program = NULL;
+ time(&now);
#if defined(HAVE_SIGACTION)
{ /* Set up signal handling. */
@@ -331,7 +336,7 @@ main(int argc, char **argv)
if (archive_match_exclude_pattern(
bsdtar->matching, bsdtar->argument) != ARCHIVE_OK)
lafe_errc(1, 0,
- "Couldn't exclude %s\n", bsdtar->argument);
+ "Couldn't exclude %s", bsdtar->argument);
break;
case OPTION_EXCLUDE_VCS: /* GNU tar */
for(t=0; vcs_files[t]; t++) {
@@ -339,7 +344,7 @@ main(int argc, char **argv)
bsdtar->matching,
vcs_files[t]) != ARCHIVE_OK)
lafe_errc(1, 0, "Couldn't "
- "exclude %s\n", vcs_files[t]);
+ "exclude %s", vcs_files[t]);
}
break;
case OPTION_FFLAGS:
@@ -673,6 +678,16 @@ main(int argc, char **argv)
}
}
break;
+ case OPTION_MTIME: /* GNU tar */
+ bsdtar->has_mtime = 1;
+ bsdtar->mtime = archive_parse_date(now, bsdtar->argument);
+ if (bsdtar->mtime == (time_t)-1) {
+ lafe_errc(1, 0, "Invalid argument to --mtime (bad date string)");
+ }
+ break;
+ case OPTION_CLAMP_MTIME: /* GNU tar */
+ bsdtar->clamp_mtime = 1;
+ break;
#if 0
/*
* The common BSD -P option is not necessary, since
@@ -740,6 +755,8 @@ main(int argc, char **argv)
bsdtar->strip_components = (int)l;
break;
case 'T': /* GNU tar */
+ if (bsdtar->names_from_file)
+ lafe_errc(1, 0, "Multiple --files-from/-T options are not supported");
bsdtar->names_from_file = bsdtar->argument;
break;
case 't': /* SUSv2 */
@@ -935,7 +952,7 @@ main(int argc, char **argv)
switch (compression) {
case 'J': case 'j': case 'y': case 'Z': case 'z':
strcpy(buff, "-?");
- buff[1] = compression;
+ buff[1] = (char)compression;
break;
default:
strcpy(buff, "--");
@@ -959,6 +976,10 @@ main(int argc, char **argv)
only_mode(bsdtar, buff, "cru");
}
+ if (!bsdtar->has_mtime && bsdtar->clamp_mtime)
+ lafe_errc(1, 0,
+ "--clamp-mtime is not valid without --mtime <date>");
+
/*
* When creating an archive from a directory tree, the directory
* walking code will already avoid entering directories when
@@ -1005,7 +1026,7 @@ main(int argc, char **argv)
}
static void
-set_mode(struct bsdtar *bsdtar, char opt)
+set_mode(struct bsdtar *bsdtar, int opt)
{
if (bsdtar->mode != '\0' && bsdtar->mode != opt)
lafe_errc(1, 0,
@@ -1063,6 +1084,8 @@ static const char *long_help_msg =
" -z, -j, -J, --lzma Compress archive with gzip/bzip2/xz/lzma\n"
" --format {ustar|pax|cpio|shar} Select archive format\n"
" --exclude <pattern> Skip files that match pattern\n"
+ " --mtime <date> Set modification times for added files\n"
+ " --clamp-mtime Only set modification times for files newer than --mtime\n"
" -C <dir> Change to <dir> before processing remaining files\n"
" @<archive> Add entries from <archive> to output\n"
"List: %p -t [options] [<patterns>]\n"
diff --git a/contrib/libarchive/tar/bsdtar.h b/contrib/libarchive/tar/bsdtar.h
index 42520c88f2bc..45dfeed7dce3 100644
--- a/contrib/libarchive/tar/bsdtar.h
+++ b/contrib/libarchive/tar/bsdtar.h
@@ -42,10 +42,13 @@ struct bsdtar {
int uid; /* --uid */
const char *uname; /* --uname */
const char *passphrase; /* --passphrase */
- char mode; /* Program mode: 'c', 't', 'r', 'u', 'x' */
+ int mode; /* Program mode: 'c', 't', 'r', 'u', 'x' */
char symlink_mode; /* H or L, per BSD conventions */
const char *option_options; /* --options */
char day_first; /* show day before month in -tv output */
+ char has_mtime; /* --mtime exists (0 or 1) */
+ char clamp_mtime; /* --clamp-mtime (0 or 1)*/
+ time_t mtime; /* --mtime */
struct creation_set *cset;
/* Option parser state */
@@ -114,7 +117,7 @@ struct bsdtar {
/* Fake short equivalents for long options that otherwise lack them. */
enum {
- OPTION_ACLS = 1,
+ OPTION_ACLS = 256,
OPTION_B64ENCODE,
OPTION_CHECK_LINKS,
OPTION_CHROOT,
@@ -175,14 +178,17 @@ enum {
OPTION_VERSION,
OPTION_XATTRS,
OPTION_ZSTD,
+ OPTION_MTIME,
+ OPTION_CLAMP_MTIME,
};
int bsdtar_getopt(struct bsdtar *);
void do_chdir(struct bsdtar *);
int edit_pathname(struct bsdtar *, struct archive_entry *);
+void edit_mtime(struct bsdtar *, struct archive_entry *);
int need_report(void);
int pathcmp(const char *a, const char *b);
-void safe_fprintf(FILE *, const char *fmt, ...) __LA_PRINTF(2, 3);
+void safe_fprintf(FILE * restrict, const char * restrict fmt, ...) __LA_PRINTF(2, 3);
void set_chdir(struct bsdtar *, const char *newdir);
const char *tar_i64toa(int64_t);
void tar_mode_c(struct bsdtar *bsdtar);
diff --git a/contrib/libarchive/tar/cmdline.c b/contrib/libarchive/tar/cmdline.c
index 35cb1cb43bf1..c766c1a52dbb 100644
--- a/contrib/libarchive/tar/cmdline.c
+++ b/contrib/libarchive/tar/cmdline.c
@@ -57,6 +57,7 @@ static const struct bsdtar_option {
{ "cd", 1, 'C' },
{ "check-links", 0, OPTION_CHECK_LINKS },
{ "chroot", 0, OPTION_CHROOT },
+ { "clamp-mtime", 0, OPTION_CLAMP_MTIME },
{ "clear-nochange-fflags", 0, OPTION_CLEAR_NOCHANGE_FFLAGS },
{ "compress", 0, 'Z' },
{ "confirmation", 0, 'w' },
@@ -95,6 +96,7 @@ static const struct bsdtar_option {
{ "lzop", 0, OPTION_LZOP },
{ "mac-metadata", 0, OPTION_MAC_METADATA },
{ "modification-time", 0, 'm' },
+ { "mtime", 1, OPTION_MTIME },
{ "newer", 1, OPTION_NEWER_CTIME },
{ "newer-ctime", 1, OPTION_NEWER_CTIME },
{ "newer-ctime-than", 1, OPTION_NEWER_CTIME_THAN },
diff --git a/contrib/libarchive/tar/subst.c b/contrib/libarchive/tar/subst.c
index 0194cc84bd2d..5546b5f93b12 100644
--- a/contrib/libarchive/tar/subst.c
+++ b/contrib/libarchive/tar/subst.c
@@ -229,6 +229,7 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result,
if (rule->from_begin && *result) {
realloc_strcat(result, name);
+ if (buffer) buffer[0] = 0;
realloc_strcat(&buffer, *result);
name = buffer;
(*result)[0] = 0;
diff --git a/contrib/libarchive/tar/test/test_list_item.c b/contrib/libarchive/tar/test/test_list_item.c
new file mode 100644
index 000000000000..fd131c475275
--- /dev/null
+++ b/contrib/libarchive/tar/test/test_list_item.c
@@ -0,0 +1,63 @@
+/*-SPDX-License-Identifier: BSD-2-Clause
+ * Copyright (c) 2024 Tarsnap Backup Inc.
+ * All rights reserved.
+ */
+#include "test.h"
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <winbase.h>
+#endif
+
+/* These lists of files come from 'test_list_archive.tar.uu', which includes
+ * the script which generated it. */
+
+static const char *tf_out =
+"f\n"
+"hl\n"
+"sl\n"
+"d/\n"
+"d/f\n"
+"fake-username\n"
+"fake-groupname\n"
+"f\n";
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static const char *tvf_out =
+"-rw-r--r-- 0 1000 1000 0 Jan 01 1980 f\n"
+"hrw-r--r-- 0 1000 1000 0 Jan 01 1980 hl link to f\n"
+"lrwxr-xr-x 0 1000 1000 0 Jan 01 1980 sl -> f\n"
+"drwxrwxrwx 0 1000 1000 0 Jan 01 1980 d/\n"
+"-r-------- 0 1000 1000 0 Jan 01 1980 d/f\n"
+"-rw-r--r-- 0 long-fake-uname 1000 0 Jan 01 1980 fake-username\n"
+"-rw-r--r-- 0 1000 long-fake-gname 0 Jan 01 1980 fake-groupname\n"
+"-rw-r--r-- 0 1000 1000 0 Jan 01 1980 f\n";
+#else
+static const char *tvf_out =
+"-rw-r--r-- 0 1000 1000 0 Jan 1 1980 f\n"
+"hrw-r--r-- 0 1000 1000 0 Jan 1 1980 hl link to f\n"
+"lrwxr-xr-x 0 1000 1000 0 Jan 1 1980 sl -> f\n"
+"drwxrwxrwx 0 1000 1000 0 Jan 1 1980 d/\n"
+"-r-------- 0 1000 1000 0 Jan 1 1980 d/f\n"
+"-rw-r--r-- 0 long-fake-uname 1000 0 Jan 1 1980 fake-username\n"
+"-rw-r--r-- 0 1000 long-fake-gname 0 Jan 1 1980 fake-groupname\n"
+"-rw-r--r-- 0 1000 1000 0 Jan 1 1980 f\n";
+#endif
+
+DEFINE_TEST(test_list_item)
+{
+ extract_reference_file("test_list_item.tar");
+
+ /* Run 'tf' and check output. */
+ assertEqualInt(0,
+ systemf("%s tf test_list_item.tar >tf.out 2>tf.err", testprog));
+ failure("'t' mode should write results to stdout");
+ assertTextFileContents(tf_out, "tf.out");
+ assertEmptyFile("tf.err");
+
+ /* Run 'tvf' and check output. */
+ assertEqualInt(0,
+ systemf("%s tvf test_list_item.tar >tvf.out 2>tvf.err", testprog));
+ failure("'t' mode with 'v' should write more results to stdout");
+ assertTextFileContents(tvf_out, "tvf.out");
+ assertEmptyFile("tvf.err");
+}
diff --git a/contrib/libarchive/tar/test/test_list_item.tar.uu b/contrib/libarchive/tar/test/test_list_item.tar.uu
new file mode 100644
index 000000000000..f0e174793438
--- /dev/null
+++ b/contrib/libarchive/tar/test/test_list_item.tar.uu
@@ -0,0 +1,169 @@
+begin 644 test_list_item.tar
+M9@``````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#`P,#8T-"``,#`Q-S4P(``P,#$W-3`@`#`P,#`P,#`P,#`P
+M(#`R,C8S-C$S,C`Q(#`P-S0P-P`@,```````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U<W1A<@`P,```````
+M````````````````````````````````````````````````````````````
+M```````````````````P,#`P,#`@`#`P,#`P,"``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````!H;```````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````,#`P-C0T(``P,#$W-3`@`#`P
+M,3<U,"``,#`P,#`P,#`P,#`@,#(R-C,V,3,R,#$@,#`W-S,T`"`Q9@``````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````'5S=&%R`#`P````````````````````````````````````````````
+M`````````````````````````````````````````#`P,#`P,"``,#`P,#`P
+M(```````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````'-L````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````P
+M,#`W-34@`#`P,3<U,"``,#`Q-S4P(``P,#`P,#`P,#`P,"`P,C(V,S8Q,S(P
+M,2`P,#<W-3,`(#)F````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````=7-T87(`,#``````````````````````
+M````````````````````````````````````````````````````````````
+M````,#`P,#`P(``P,#`P,#`@````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````9"\`````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````#`P,#<W-R``,#`Q-S4P(``P,#$W-3`@`#`P,#`P
+M,#`P,#`P(#`R,C8S-C$S,C`Q(#`P-S4P,``@-0``````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````!U<W1A<@`P
+M,```````````````````````````````````````````````````````````
+M```````````````````````````P,#`P,#`@`#`P,#`P,"``````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````!D+V8`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````,#`P-#`P(``P,#$W
+M-3`@`#`P,3<U,"``,#`P,#`P,#`P,#`@,#(R-C,V,3,R,#$@,#`W-C(P`"`P
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````'5S=&%R`#`P````````````````````````````````````
+M`````````````````````````````````````````````````#`P,#`P,"``
+M,#`P,#`P(```````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````&9A:V4M
+M=7-E<FYA;64`````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````P,#`V-#0@`#`P,3<U,"``,#`Q-S4P(``P,#`P,#`P,#`P,"`P,C(V
+M,S8Q,S(P,2`P,30U-S0`(#``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````=7-T87(`,#!L;VYG+69A:V4M
+M=6YA;64`````````````````````````````````````````````````````
+M````````````,#`P,#`P(``P,#`P,#`@````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````9F%K92UG<F]U<&YA;64`````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````#`P,#8T-"``,#`Q-S4P(``P,#$W-3`@
+M`#`P,#`P,#`P,#`P(#`R,C8S-C$S,C`Q(#`Q-#<S-``@,```````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````````!U
+M<W1A<@`P,```````````````````````````````````````````;&]N9RUF
+M86ME+6=N86UE```````````````````````P,#`P,#`@`#`P,#`P,"``````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````!F````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````,#`P-C0T
+M(``P,#$W-3`@`#`P,3<U,"``,#`P,#`P,#`P,#`@,#(R-C,V,3,R,#$@,#`W
+M-#`W`"`P````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````'5S=&%R`#`P````````````````````````````
+M`````````````````````````````````````````````````````````#`P
+M,#`P,"``,#`P,#`P(```````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+C````````````````````````````````````````````````
+`
+end
+#!/bin/sh
+
+set -e
+
+mkdir test-list-item
+cd test-list-item
+
+# Create files
+touch f
+ln f hl
+ln -s f sl
+
+mkdir d
+chmod 777 d
+touch d/f
+chmod 400 d/f
+
+touch fake-username
+touch fake-groupname
+
+# Set all the dates to 1980
+touch -d "1980-01-01T00:00:01" -h -a -m ./*
+touch -d "1980-01-01T00:00:01" -h -a -m d/*
+
+# Archive
+tar -cf test_list_item.tar \
+ --uid 1000 --gid 1000 \
+ f hl sl d
+
+# Append to archive, with fake username and groupname
+tar --append -f test_list_item.tar \
+ --uid 1000 --gid 1000 \
+ --uname long-fake-uname \
+ fake-username
+tar --append -f test_list_item.tar \
+ --uid 1000 --gid 1000 \
+ --gname long-fake-gname \
+ fake-groupname
+# Add f again, to print with the expanded field lengths
+tar --append -f test_list_item.tar \
+ --uid 1000 --gid 1000 \
+ f
+
+# uuencode for the test suite
+uuencode -o test_list_item.tar.uu test_list_item.tar test_list_item.tar
+
+# Append this script, and overwrite file in git
+cat ../"$0" >> test_list_item.tar.uu
+mv test_list_item.tar.uu ../
+
+# Don't delete the temporary directory; leave that up to the developer to
+# delete manually when they want to.
diff --git a/contrib/libarchive/tar/test/test_option_C_mtree.c b/contrib/libarchive/tar/test/test_option_C_mtree.c
index b6ab159941d8..6cbac38fcac5 100644
--- a/contrib/libarchive/tar/test/test_option_C_mtree.c
+++ b/contrib/libarchive/tar/test/test_option_C_mtree.c
@@ -17,7 +17,7 @@ DEFINE_TEST(test_option_C_mtree)
p0 = NULL;
char *content = "./foo type=file uname=root gname=root mode=0755\n";
char *filename = "output.tar";
-#if defined(_WIN32) && !defined(CYGWIN)
+#if defined(_WIN32) && !defined(__CYGWIN__)
char *p;
#endif
@@ -32,7 +32,7 @@ DEFINE_TEST(test_option_C_mtree)
assertMakeDir("bar", 0775);
assertMakeFile("bar/foo", 0777, "abc");
-#if defined(_WIN32) && !defined(CYGWIN)
+#if defined(_WIN32) && !defined(__CYGWIN__)
p = absolute_path;
while(*p != '\0') {
if (*p == '/')
diff --git a/contrib/libarchive/tar/test/test_option_P.c b/contrib/libarchive/tar/test/test_option_P_upper.c
index 953d9f58991c..953d9f58991c 100644
--- a/contrib/libarchive/tar/test/test_option_P.c
+++ b/contrib/libarchive/tar/test/test_option_P_upper.c
diff --git a/contrib/libarchive/tar/test/test_option_ignore_zeros.c b/contrib/libarchive/tar/test/test_option_ignore_zeros.c
index 31e0dd940460..453e8a0907e6 100644
--- a/contrib/libarchive/tar/test/test_option_ignore_zeros.c
+++ b/contrib/libarchive/tar/test/test_option_ignore_zeros.c
@@ -76,8 +76,7 @@ DEFINE_TEST(test_option_ignore_zeros_mode_c)
// bsdtar.exe: b: Can't translate uname '(null)' to UTF-8
skipping("TODO: figure out why this test fails on github workflows with MSVC");
return;
-#endif
-
+#else
if (make_files())
return;
@@ -97,6 +96,7 @@ DEFINE_TEST(test_option_ignore_zeros_mode_c)
assertEqualFile("out/a", "in/a");
assertEqualFile("out/b", "in/b");
assertEqualFile("out/c", "in/c");
+#endif
}
static void
diff --git a/contrib/libarchive/tar/test/test_option_mtime.c b/contrib/libarchive/tar/test/test_option_mtime.c
new file mode 100644
index 000000000000..75cdb8390bc0
--- /dev/null
+++ b/contrib/libarchive/tar/test/test_option_mtime.c
@@ -0,0 +1,82 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Zhaofeng Li
+ * All rights reserved.
+ */
+#include "test.h"
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+/* system() on Windows runs its arguments through CMD.EXE, which has
+ * notoriously unfriendly quoting rules. The current best documented way around
+ * them is to wrap your *entire commandline* in sacrificial quotes.
+ *
+ * See CMD.EXE /? for more information. Excerpted here:
+ * | Otherwise, old behavior is to see if the first character is
+ * | a quote character and if so, strip the leading character and
+ * | remove the last quote character on the command line, preserving
+ * | any text after the last quote character.
+ *
+ * Since this test makes heavy use of systemf() with quoted arguments inside
+ * the commandline, this macro is unfortunately an easier workaround.
+ */
+#define systemf(command, ...) systemf("\"" command "\"", __VA_ARGS__)
+#endif
+
+DEFINE_TEST(test_option_mtime)
+{
+ /* Create three files with different mtimes. */
+ assertMakeDir("in", 0755);
+ assertChdir("in");
+ assertMakeFile("new_mtime", 0666, "new");
+ assertUtimes("new_mtime", 100000, 0, 100000, 0);
+ assertMakeFile("mid_mtime", 0666, "mid");
+ assertUtimes("mid_mtime", 10000, 0, 10000, 0);
+ assertMakeFile("old_mtime", 0666, "old");
+ // assertion_utimes silently discards 0 :(
+ assertUtimes("old_mtime", 1, 0, 1, 0);
+
+ /* Archive with --mtime 86400 */
+ assertEqualInt(0,
+ systemf("%s --format pax -cf ../noclamp.tar "
+ "--mtime \"1970/1/2 0:0:0 UTC\" .",
+ testprog));
+ assertChdir("..");
+
+ assertMakeDir("out.noclamp", 0755);
+ assertChdir("out.noclamp");
+ assertEqualInt(0, systemf("%s xf ../noclamp.tar", testprog));
+ assertFileMtime("new_mtime", 86400, 0);
+ assertFileMtime("mid_mtime", 86400, 0);
+ assertFileMtime("old_mtime", 86400, 0);
+ assertChdir("..");
+
+ /* Archive with --mtime 86400 --clamp-mtime */
+ assertChdir("in");
+ assertEqualInt(0,
+ systemf("%s --format pax -cf ../clamp.tar "
+ "--mtime \"1970/1/2 0:0:0 UTC\" --clamp-mtime .",
+ testprog));
+ assertChdir("..");
+
+ assertMakeDir("out.clamp", 0755);
+ assertChdir("out.clamp");
+ assertEqualInt(0, systemf("%s xf ../clamp.tar", testprog));
+ assertFileMtime("new_mtime", 86400, 0);
+ assertFileMtime("mid_mtime", 10000, 0);
+ assertFileMtime("old_mtime", 1, 0);
+ assertChdir("..");
+
+ /* Archive-to-archive copy with --mtime 0 */
+ assertEqualInt(0,
+ systemf("%s --format pax -cf ./archive2archive.tar "
+ "--mtime \"1970/1/1 0:0:0 UTC\" @noclamp.tar",
+ testprog));
+ assertMakeDir("out.archive2archive", 0755);
+ assertChdir("out.archive2archive");
+ assertEqualInt(0, systemf("%s xf ../archive2archive.tar", testprog));
+ assertFileMtime("new_mtime", 0, 0);
+ assertFileMtime("mid_mtime", 0, 0);
+ assertFileMtime("old_mtime", 0, 0);
+ assertChdir("..");
+}
diff --git a/contrib/libarchive/tar/test/test_option_s.c b/contrib/libarchive/tar/test/test_option_s.c
index 1a36280c111f..125e971d3304 100644
--- a/contrib/libarchive/tar/test/test_option_s.c
+++ b/contrib/libarchive/tar/test/test_option_s.c
@@ -70,7 +70,7 @@ DEFINE_TEST(test_option_s)
assertFileContents("bar", 3, "test4/in/d1/baz");
/*
- * Test 4b: Multiple substitutions behavior with option b).
+ * Test 4b: Multiple substitutions behavior with option b.
*/
assertMakeDir("test4b", 0755);
systemf("%s -cf test4b.tar in/d1/foo in/d1/bar",
@@ -81,6 +81,18 @@ DEFINE_TEST(test_option_s)
assertFileContents("bar", 3, "test4b/in/d1/baz");
/*
+ * Test 4bb: Multiple substitutions with option b
+ * (libarchive/libarchive#2414 GitHub issue regression test).
+ */
+ assertMakeDir("test4bb", 0755);
+ systemf("%s -cf test4bb.tar in/d1/foo in/d1/bar",
+ testprog);
+ systemf("%s -xf test4bb.tar -s /oo/ar/ -s }ar}az}b -s :az:end:b -C test4bb",
+ testprog);
+ assertFileContents("foo", 3, "test4bb/in/d1/fend");
+ assertFileContents("bar", 3, "test4bb/in/d1/bend");
+
+ /*
* Test 5: Name-switching substitutions when extracting archive.
*/
assertMakeDir("test5", 0755);
diff --git a/contrib/libarchive/tar/test/test_stdio.c b/contrib/libarchive/tar/test/test_stdio.c
index 0c27c59a2af6..239f3815fb71 100644
--- a/contrib/libarchive/tar/test/test_stdio.c
+++ b/contrib/libarchive/tar/test/test_stdio.c
@@ -6,6 +6,28 @@
*/
#include "test.h"
+/*
+ * This data would fit onto one line, but it's easier to understand when it's
+ * on mulitple lines (and thus matches the output files).
+ */
+static const char *cvf_err =
+"a f\n"
+"a l\n";
+
+static const char *tf_out =
+"f\n"
+"l\n";
+
+static const char *xvf_err =
+"x f\n"
+"x l\n";
+
+/*
+ * This string should appear in the verbose listing regardless of platform,
+ * locale, username, or groupname.
+ */
+static const char * tvf_contains = "l link to f";
+
DEFINE_TEST(test_stdio)
{
FILE *filelist;
@@ -47,35 +69,43 @@ DEFINE_TEST(test_stdio)
failure("'cv' writes filenames to stderr, nothing to stdout (SUSv2)\n"
"Note that GNU tar writes the file list to stdout by default.");
assertEmptyFile("cvf.out");
- /* TODO: Verify cvf.err has file list in SUSv2-prescribed format. */
+ assertTextFileContents(cvf_err, "cvf.err");
/* 'cvf -' should generate file list on stderr, archive on stdout. */
r = systemf("%s cvf - f l >cvf-.out 2>cvf-.err", testprog);
assertEqualInt(r, 0);
failure("cvf - should write archive to stdout");
- /* TODO: Verify cvf-.out has archive. */
failure("cvf - should write file list to stderr (SUSv2)");
- /* TODO: Verify cvf-.err has verbose file list. */
+ assertEqualFile("cvf.err", "cvf-.err");
+ /* Check that stdout from 'cvf -' was a valid archive. */
+ r = systemf("%s tf cvf-.out >cvf-tf.out 2>cvf-tf.err", testprog);
+ assertEqualInt(r, 0);
+ assertEmptyFile("cvf-tf.err");
+ assertTextFileContents(tf_out, "cvf-tf.out");
/* 'tf' should generate file list on stdout, empty stderr. */
r = systemf("%s tf archive >tf.out 2>tf.err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("tf.err");
failure("'t' mode should write results to stdout");
- /* TODO: Verify tf.out has file list. */
+ assertTextFileContents(tf_out, "tf.out");
/* 'tvf' should generate file list on stdout, empty stderr. */
r = systemf("%s tvf archive >tvf.out 2>tvf.err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("tvf.err");
failure("'tv' mode should write results to stdout");
- /* TODO: Verify tvf.out has file list. */
+ /* Check that it contains a string only found in the verbose listing. */
+ p = slurpfile(&s, "%s", "tvf.out");
+ assert(strstr(p, tvf_contains) != NULL);
+ free(p);
/* 'tvf -' uses stdin, file list on stdout, empty stderr. */
r = systemf("%s tvf - < archive >tvf-.out 2>tvf-.err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("tvf-.err");
- /* TODO: Verify tvf-.out has file list. */
+ failure("'tvf-' mode should write the same results as 'tvf'");
+ assertEqualFile("tvf.out", "tvf-.out");
/* Basic 'xf' should generate no output on stdout or stderr. */
r = systemf("%s xf archive >xf.out 2>xf.err", testprog);
@@ -87,7 +117,7 @@ DEFINE_TEST(test_stdio)
r = systemf("%s xvf archive >xvf.out 2>xvf.err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("xvf.out");
- /* TODO: Verify xvf.err */
+ assertTextFileContents(xvf_err, "xvf.err");
/* 'xvOf' should generate list on stderr, file contents on stdout. */
r = systemf("%s xvOf archive >xvOf.out 2>xvOf.err", testprog);
@@ -96,12 +126,12 @@ DEFINE_TEST(test_stdio)
p = slurpfile(&s, "xvOf.out");
assertEqualInt((int)s, 3);
assertEqualMem(p, "abc", 3);
- /* TODO: Verify xvf.err */
+ assertEqualFile("xvf.err", "xvOf.err");
free(p);
/* 'xvf -' should generate list on stderr, empty stdout. */
r = systemf("%s xvf - < archive >xvf-.out 2>xvf-.err", testprog);
assertEqualInt(r, 0);
assertEmptyFile("xvf-.out");
- /* TODO: Verify xvf-.err */
+ assertEqualFile("xvf.err", "xvf-.err");
}
diff --git a/contrib/libarchive/tar/util.c b/contrib/libarchive/tar/util.c
index a152f3506994..c99f67797562 100644
--- a/contrib/libarchive/tar/util.c
+++ b/contrib/libarchive/tar/util.c
@@ -67,26 +67,26 @@ static const char *strip_components(const char *path, int elements);
* malloc()), partly out of expedience (we have to call vsnprintf()
* before malloc() anyway to find out how big a buffer we need; we may
* as well point that first call at a small local buffer in case it
- * works), but mostly for safety (so we can use this to print messages
- * about out-of-memory conditions).
+ * works).
*/
void
-safe_fprintf(FILE *f, const char *fmt, ...)
+safe_fprintf(FILE * restrict f, const char * restrict fmt, ...)
{
char fmtbuff_stack[256]; /* Place to format the printf() string. */
char outbuff[256]; /* Buffer for outgoing characters. */
char *fmtbuff_heap; /* If fmtbuff_stack is too small, we use malloc */
char *fmtbuff; /* Pointer to fmtbuff_stack or fmtbuff_heap. */
- int fmtbuff_length;
+ size_t fmtbuff_length;
int length, n;
va_list ap;
const char *p;
- unsigned i;
+ size_t i;
wchar_t wc;
char try_wc;
/* Use a stack-allocated buffer if we can, for speed and safety. */
+ memset(fmtbuff_stack, '\0', sizeof(fmtbuff_stack));
fmtbuff_heap = NULL;
fmtbuff_length = sizeof(fmtbuff_stack);
fmtbuff = fmtbuff_stack;
@@ -96,17 +96,21 @@ safe_fprintf(FILE *f, const char *fmt, ...)
length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
va_end(ap);
+ /* If vsnprintf will always fail, stop early. */
+ if (length < 0 && errno == EOVERFLOW)
+ return;
+
/* If the result was too large, allocate a buffer on the heap. */
- while (length < 0 || length >= fmtbuff_length) {
- if (length >= fmtbuff_length)
- fmtbuff_length = length+1;
+ while (length < 0 || (size_t)length >= fmtbuff_length) {
+ if (length >= 0 && (size_t)length >= fmtbuff_length)
+ fmtbuff_length = (size_t)length + 1;
else if (fmtbuff_length < 8192)
fmtbuff_length *= 2;
else if (fmtbuff_length < 1000000)
fmtbuff_length += fmtbuff_length / 4;
else {
- length = fmtbuff_length;
- fmtbuff_heap[length-1] = '\0';
+ fmtbuff[fmtbuff_length - 1] = '\0';
+ length = (int)strlen(fmtbuff);
break;
}
free(fmtbuff_heap);
@@ -121,8 +125,9 @@ safe_fprintf(FILE *f, const char *fmt, ...)
} else {
/* Leave fmtbuff pointing to the truncated
* string in fmtbuff_stack. */
+ fmtbuff_stack[sizeof(fmtbuff_stack) - 1] = '\0';
fmtbuff = fmtbuff_stack;
- length = sizeof(fmtbuff_stack) - 1;
+ length = (int)strlen(fmtbuff);
break;
}
}
@@ -153,13 +158,13 @@ safe_fprintf(FILE *f, const char *fmt, ...)
} else {
/* Not printable, format the bytes. */
while (n-- > 0)
- i += (unsigned)bsdtar_expand_char(
+ i += bsdtar_expand_char(
outbuff, sizeof(outbuff), i, *p++);
}
} else {
/* After any conversion failure, don't bother
* trying to convert the rest. */
- i += (unsigned)bsdtar_expand_char(outbuff, sizeof(outbuff), i, *p++);
+ i += bsdtar_expand_char(outbuff, sizeof(outbuff), i, *p++);
try_wc = 0;
}
@@ -202,7 +207,8 @@ bsdtar_expand_char(char *buff, size_t buffsize, size_t offset, char c)
case '\v': buff[i++] = 'v'; break;
case '\\': buff[i++] = '\\'; break;
default:
- snprintf(buff + i, buffsize - i, "%03o", 0xFF & (int)c);
+ snprintf(buff + i, buffsize - i, "%03o",
+ 0xFF & (unsigned int)c);
i += 3;
}
}
@@ -328,7 +334,7 @@ do_chdir(struct bsdtar *bsdtar)
return;
if (chdir(bsdtar->pending_chdir) != 0) {
- lafe_errc(1, 0, "could not chdir to '%s'\n",
+ lafe_errc(1, 0, "could not chdir to '%s'",
bsdtar->pending_chdir);
}
free(bsdtar->pending_chdir);
@@ -562,6 +568,20 @@ edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
}
/*
+ * Apply --mtime and --clamp-mtime options.
+ */
+void
+edit_mtime(struct bsdtar *bsdtar, struct archive_entry *entry)
+{
+ if (!bsdtar->has_mtime)
+ return;
+
+ __LA_TIME_T entry_mtime = archive_entry_mtime(entry);
+ if (!bsdtar->clamp_mtime || entry_mtime > bsdtar->mtime)
+ archive_entry_set_mtime(entry, bsdtar->mtime, 0);
+}
+
+/*
* It would be nice to just use printf() for formatting large numbers,
* but the compatibility problems are quite a headache. Hence the
* following simple utility function.
@@ -684,7 +704,7 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
}
if (!now)
time(&now);
- fprintf(out, "%s %d ",
+ fprintf(out, "%s %u ",
archive_entry_strmode(entry),
archive_entry_nlink(entry));
@@ -748,7 +768,10 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
#else
ltime = localtime(&tim);
#endif
- strftime(tmp, sizeof(tmp), fmt, ltime);
+ if (ltime)
+ strftime(tmp, sizeof(tmp), fmt, ltime);
+ else
+ sprintf(tmp, "-- -- ----");
fprintf(out, " %s ", tmp);
safe_fprintf(out, "%s", archive_entry_pathname(entry));
diff --git a/contrib/libarchive/tar/write.c b/contrib/libarchive/tar/write.c
index f1838d6b5dea..21984e980ebd 100644
--- a/contrib/libarchive/tar/write.c
+++ b/contrib/libarchive/tar/write.c
@@ -682,6 +682,7 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
if ((bsdtar->flags & OPTFLAG_INTERACTIVE) &&
!yes("copy '%s'", archive_entry_pathname(in_entry)))
continue;
+ edit_mtime(bsdtar, in_entry);
if (bsdtar->verbose > 1) {
safe_fprintf(stderr, "a ");
list_item_verbose(bsdtar, stderr, in_entry);
@@ -908,6 +909,9 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
if (edit_pathname(bsdtar, entry))
continue;
+ /* Rewrite the mtime. */
+ edit_mtime(bsdtar, entry);
+
/* Display entry as we process it. */
if (bsdtar->verbose > 1) {
safe_fprintf(stderr, "a ");