Merge branch 'update-libarchive' into release

This commit is contained in:
Brad King 2016-06-20 10:53:25 -04:00
commit d38fc22132
19 changed files with 88 additions and 49 deletions

View File

@ -1 +1 @@
3002000 3002001

View File

@ -36,7 +36,7 @@
* assert that ARCHIVE_VERSION_NUMBER >= 2012108. * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/ */
/* Note: Compiler will complain if this does not match archive_entry.h! */ /* Note: Compiler will complain if this does not match archive_entry.h! */
#define ARCHIVE_VERSION_NUMBER 3002000 #define ARCHIVE_VERSION_NUMBER 3002001
#include <sys/stat.h> #include <sys/stat.h>
#include <stddef.h> /* for wchar_t */ #include <stddef.h> /* for wchar_t */
@ -152,7 +152,7 @@ __LA_DECL int archive_version_number(void);
/* /*
* Textual name/version of the library, useful for version displays. * Textual name/version of the library, useful for version displays.
*/ */
#define ARCHIVE_VERSION_ONLY_STRING "3.2.0" #define ARCHIVE_VERSION_ONLY_STRING "3.2.1"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING #define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void); __LA_DECL const char * archive_version_string(void);

View File

@ -29,7 +29,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED #define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */ /* Note: Compiler will complain if this does not match archive.h! */
#define ARCHIVE_VERSION_NUMBER 3002000 #define ARCHIVE_VERSION_NUMBER 3002001
/* /*
* Note: archive_entry.h is for use outside of libarchive; the * Note: archive_entry.h is for use outside of libarchive; the

View File

@ -91,16 +91,11 @@ archive_entry_xattr_add_entry(struct archive_entry *entry,
{ {
struct ae_xattr *xp; struct ae_xattr *xp;
for (xp = entry->xattr_head; xp != NULL; xp = xp->next)
;
if ((xp = (struct ae_xattr *)malloc(sizeof(struct ae_xattr))) == NULL) if ((xp = (struct ae_xattr *)malloc(sizeof(struct ae_xattr))) == NULL)
/* XXX Error XXX */ __archive_errx(1, "Out of memory");
return;
if ((xp->name = strdup(name)) == NULL) if ((xp->name = strdup(name)) == NULL)
/* XXX Error XXX */ __archive_errx(1, "Out of memory");
return;
if ((xp->value = malloc(size)) != NULL) { if ((xp->value = malloc(size)) != NULL) {
memcpy(xp->value, value, size); memcpy(xp->value, value, size);

View File

@ -126,6 +126,11 @@ static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
{ {
if (p->Base == 0 || p->Size != size) if (p->Base == 0 || p->Size != size)
{ {
/* RestartModel() below assumes that p->Size >= UNIT_SIZE
(see the calculation of m->MinContext). */
if (size < UNIT_SIZE) {
return False;
}
Ppmd7_Free(p, alloc); Ppmd7_Free(p, alloc);
p->AlignOffset = p->AlignOffset =
#ifdef PPMD_32BIT #ifdef PPMD_32BIT

View File

@ -2153,6 +2153,9 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
return (-1); return (-1);
if (UMAX_ENTRY < f[i].numUnpackStreams) if (UMAX_ENTRY < f[i].numUnpackStreams)
return (-1); return (-1);
if (unpack_streams > SIZE_MAX - UMAX_ENTRY) {
return (-1);
}
unpack_streams += (size_t)f[i].numUnpackStreams; unpack_streams += (size_t)f[i].numUnpackStreams;
} }
if ((p = header_bytes(a, 1)) == NULL) if ((p = header_bytes(a, 1)) == NULL)

View File

@ -401,6 +401,11 @@ archive_read_format_cpio_read_header(struct archive_read *a,
/* If this is a symlink, read the link contents. */ /* If this is a symlink, read the link contents. */
if (archive_entry_filetype(entry) == AE_IFLNK) { if (archive_entry_filetype(entry) == AE_IFLNK) {
if (cpio->entry_bytes_remaining > 1024 * 1024) {
archive_set_error(&a->archive, ENOMEM,
"Rejecting malformed cpio archive: symlink contents exceed 1 megabyte");
return (ARCHIVE_FATAL);
}
h = __archive_read_ahead(a, h = __archive_read_ahead(a,
(size_t)cpio->entry_bytes_remaining, NULL); (size_t)cpio->entry_bytes_remaining, NULL);
if (h == NULL) if (h == NULL)

View File

@ -1091,7 +1091,7 @@ choose_volume(struct archive_read *a, struct iso9660 *iso9660)
/* This condition is unlikely; by way of caution. */ /* This condition is unlikely; by way of caution. */
vd = &(iso9660->joliet); vd = &(iso9660->joliet);
skipsize = LOGICAL_BLOCK_SIZE * vd->location; skipsize = LOGICAL_BLOCK_SIZE * (int64_t)vd->location;
skipsize = __archive_read_consume(a, skipsize); skipsize = __archive_read_consume(a, skipsize);
if (skipsize < 0) if (skipsize < 0)
return ((int)skipsize); return ((int)skipsize);
@ -1129,7 +1129,7 @@ choose_volume(struct archive_read *a, struct iso9660 *iso9660)
&& iso9660->seenJoliet) { && iso9660->seenJoliet) {
/* Switch reading data from primary to joliet. */ /* Switch reading data from primary to joliet. */
vd = &(iso9660->joliet); vd = &(iso9660->joliet);
skipsize = LOGICAL_BLOCK_SIZE * vd->location; skipsize = LOGICAL_BLOCK_SIZE * (int64_t)vd->location;
skipsize -= iso9660->current_position; skipsize -= iso9660->current_position;
skipsize = __archive_read_consume(a, skipsize); skipsize = __archive_read_consume(a, skipsize);
if (skipsize < 0) if (skipsize < 0)

View File

@ -1342,7 +1342,7 @@ parse_line(struct archive_read *a, struct archive_entry *entry,
/* strsep() is not in C90, but strcspn() is. */ /* strsep() is not in C90, but strcspn() is. */
/* Taken from http://unixpapa.com/incnote/string.html */ /* Taken from http://unixpapa.com/incnote/string.html */
static char * static char *
la_strsep(char **sp, char *sep) la_strsep(char **sp, const char *sep)
{ {
char *p, *s; char *p, *s;
if (sp == NULL || *sp == NULL || **sp == '\0') if (sp == NULL || *sp == NULL || **sp == '\0')
@ -1385,12 +1385,12 @@ parse_device(dev_t *pdev, struct archive *a, char *val)
"Missing number"); "Missing number");
return ARCHIVE_WARN; return ARCHIVE_WARN;
} }
numbers[argc++] = (unsigned long)mtree_atol(&p); if (argc >= MAX_PACK_ARGS) {
if (argc > MAX_PACK_ARGS) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
"Too many arguments"); "Too many arguments");
return ARCHIVE_WARN; return ARCHIVE_WARN;
} }
numbers[argc++] = (unsigned long)mtree_atol(&p);
} }
if (argc < 2) { if (argc < 2) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,

View File

@ -2127,6 +2127,12 @@ parse_codes(struct archive_read *a)
rar->range_dec.Stream = &rar->bytein; rar->range_dec.Stream = &rar->bytein;
__archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context); __archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context);
if (rar->dictionary_size == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid zero dictionary size");
return (ARCHIVE_FATAL);
}
if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context, if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
rar->dictionary_size, &g_szalloc)) rar->dictionary_size, &g_szalloc))
{ {
@ -2884,11 +2890,10 @@ copy_from_lzss_window(struct archive_read *a, const void **buffer,
} }
windowoffs = lzss_offset_for_position(&rar->lzss, startpos); windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
if(windowoffs + length <= lzss_size(&rar->lzss)) if(windowoffs + length <= lzss_size(&rar->lzss)) {
memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs], memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs],
length); length);
else } else if (length <= lzss_size(&rar->lzss)) {
{
firstpart = lzss_size(&rar->lzss) - windowoffs; firstpart = lzss_size(&rar->lzss) - windowoffs;
if (firstpart < 0) { if (firstpart < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@ -2900,9 +2905,14 @@ copy_from_lzss_window(struct archive_read *a, const void **buffer,
&rar->lzss.window[windowoffs], firstpart); &rar->lzss.window[windowoffs], firstpart);
memcpy(&rar->unp_buffer[rar->unp_offset + firstpart], memcpy(&rar->unp_buffer[rar->unp_offset + firstpart],
&rar->lzss.window[0], length - firstpart); &rar->lzss.window[0], length - firstpart);
} else } else {
memcpy(&rar->unp_buffer[rar->unp_offset], memcpy(&rar->unp_buffer[rar->unp_offset],
&rar->lzss.window[windowoffs], length); &rar->lzss.window[windowoffs], length);
}
} else {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file data");
return (ARCHIVE_FATAL);
} }
rar->unp_offset += length; rar->unp_offset += length;
if (rar->unp_offset >= rar->unp_buffer_size) if (rar->unp_offset >= rar->unp_buffer_size)

View File

@ -202,7 +202,7 @@ static int archive_read_format_tar_read_header(struct archive_read *,
struct archive_entry *); struct archive_entry *);
static int checksum(struct archive_read *, const void *); static int checksum(struct archive_read *, const void *);
static int pax_attribute(struct archive_read *, struct tar *, static int pax_attribute(struct archive_read *, struct tar *,
struct archive_entry *, char *key, char *value); struct archive_entry *, const char *key, const char *value);
static int pax_header(struct archive_read *, struct tar *, static int pax_header(struct archive_read *, struct tar *,
struct archive_entry *, char *attr); struct archive_entry *, char *attr);
static void pax_time(const char *, int64_t *sec, long *nanos); static void pax_time(const char *, int64_t *sec, long *nanos);
@ -1664,7 +1664,7 @@ pax_header(struct archive_read *a, struct tar *tar,
static int static int
pax_attribute_xattr(struct archive_entry *entry, pax_attribute_xattr(struct archive_entry *entry,
char *name, char *value) const char *name, const char *value)
{ {
char *name_decoded; char *name_decoded;
void *value_decoded; void *value_decoded;
@ -1710,7 +1710,7 @@ pax_attribute_xattr(struct archive_entry *entry,
*/ */
static int static int
pax_attribute(struct archive_read *a, struct tar *tar, pax_attribute(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, char *key, char *value) struct archive_entry *entry, const char *key, const char *value)
{ {
int64_t s; int64_t s;
long n; long n;

View File

@ -181,6 +181,14 @@ struct zip {
char init_decryption; char init_decryption;
/* Decryption buffer. */ /* Decryption buffer. */
/*
* The decrypted data starts at decrypted_ptr and
* extends for decrypted_bytes_remaining. Decryption
* adds new data to the end of this block, data is returned
* to clients from the beginning. When the block hits the
* end of decrypted_buffer, it has to be shuffled back to
* the beginning of the buffer.
*/
unsigned char *decrypted_buffer; unsigned char *decrypted_buffer;
unsigned char *decrypted_ptr; unsigned char *decrypted_ptr;
size_t decrypted_buffer_size; size_t decrypted_buffer_size;
@ -1293,8 +1301,9 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
if (zip->tctx_valid || zip->cctx_valid) { if (zip->tctx_valid || zip->cctx_valid) {
if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) { if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) {
size_t buff_remaining = zip->decrypted_buffer_size size_t buff_remaining =
- (zip->decrypted_ptr - zip->decrypted_buffer); (zip->decrypted_buffer + zip->decrypted_buffer_size)
- (zip->decrypted_ptr + zip->decrypted_bytes_remaining);
if (buff_remaining > (size_t)bytes_avail) if (buff_remaining > (size_t)bytes_avail)
buff_remaining = (size_t)bytes_avail; buff_remaining = (size_t)bytes_avail;

View File

@ -468,9 +468,17 @@ permissive_name_w(struct archive_write_disk *a)
return (-1); return (-1);
archive_wstring_ensure(&(a->_name_data), 4 + l + 1 + wcslen(wn) + 1); archive_wstring_ensure(&(a->_name_data), 4 + l + 1 + wcslen(wn) + 1);
a->name = a->_name_data.s; a->name = a->_name_data.s;
/* Prepend "\\?\" and drive name. */ /* Prepend "\\?\" and drive name if not already added. */
archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4); if (l > 3 && wsp[0] == L'\\' && wsp[1] == L'\\' &&
archive_wstrncat(&(a->_name_data), wsp, l); wsp[2] == L'?' && wsp[3] == L'\\')
{
archive_wstrncpy(&(a->_name_data), wsp, l);
}
else
{
archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
archive_wstrncat(&(a->_name_data), wsp, l);
}
archive_wstrncat(&(a->_name_data), L"\\", 1); archive_wstrncat(&(a->_name_data), L"\\", 1);
archive_wstrcat(&(a->_name_data), wn); archive_wstrcat(&(a->_name_data), wn);
a->name = a->_name_data.s; a->name = a->_name_data.s;

View File

@ -43,6 +43,7 @@
.Nm archive_write_add_filter_program , .Nm archive_write_add_filter_program ,
.Nm archive_write_add_filter_uuencode , .Nm archive_write_add_filter_uuencode ,
.Nm archive_write_add_filter_xz .Nm archive_write_add_filter_xz
.Nd functions enabling output filters
.Sh LIBRARY .Sh LIBRARY
Streaming Archive Library (libarchive, -larchive) Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS .Sh SYNOPSIS

View File

@ -467,7 +467,7 @@ archive_write_gnutar_header(struct archive_write *a,
} }
} }
if (gnutar->linkname_length > GNUTAR_linkname_size) { if (gnutar->linkname_length > GNUTAR_linkname_size) {
size_t todo = gnutar->linkname_length; size_t length = gnutar->linkname_length + 1;
struct archive_entry *temp = archive_entry_new2(&a->archive); struct archive_entry *temp = archive_entry_new2(&a->archive);
/* Uname/gname here don't really matter since no one reads them; /* Uname/gname here don't really matter since no one reads them;
@ -476,7 +476,7 @@ archive_write_gnutar_header(struct archive_write *a,
archive_entry_set_gname(temp, "wheel"); archive_entry_set_gname(temp, "wheel");
archive_entry_set_pathname(temp, "././@LongLink"); archive_entry_set_pathname(temp, "././@LongLink");
archive_entry_set_size(temp, gnutar->linkname_length + 1); archive_entry_set_size(temp, length);
ret = archive_format_gnutar_header(a, buff, temp, 'K'); ret = archive_format_gnutar_header(a, buff, temp, 'K');
if (ret < ARCHIVE_WARN) if (ret < ARCHIVE_WARN)
goto exit_write_header; goto exit_write_header;
@ -484,11 +484,12 @@ archive_write_gnutar_header(struct archive_write *a,
if(ret < ARCHIVE_WARN) if(ret < ARCHIVE_WARN)
goto exit_write_header; goto exit_write_header;
archive_entry_free(temp); archive_entry_free(temp);
/* Write as many 512 bytes blocks as needed to write full name. */ /* Write name and trailing null byte. */
ret = __archive_write_output(a, gnutar->linkname, todo); ret = __archive_write_output(a, gnutar->linkname, length);
if(ret < ARCHIVE_WARN) if(ret < ARCHIVE_WARN)
goto exit_write_header; goto exit_write_header;
ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo)); /* Pad to 512 bytes */
ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));
if (ret < ARCHIVE_WARN) if (ret < ARCHIVE_WARN)
goto exit_write_header; goto exit_write_header;
} }
@ -496,7 +497,7 @@ archive_write_gnutar_header(struct archive_write *a,
/* If pathname is longer than 100 chars we need to add an 'L' header. */ /* If pathname is longer than 100 chars we need to add an 'L' header. */
if (gnutar->pathname_length > GNUTAR_name_size) { if (gnutar->pathname_length > GNUTAR_name_size) {
const char *pathname = gnutar->pathname; const char *pathname = gnutar->pathname;
size_t todo = gnutar->pathname_length; size_t length = gnutar->pathname_length + 1;
struct archive_entry *temp = archive_entry_new2(&a->archive); struct archive_entry *temp = archive_entry_new2(&a->archive);
/* Uname/gname here don't really matter since no one reads them; /* Uname/gname here don't really matter since no one reads them;
@ -505,7 +506,7 @@ archive_write_gnutar_header(struct archive_write *a,
archive_entry_set_gname(temp, "wheel"); archive_entry_set_gname(temp, "wheel");
archive_entry_set_pathname(temp, "././@LongLink"); archive_entry_set_pathname(temp, "././@LongLink");
archive_entry_set_size(temp, gnutar->pathname_length + 1); archive_entry_set_size(temp, length);
ret = archive_format_gnutar_header(a, buff, temp, 'L'); ret = archive_format_gnutar_header(a, buff, temp, 'L');
if (ret < ARCHIVE_WARN) if (ret < ARCHIVE_WARN)
goto exit_write_header; goto exit_write_header;
@ -513,11 +514,12 @@ archive_write_gnutar_header(struct archive_write *a,
if(ret < ARCHIVE_WARN) if(ret < ARCHIVE_WARN)
goto exit_write_header; goto exit_write_header;
archive_entry_free(temp); archive_entry_free(temp);
/* Write as many 512 bytes blocks as needed to write full name. */ /* Write pathname + trailing null byte. */
ret = __archive_write_output(a, pathname, todo); ret = __archive_write_output(a, pathname, length);
if(ret < ARCHIVE_WARN) if(ret < ARCHIVE_WARN)
goto exit_write_header; goto exit_write_header;
ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo)); /* Pad to multiple of 512 bytes. */
ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));
if (ret < ARCHIVE_WARN) if (ret < ARCHIVE_WARN)
goto exit_write_header; goto exit_write_header;
} }

View File

@ -6225,7 +6225,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
unsigned char *p; unsigned char *p;
size_t l; size_t l;
int r; int r;
int ffmax, parent_len; size_t ffmax, parent_len;
static const struct archive_rb_tree_ops rb_ops = { static const struct archive_rb_tree_ops rb_ops = {
isoent_cmp_node_joliet, isoent_cmp_key_joliet isoent_cmp_node_joliet, isoent_cmp_key_joliet
}; };
@ -6239,7 +6239,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
else else
ffmax = 128; ffmax = 128;
r = idr_start(a, idr, isoent->children.cnt, ffmax, 6, 2, &rb_ops); r = idr_start(a, idr, isoent->children.cnt, (int)ffmax, 6, 2, &rb_ops);
if (r < 0) if (r < 0)
return (r); return (r);
@ -6252,7 +6252,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
int ext_off, noff, weight; int ext_off, noff, weight;
size_t lt; size_t lt;
if ((int)(l = np->file->basename_utf16.length) > ffmax) if ((l = np->file->basename_utf16.length) > ffmax)
l = ffmax; l = ffmax;
p = malloc((l+1)*2); p = malloc((l+1)*2);
@ -6285,7 +6285,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
/* /*
* Get a length of MBS of a full-pathname. * Get a length of MBS of a full-pathname.
*/ */
if ((int)np->file->basename_utf16.length > ffmax) { if (np->file->basename_utf16.length > ffmax) {
if (archive_strncpy_l(&iso9660->mbs, if (archive_strncpy_l(&iso9660->mbs,
(const char *)np->identifier, l, (const char *)np->identifier, l,
iso9660->sconv_from_utf16be) != 0 && iso9660->sconv_from_utf16be) != 0 &&
@ -6302,7 +6302,9 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
/* If a length of full-pathname is longer than 240 bytes, /* If a length of full-pathname is longer than 240 bytes,
* it violates Joliet extensions regulation. */ * it violates Joliet extensions regulation. */
if (parent_len + np->mb_len > 240) { if (parent_len > 240
|| np->mb_len > 240
|| parent_len + np->mb_len > 240) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"The regulation of Joliet extensions;" "The regulation of Joliet extensions;"
" A length of a full-pathname of `%s' is " " A length of a full-pathname of `%s' is "
@ -6314,11 +6316,11 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
/* Make an offset of the number which is used to be set /* Make an offset of the number which is used to be set
* hexadecimal number to avoid duplicate identifier. */ * hexadecimal number to avoid duplicate identifier. */
if ((int)l == ffmax) if (l == ffmax)
noff = ext_off - 6; noff = ext_off - 6;
else if ((int)l == ffmax-2) else if (l == ffmax-2)
noff = ext_off - 4; noff = ext_off - 4;
else if ((int)l == ffmax-4) else if (l == ffmax-4)
noff = ext_off - 2; noff = ext_off - 2;
else else
noff = ext_off; noff = ext_off;

View File

@ -32,7 +32,7 @@
.Nm archive_write_set_format_option , .Nm archive_write_set_format_option ,
.Nm archive_write_set_option , .Nm archive_write_set_option ,
.Nm archive_write_set_options .Nm archive_write_set_options
.Nd functions controlling options for reading archives .Nd functions controlling options for writing archives
.Sh LIBRARY .Sh LIBRARY
Streaming Archive Library (libarchive, -larchive) Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS .Sh SYNOPSIS

View File

@ -65,7 +65,6 @@ Later variants have extended this by either appropriating undefined
areas of the header record, extending the header to multiple records, areas of the header record, extending the header to multiple records,
or by storing special entries that modify the interpretation of or by storing special entries that modify the interpretation of
subsequent entries. subsequent entries.
.Pp
.Bl -tag -width indent .Bl -tag -width indent
.It Cm gnutar .It Cm gnutar
The The

View File

@ -28,7 +28,7 @@
.Dt LIBARCHIVE_CHANGES 3 .Dt LIBARCHIVE_CHANGES 3
.Os .Os
.Sh NAME .Sh NAME
.Nm changes in libarchive interface .Nd changes in libarchive interface
.\" .\"
.Sh CHANGES IN LIBARCHIVE 3 .Sh CHANGES IN LIBARCHIVE 3
This page describes user-visible changes in libarchive3, and lists This page describes user-visible changes in libarchive3, and lists