MFV r304866:
Sync libarchive with vendor including security fixes Vendor issues fixed: Issue #731: Reject tar entries >= INT64_MAX Issue #744 (part of Issue #743): Enforce sandbox with very long pathnames Issue #748: Zip decompression failure with highly-compressed data Issue #767: Buffer overflow printing a filename Issue #770: Zip read: be more careful about extra_length MFC after: 3 days
This commit is contained in:
commit
c4676089b0
File diff suppressed because it is too large
Load Diff
@ -426,6 +426,7 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi
|
|||||||
#define ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY 0x10000000
|
#define ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY 0x10000000
|
||||||
#define ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS 0x20000000
|
#define ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS 0x20000000
|
||||||
#define ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS 0x40000000
|
#define ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS 0x40000000
|
||||||
|
#define ARCHIVE_ENTRY_ACL_ENTRY_INHERITED 0x80000000
|
||||||
|
|
||||||
#define ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4 \
|
#define ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4 \
|
||||||
(ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT \
|
(ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT \
|
||||||
@ -501,8 +502,8 @@ __LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type
|
|||||||
* ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
|
* ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
|
||||||
* default ACL entry, as used in old Solaris ACLs.
|
* default ACL entry, as used in old Solaris ACLs.
|
||||||
*/
|
*/
|
||||||
#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
|
#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 16384
|
||||||
#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
|
#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 32768
|
||||||
__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
|
__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
|
||||||
int /* flags */);
|
int /* flags */);
|
||||||
__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
|
__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
|
||||||
|
@ -411,75 +411,116 @@ setup_acls(struct archive_read_disk *a,
|
|||||||
{
|
{
|
||||||
const char *accpath;
|
const char *accpath;
|
||||||
acl_t acl;
|
acl_t acl;
|
||||||
#if HAVE_ACL_IS_TRIVIAL_NP
|
|
||||||
int r;
|
int r;
|
||||||
#endif
|
|
||||||
|
|
||||||
accpath = archive_entry_sourcepath(entry);
|
accpath = archive_entry_sourcepath(entry);
|
||||||
if (accpath == NULL)
|
if (accpath == NULL)
|
||||||
accpath = archive_entry_pathname(entry);
|
accpath = archive_entry_pathname(entry);
|
||||||
|
|
||||||
|
if (*fd < 0 && a->tree != NULL) {
|
||||||
|
if (a->follow_symlinks ||
|
||||||
|
archive_entry_filetype(entry) != AE_IFLNK)
|
||||||
|
*fd = a->open_on_current_dir(a->tree,
|
||||||
|
accpath, O_RDONLY | O_NONBLOCK);
|
||||||
|
if (*fd < 0) {
|
||||||
|
if (a->tree_enter_working_dir(a->tree) != 0) {
|
||||||
|
archive_set_error(&a->archive, errno,
|
||||||
|
"Couldn't access %s", accpath);
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
archive_entry_acl_clear(entry);
|
archive_entry_acl_clear(entry);
|
||||||
|
|
||||||
|
acl = NULL;
|
||||||
|
|
||||||
#ifdef ACL_TYPE_NFS4
|
#ifdef ACL_TYPE_NFS4
|
||||||
/* Try NFS4 ACL first. */
|
/* Try NFS4 ACL first. */
|
||||||
|
#if HAVE_ACL_GET_FD_NP
|
||||||
if (*fd >= 0)
|
if (*fd >= 0)
|
||||||
acl = acl_get_fd(*fd);
|
acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4);
|
||||||
|
#endif
|
||||||
|
if (acl == NULL) {
|
||||||
#if HAVE_ACL_GET_LINK_NP
|
#if HAVE_ACL_GET_LINK_NP
|
||||||
else if (!a->follow_symlinks)
|
if (!a->follow_symlinks)
|
||||||
acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
|
acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
|
||||||
#else
|
#else
|
||||||
else if ((!a->follow_symlinks)
|
if ((!a->follow_symlinks)
|
||||||
&& (archive_entry_filetype(entry) == AE_IFLNK))
|
&& (archive_entry_filetype(entry) == AE_IFLNK)) }
|
||||||
/* We can't get the ACL of a symlink, so we assume it can't
|
/* We can't get the ACL of a symlink, so we assume
|
||||||
have one. */
|
it can't have one. */
|
||||||
acl = NULL;
|
acl = NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
|
||||||
acl = acl_get_file(accpath, ACL_TYPE_NFS4);
|
|
||||||
#if HAVE_ACL_IS_TRIVIAL_NP
|
|
||||||
/* Ignore "trivial" ACLs that just mirror the file mode. */
|
|
||||||
acl_is_trivial_np(acl, &r);
|
|
||||||
if (r) {
|
|
||||||
acl_free(acl);
|
|
||||||
acl = NULL;
|
|
||||||
}
|
}
|
||||||
#endif
|
if (acl == NULL)
|
||||||
|
acl = acl_get_file(accpath, ACL_TYPE_NFS4);
|
||||||
|
|
||||||
if (acl != NULL) {
|
if (acl != NULL) {
|
||||||
translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
|
#if HAVE_ACL_IS_TRIVIAL_NP
|
||||||
|
/* Ignore "trivial" ACLs that just mirror the file mode. */
|
||||||
|
if (acl_is_trivial_np(acl, &r) == 0) {
|
||||||
|
if (r) {
|
||||||
|
acl_free(acl);
|
||||||
|
acl = NULL;
|
||||||
|
return (ARCHIVE_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
|
||||||
acl_free(acl);
|
acl_free(acl);
|
||||||
return (ARCHIVE_OK);
|
return (r);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Retrieve access ACL from file. */
|
/* Retrieve access ACL from file. */
|
||||||
if (*fd >= 0)
|
if (*fd >= 0)
|
||||||
acl = acl_get_fd(*fd);
|
acl = acl_get_fd(*fd);
|
||||||
|
if (acl == NULL) {
|
||||||
#if HAVE_ACL_GET_LINK_NP
|
#if HAVE_ACL_GET_LINK_NP
|
||||||
else if (!a->follow_symlinks)
|
if (!a->follow_symlinks)
|
||||||
acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
|
acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
|
||||||
#else
|
#else
|
||||||
else if ((!a->follow_symlinks)
|
if ((!a->follow_symlinks)
|
||||||
&& (archive_entry_filetype(entry) == AE_IFLNK))
|
&& (archive_entry_filetype(entry) == AE_IFLNK)) {
|
||||||
/* We can't get the ACL of a symlink, so we assume it can't
|
/* We can't get the ACL of a symlink, so we assume it
|
||||||
have one. */
|
can't have one. */
|
||||||
acl = NULL;
|
acl = NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
}
|
||||||
|
if (acl == NULL)
|
||||||
acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
|
acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
|
||||||
|
|
||||||
if (acl != NULL) {
|
if (acl != NULL) {
|
||||||
translate_acl(a, entry, acl,
|
#if HAVE_ACL_IS_TRIVIAL_NP
|
||||||
|
/* Ignore "trivial" ACLs that just mirror the file mode. */
|
||||||
|
if (acl_is_trivial_np(acl, &r) == 0) {
|
||||||
|
if (r) {
|
||||||
|
acl_free(acl);
|
||||||
|
acl = NULL;
|
||||||
|
return (ARCHIVE_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
r = translate_acl(a, entry, acl,
|
||||||
ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
|
ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
|
||||||
acl_free(acl);
|
acl_free(acl);
|
||||||
|
acl = NULL;
|
||||||
|
if (r != 0)
|
||||||
|
return (r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only directories can have default ACLs. */
|
/* Only directories can have default ACLs. */
|
||||||
if (S_ISDIR(archive_entry_mode(entry))) {
|
if (S_ISDIR(archive_entry_mode(entry))) {
|
||||||
acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
|
acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
|
||||||
if (acl != NULL) {
|
if (acl != NULL) {
|
||||||
translate_acl(a, entry, acl,
|
r = translate_acl(a, entry, acl,
|
||||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
|
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
|
||||||
acl_free(acl);
|
acl_free(acl);
|
||||||
|
if (r != 0)
|
||||||
|
return (r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (ARCHIVE_OK);
|
return (ARCHIVE_OK);
|
||||||
@ -535,19 +576,23 @@ translate_acl(struct archive_read_disk *a,
|
|||||||
#ifdef ACL_TYPE_NFS4
|
#ifdef ACL_TYPE_NFS4
|
||||||
acl_entry_type_t acl_type;
|
acl_entry_type_t acl_type;
|
||||||
acl_flagset_t acl_flagset;
|
acl_flagset_t acl_flagset;
|
||||||
int brand, r;
|
int brand;
|
||||||
#endif
|
#endif
|
||||||
acl_entry_t acl_entry;
|
acl_entry_t acl_entry;
|
||||||
acl_permset_t acl_permset;
|
acl_permset_t acl_permset;
|
||||||
int i, entry_acl_type;
|
int i, entry_acl_type;
|
||||||
int s, ae_id, ae_tag, ae_perm;
|
int r, s, ae_id, ae_tag, ae_perm;
|
||||||
const char *ae_name;
|
const char *ae_name;
|
||||||
|
|
||||||
#ifdef ACL_TYPE_NFS4
|
#ifdef ACL_TYPE_NFS4
|
||||||
// FreeBSD "brands" ACLs as POSIX.1e or NFSv4
|
// FreeBSD "brands" ACLs as POSIX.1e or NFSv4
|
||||||
// Make sure the "brand" on this ACL is consistent
|
// Make sure the "brand" on this ACL is consistent
|
||||||
// with the default_entry_acl_type bits provided.
|
// with the default_entry_acl_type bits provided.
|
||||||
acl_get_brand_np(acl, &brand);
|
if (acl_get_brand_np(acl, &brand) != 0) {
|
||||||
|
archive_set_error(&a->archive, errno,
|
||||||
|
"Failed to read ACL brand");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
switch (brand) {
|
switch (brand) {
|
||||||
case ACL_BRAND_POSIX:
|
case ACL_BRAND_POSIX:
|
||||||
switch (default_entry_acl_type) {
|
switch (default_entry_acl_type) {
|
||||||
@ -555,31 +600,43 @@ translate_acl(struct archive_read_disk *a,
|
|||||||
case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
|
case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// XXX set warning message?
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||||
return ARCHIVE_FAILED;
|
"Invalid ACL entry type for POSIX.1e ACL");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ACL_BRAND_NFS4:
|
case ACL_BRAND_NFS4:
|
||||||
if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
|
if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
|
||||||
// XXX set warning message?
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||||
return ARCHIVE_FAILED;
|
"ACL brand mismatch");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// XXX set warning message?
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||||
return ARCHIVE_FAILED;
|
"Invalid ACL brand");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
|
s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
|
||||||
|
if (s == -1) {
|
||||||
|
archive_set_error(&a->archive, errno,
|
||||||
|
"Failed to get ACL entry");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
while (s == 1) {
|
while (s == 1) {
|
||||||
ae_id = -1;
|
ae_id = -1;
|
||||||
ae_name = NULL;
|
ae_name = NULL;
|
||||||
ae_perm = 0;
|
ae_perm = 0;
|
||||||
|
|
||||||
acl_get_tag_type(acl_entry, &acl_tag);
|
if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
|
||||||
|
archive_set_error(&a->archive, errno,
|
||||||
|
"Failed to get ACL tag type");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
switch (acl_tag) {
|
switch (acl_tag) {
|
||||||
case ACL_USER:
|
case ACL_USER:
|
||||||
ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
|
ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
|
||||||
@ -619,8 +676,12 @@ translate_acl(struct archive_read_disk *a,
|
|||||||
// non-NFSv4 ACLs
|
// non-NFSv4 ACLs
|
||||||
entry_acl_type = default_entry_acl_type;
|
entry_acl_type = default_entry_acl_type;
|
||||||
#ifdef ACL_TYPE_NFS4
|
#ifdef ACL_TYPE_NFS4
|
||||||
r = acl_get_entry_type_np(acl_entry, &acl_type);
|
if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
|
||||||
if (r == 0) {
|
if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
|
||||||
|
archive_set_error(&a->archive, errno,
|
||||||
|
"Failed to get ACL type from an NFSv4 ACL entry");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
switch (acl_type) {
|
switch (acl_type) {
|
||||||
case ACL_ENTRY_TYPE_ALLOW:
|
case ACL_ENTRY_TYPE_ALLOW:
|
||||||
entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
|
entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
|
||||||
@ -634,40 +695,64 @@ translate_acl(struct archive_read_disk *a,
|
|||||||
case ACL_ENTRY_TYPE_ALARM:
|
case ACL_ENTRY_TYPE_ALARM:
|
||||||
entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
|
entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
archive_set_error(&a->archive, errno,
|
||||||
|
"Unknown NFSv4 ACL entry type: %d", acl_type);
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Libarchive stores "flag" (NFSv4 inheritance bits)
|
* Libarchive stores "flag" (NFSv4 inheritance bits)
|
||||||
* in the ae_perm bitmap.
|
* in the ae_perm bitmap.
|
||||||
*/
|
*/
|
||||||
// XXX acl_get_flagset_np on FreeBSD returns EINVAL for
|
if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
|
||||||
// non-NFSv4 ACLs
|
archive_set_error(&a->archive, errno,
|
||||||
r = acl_get_flagset_np(acl_entry, &acl_flagset);
|
"Failed to get flagset from an NFSv4 ACL entry");
|
||||||
if (r == 0) {
|
return (ARCHIVE_FAILED);
|
||||||
for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
|
}
|
||||||
if (acl_get_flag_np(acl_flagset,
|
for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
|
||||||
acl_inherit_map[i].platform_inherit))
|
r = acl_get_flag_np(acl_flagset, acl_inherit_map[i].platform_inherit);
|
||||||
|
if (r == -1) {
|
||||||
|
archive_set_error(&a->archive, errno,
|
||||||
|
"Failed to check flag in a NFSv4 ACL flagset");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
} else if (r)
|
||||||
ae_perm |= acl_inherit_map[i].archive_inherit;
|
ae_perm |= acl_inherit_map[i].archive_inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
acl_get_permset(acl_entry, &acl_permset);
|
if (acl_get_permset(acl_entry, &acl_permset) != 0) {
|
||||||
|
archive_set_error(&a->archive, errno,
|
||||||
|
"Failed to get ACL permission set");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
|
for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
|
||||||
/*
|
/*
|
||||||
* acl_get_perm() is spelled differently on different
|
* acl_get_perm() is spelled differently on different
|
||||||
* platforms; see above.
|
* platforms; see above.
|
||||||
*/
|
*/
|
||||||
if (ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm))
|
r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm);
|
||||||
|
if (r == -1) {
|
||||||
|
archive_set_error(&a->archive, errno,
|
||||||
|
"Failed to check permission in an ACL permission set");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
} else if (r)
|
||||||
ae_perm |= acl_perm_map[i].archive_perm;
|
ae_perm |= acl_perm_map[i].archive_perm;
|
||||||
}
|
}
|
||||||
|
|
||||||
archive_entry_acl_add_entry(entry, entry_acl_type,
|
r = archive_entry_acl_add_entry(entry, entry_acl_type,
|
||||||
ae_perm, ae_tag,
|
ae_perm, ae_tag,
|
||||||
ae_id, ae_name);
|
ae_id, ae_name);
|
||||||
|
if (r != 0)
|
||||||
|
return (r);
|
||||||
|
|
||||||
s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
|
s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
|
||||||
|
if (s == -1) {
|
||||||
|
archive_set_error(&a->archive, errno,
|
||||||
|
"Failed to get ACL entry");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (ARCHIVE_OK);
|
return (ARCHIVE_OK);
|
||||||
}
|
}
|
||||||
|
@ -203,6 +203,10 @@ static int archive_read_format_tar_read_header(struct archive_read *,
|
|||||||
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 *, const char *key, const char *value);
|
struct archive_entry *, const char *key, const char *value);
|
||||||
|
static int pax_attribute_acl(struct archive_read *, struct tar *,
|
||||||
|
struct archive_entry *, const char *, int);
|
||||||
|
static int pax_attribute_xattr(struct archive_entry *, const char *,
|
||||||
|
const char *);
|
||||||
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);
|
||||||
@ -1128,8 +1132,15 @@ header_common(struct archive_read *a, struct tar *tar,
|
|||||||
if (tar->entry_bytes_remaining < 0) {
|
if (tar->entry_bytes_remaining < 0) {
|
||||||
tar->entry_bytes_remaining = 0;
|
tar->entry_bytes_remaining = 0;
|
||||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||||
"Tar entry has negative size?");
|
"Tar entry has negative size");
|
||||||
err = ARCHIVE_WARN;
|
return (ARCHIVE_FATAL);
|
||||||
|
}
|
||||||
|
if (tar->entry_bytes_remaining == INT64_MAX) {
|
||||||
|
/* Note: tar_atol returns INT64_MAX on overflow */
|
||||||
|
tar->entry_bytes_remaining = 0;
|
||||||
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||||
|
"Tar entry size overflow");
|
||||||
|
return (ARCHIVE_FATAL);
|
||||||
}
|
}
|
||||||
tar->realsize = tar->entry_bytes_remaining;
|
tar->realsize = tar->entry_bytes_remaining;
|
||||||
archive_entry_set_size(entry, tar->entry_bytes_remaining);
|
archive_entry_set_size(entry, tar->entry_bytes_remaining);
|
||||||
@ -1695,6 +1706,52 @@ pax_attribute_xattr(struct archive_entry *entry,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pax_attribute_acl(struct archive_read *a, struct tar *tar,
|
||||||
|
struct archive_entry *entry, const char *value, int type)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
const char* errstr;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
|
||||||
|
errstr = "SCHILY.acl.access";
|
||||||
|
break;
|
||||||
|
case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
|
||||||
|
errstr = "SCHILY.acl.default";
|
||||||
|
break;
|
||||||
|
case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
|
||||||
|
errstr = "SCHILY.acl.ace";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||||
|
"Unknown ACL type: %d", type);
|
||||||
|
return(ARCHIVE_FATAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tar->sconv_acl == NULL) {
|
||||||
|
tar->sconv_acl =
|
||||||
|
archive_string_conversion_from_charset(
|
||||||
|
&(a->archive), "UTF-8", 1);
|
||||||
|
if (tar->sconv_acl == NULL)
|
||||||
|
return (ARCHIVE_FATAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = archive_acl_parse_l(archive_entry_acl(entry), value, type,
|
||||||
|
tar->sconv_acl);
|
||||||
|
if (r != ARCHIVE_OK) {
|
||||||
|
if (r == ARCHIVE_FATAL) {
|
||||||
|
archive_set_error(&a->archive, ENOMEM,
|
||||||
|
"%s %s", "Can't allocate memory for ",
|
||||||
|
errstr);
|
||||||
|
return (r);
|
||||||
|
}
|
||||||
|
archive_set_error(&a->archive,
|
||||||
|
ARCHIVE_ERRNO_MISC, "%s %s", "Parse error: ", errstr);
|
||||||
|
}
|
||||||
|
return (r);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a single key=value attribute. key/value pointers are
|
* Parse a single key=value attribute. key/value pointers are
|
||||||
* assumed to point into reasonably long-lived storage.
|
* assumed to point into reasonably long-lived storage.
|
||||||
@ -1805,53 +1862,20 @@ pax_attribute(struct archive_read *a, struct tar *tar,
|
|||||||
case 'S':
|
case 'S':
|
||||||
/* We support some keys used by the "star" archiver */
|
/* We support some keys used by the "star" archiver */
|
||||||
if (strcmp(key, "SCHILY.acl.access") == 0) {
|
if (strcmp(key, "SCHILY.acl.access") == 0) {
|
||||||
if (tar->sconv_acl == NULL) {
|
r = pax_attribute_acl(a, tar, entry, value,
|
||||||
tar->sconv_acl =
|
ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
|
||||||
archive_string_conversion_from_charset(
|
if (r == ARCHIVE_FATAL)
|
||||||
&(a->archive), "UTF-8", 1);
|
return (r);
|
||||||
if (tar->sconv_acl == NULL)
|
|
||||||
return (ARCHIVE_FATAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = archive_acl_parse_l(archive_entry_acl(entry),
|
|
||||||
value, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
|
||||||
tar->sconv_acl);
|
|
||||||
if (r != ARCHIVE_OK) {
|
|
||||||
err = r;
|
|
||||||
if (err == ARCHIVE_FATAL) {
|
|
||||||
archive_set_error(&a->archive, ENOMEM,
|
|
||||||
"Can't allocate memory for "
|
|
||||||
"SCHILY.acl.access");
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
archive_set_error(&a->archive,
|
|
||||||
ARCHIVE_ERRNO_MISC,
|
|
||||||
"Parse error: SCHILY.acl.access");
|
|
||||||
}
|
|
||||||
} else if (strcmp(key, "SCHILY.acl.default") == 0) {
|
} else if (strcmp(key, "SCHILY.acl.default") == 0) {
|
||||||
if (tar->sconv_acl == NULL) {
|
r = pax_attribute_acl(a, tar, entry, value,
|
||||||
tar->sconv_acl =
|
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
|
||||||
archive_string_conversion_from_charset(
|
if (r == ARCHIVE_FATAL)
|
||||||
&(a->archive), "UTF-8", 1);
|
return (r);
|
||||||
if (tar->sconv_acl == NULL)
|
} else if (strcmp(key, "SCHILY.acl.ace") == 0) {
|
||||||
return (ARCHIVE_FATAL);
|
r = pax_attribute_acl(a, tar, entry, value,
|
||||||
}
|
ARCHIVE_ENTRY_ACL_TYPE_NFS4);
|
||||||
|
if (r == ARCHIVE_FATAL)
|
||||||
r = archive_acl_parse_l(archive_entry_acl(entry),
|
return (r);
|
||||||
value, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
|
|
||||||
tar->sconv_acl);
|
|
||||||
if (r != ARCHIVE_OK) {
|
|
||||||
err = r;
|
|
||||||
if (err == ARCHIVE_FATAL) {
|
|
||||||
archive_set_error(&a->archive, ENOMEM,
|
|
||||||
"Can't allocate memory for "
|
|
||||||
"SCHILY.acl.default");
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
archive_set_error(&a->archive,
|
|
||||||
ARCHIVE_ERRNO_MISC,
|
|
||||||
"Parse error: SCHILY.acl.default");
|
|
||||||
}
|
|
||||||
} else if (strcmp(key, "SCHILY.devmajor") == 0) {
|
} else if (strcmp(key, "SCHILY.devmajor") == 0) {
|
||||||
archive_entry_set_rdevmajor(entry,
|
archive_entry_set_rdevmajor(entry,
|
||||||
(dev_t)tar_atol10(value, strlen(value)));
|
(dev_t)tar_atol10(value, strlen(value)));
|
||||||
|
@ -418,18 +418,30 @@ zip_time(const char *p)
|
|||||||
* id1+size1+data1 + id2+size2+data2 ...
|
* id1+size1+data1 + id2+size2+data2 ...
|
||||||
* triplets. id and size are 2 bytes each.
|
* triplets. id and size are 2 bytes each.
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
|
process_extra(struct archive_read *a, const char *p, size_t extra_length, struct zip_entry* zip_entry)
|
||||||
{
|
{
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
|
|
||||||
while (offset < extra_length - 4) {
|
if (extra_length == 0) {
|
||||||
|
return ARCHIVE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extra_length < 4) {
|
||||||
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||||
|
"Too-small extra data: Need at least 4 bytes, but only found %d bytes", (int)extra_length);
|
||||||
|
return ARCHIVE_FAILED;
|
||||||
|
}
|
||||||
|
while (offset <= extra_length - 4) {
|
||||||
unsigned short headerid = archive_le16dec(p + offset);
|
unsigned short headerid = archive_le16dec(p + offset);
|
||||||
unsigned short datasize = archive_le16dec(p + offset + 2);
|
unsigned short datasize = archive_le16dec(p + offset + 2);
|
||||||
|
|
||||||
offset += 4;
|
offset += 4;
|
||||||
if (offset + datasize > extra_length) {
|
if (offset + datasize > extra_length) {
|
||||||
break;
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||||
|
"Extra data overflow: Need %d bytes but only found %d bytes",
|
||||||
|
(int)datasize, (int)(extra_length - offset));
|
||||||
|
return ARCHIVE_FAILED;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "Header id 0x%04x, length %d\n",
|
fprintf(stderr, "Header id 0x%04x, length %d\n",
|
||||||
@ -715,13 +727,13 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
|
|||||||
}
|
}
|
||||||
offset += datasize;
|
offset += datasize;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
if (offset != extra_length) {
|
||||||
if (offset != extra_length)
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||||
{
|
"Malformed extra data: Consumed %d bytes of %d bytes",
|
||||||
fprintf(stderr,
|
(int)offset, (int)extra_length);
|
||||||
"Extra data field contents do not match reported size!\n");
|
return ARCHIVE_FAILED;
|
||||||
}
|
}
|
||||||
#endif
|
return ARCHIVE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -840,7 +852,9 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
|
|||||||
return (ARCHIVE_FATAL);
|
return (ARCHIVE_FATAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
process_extra(h, extra_length, zip_entry);
|
if (ARCHIVE_OK != process_extra(a, h, extra_length, zip_entry)) {
|
||||||
|
return ARCHIVE_FATAL;
|
||||||
|
}
|
||||||
__archive_read_consume(a, extra_length);
|
__archive_read_consume(a, extra_length);
|
||||||
|
|
||||||
/* Work around a bug in Info-Zip: When reading from a pipe, it
|
/* Work around a bug in Info-Zip: When reading from a pipe, it
|
||||||
@ -1293,7 +1307,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
|
|||||||
&& bytes_avail > zip->entry_bytes_remaining) {
|
&& bytes_avail > zip->entry_bytes_remaining) {
|
||||||
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
|
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
|
||||||
}
|
}
|
||||||
if (bytes_avail <= 0) {
|
if (bytes_avail < 0) {
|
||||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||||
"Truncated ZIP file body");
|
"Truncated ZIP file body");
|
||||||
return (ARCHIVE_FATAL);
|
return (ARCHIVE_FATAL);
|
||||||
@ -2691,7 +2705,9 @@ slurp_central_directory(struct archive_read *a, struct zip *zip)
|
|||||||
"Truncated ZIP file header");
|
"Truncated ZIP file header");
|
||||||
return ARCHIVE_FATAL;
|
return ARCHIVE_FATAL;
|
||||||
}
|
}
|
||||||
process_extra(p + filename_length, extra_length, zip_entry);
|
if (ARCHIVE_OK != process_extra(a, p + filename_length, extra_length, zip_entry)) {
|
||||||
|
return ARCHIVE_FATAL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mac resource fork files are stored under the
|
* Mac resource fork files are stored under the
|
||||||
|
@ -138,6 +138,7 @@ set_acl(struct archive *a, int fd, const char *name,
|
|||||||
acl_permset_t acl_permset;
|
acl_permset_t acl_permset;
|
||||||
#ifdef ACL_TYPE_NFS4
|
#ifdef ACL_TYPE_NFS4
|
||||||
acl_flagset_t acl_flagset;
|
acl_flagset_t acl_flagset;
|
||||||
|
int r;
|
||||||
#endif
|
#endif
|
||||||
int ret;
|
int ret;
|
||||||
int ae_type, ae_permset, ae_tag, ae_id;
|
int ae_type, ae_permset, ae_tag, ae_id;
|
||||||
@ -145,16 +146,25 @@ set_acl(struct archive *a, int fd, const char *name,
|
|||||||
gid_t ae_gid;
|
gid_t ae_gid;
|
||||||
const char *ae_name;
|
const char *ae_name;
|
||||||
int entries;
|
int entries;
|
||||||
int i, r;
|
int i;
|
||||||
|
|
||||||
ret = ARCHIVE_OK;
|
ret = ARCHIVE_OK;
|
||||||
entries = archive_acl_reset(abstract_acl, ae_requested_type);
|
entries = archive_acl_reset(abstract_acl, ae_requested_type);
|
||||||
if (entries == 0)
|
if (entries == 0)
|
||||||
return (ARCHIVE_OK);
|
return (ARCHIVE_OK);
|
||||||
acl = acl_init(entries);
|
acl = acl_init(entries);
|
||||||
|
if (acl == (acl_t)NULL) {
|
||||||
|
archive_set_error(a, errno,
|
||||||
|
"Failed to initialize ACL working storage");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
|
while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
|
||||||
&ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
|
&ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
|
||||||
acl_create_entry(&acl, &acl_entry);
|
if (acl_create_entry(&acl, &acl_entry) != 0) {
|
||||||
|
archive_set_error(a, errno,
|
||||||
|
"Failed to create a new ACL entry");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
switch (ae_tag) {
|
switch (ae_tag) {
|
||||||
case ARCHIVE_ENTRY_ACL_USER:
|
case ARCHIVE_ENTRY_ACL_USER:
|
||||||
@ -185,53 +195,84 @@ set_acl(struct archive *a, int fd, const char *name,
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
/* XXX */
|
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||||
break;
|
"Unknown ACL tag: %d", ae_tag);
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ACL_TYPE_NFS4
|
#ifdef ACL_TYPE_NFS4
|
||||||
|
r = 0;
|
||||||
switch (ae_type) {
|
switch (ae_type) {
|
||||||
case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
|
case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
|
||||||
acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
|
r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
|
||||||
break;
|
break;
|
||||||
case ARCHIVE_ENTRY_ACL_TYPE_DENY:
|
case ARCHIVE_ENTRY_ACL_TYPE_DENY:
|
||||||
acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
|
r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
|
||||||
break;
|
break;
|
||||||
case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
|
case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
|
||||||
acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
|
r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
|
||||||
break;
|
break;
|
||||||
case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
|
case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
|
||||||
acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
|
r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
|
||||||
break;
|
break;
|
||||||
case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
|
case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
|
||||||
case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
|
case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
|
||||||
// These don't translate directly into the system ACL.
|
// These don't translate directly into the system ACL.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// XXX error handling here.
|
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||||
break;
|
"Unknown ACL entry type: %d", ae_type);
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
|
if (r != 0) {
|
||||||
|
archive_set_error(a, errno,
|
||||||
|
"Failed to set ACL entry type");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
acl_get_permset(acl_entry, &acl_permset);
|
if (acl_get_permset(acl_entry, &acl_permset) != 0) {
|
||||||
acl_clear_perms(acl_permset);
|
archive_set_error(a, errno,
|
||||||
|
"Failed to get ACL permission set");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
|
if (acl_clear_perms(acl_permset) != 0) {
|
||||||
|
archive_set_error(a, errno,
|
||||||
|
"Failed to clear ACL permissions");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
|
for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
|
||||||
if (ae_permset & acl_perm_map[i].archive_perm)
|
if (ae_permset & acl_perm_map[i].archive_perm)
|
||||||
acl_add_perm(acl_permset,
|
if (acl_add_perm(acl_permset,
|
||||||
acl_perm_map[i].platform_perm);
|
acl_perm_map[i].platform_perm) != 0) {
|
||||||
|
archive_set_error(a, errno,
|
||||||
|
"Failed to add ACL permission");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ACL_TYPE_NFS4
|
#ifdef ACL_TYPE_NFS4
|
||||||
// XXX acl_get_flagset_np on FreeBSD returns EINVAL for
|
if (acl_type == ACL_TYPE_NFS4) {
|
||||||
// non-NFSv4 ACLs
|
if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
|
||||||
r = acl_get_flagset_np(acl_entry, &acl_flagset);
|
archive_set_error(a, errno,
|
||||||
if (r == 0) {
|
"Failed to get flagset from an NFSv4 ACL entry");
|
||||||
acl_clear_flags_np(acl_flagset);
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
|
if (acl_clear_flags_np(acl_flagset) != 0) {
|
||||||
|
archive_set_error(a, errno,
|
||||||
|
"Failed to clear flags from an NFSv4 ACL flagset");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
|
for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
|
||||||
if (ae_permset & acl_inherit_map[i].archive_inherit)
|
if (ae_permset & acl_inherit_map[i].archive_inherit) {
|
||||||
acl_add_flag_np(acl_flagset,
|
if (acl_add_flag_np(acl_flagset,
|
||||||
acl_inherit_map[i].platform_inherit);
|
acl_inherit_map[i].platform_inherit) != 0) {
|
||||||
|
archive_set_error(a, errno,
|
||||||
|
"Failed to add flag to NFSv4 ACL flagset");
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2401,8 +2401,18 @@ check_symlinks(struct archive_write_disk *a)
|
|||||||
r = lstat(a->name, &st);
|
r = lstat(a->name, &st);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
/* We've hit a dir that doesn't exist; stop now. */
|
/* We've hit a dir that doesn't exist; stop now. */
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT) {
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
/* Note: This effectively disables deep directory
|
||||||
|
* support when security checks are enabled.
|
||||||
|
* Otherwise, very long pathnames that trigger
|
||||||
|
* an error here could evade the sandbox.
|
||||||
|
* TODO: We could do better, but it would probably
|
||||||
|
* require merging the symlink checks with the
|
||||||
|
* deep-directory editing. */
|
||||||
|
return (ARCHIVE_FAILED);
|
||||||
|
}
|
||||||
} else if (S_ISLNK(st.st_mode)) {
|
} else if (S_ISLNK(st.st_mode)) {
|
||||||
if (c == '\0') {
|
if (c == '\0') {
|
||||||
/*
|
/*
|
||||||
|
@ -70,6 +70,8 @@ static void add_pax_attr_int(struct archive_string *,
|
|||||||
static void add_pax_attr_time(struct archive_string *,
|
static void add_pax_attr_time(struct archive_string *,
|
||||||
const char *key, int64_t sec,
|
const char *key, int64_t sec,
|
||||||
unsigned long nanos);
|
unsigned long nanos);
|
||||||
|
static int add_pax_acl(struct archive_write *,
|
||||||
|
struct archive_entry *, struct pax *, int);
|
||||||
static ssize_t archive_write_pax_data(struct archive_write *,
|
static ssize_t archive_write_pax_data(struct archive_write *,
|
||||||
const void *, size_t);
|
const void *, size_t);
|
||||||
static int archive_write_pax_close(struct archive_write *);
|
static int archive_write_pax_close(struct archive_write *);
|
||||||
@ -450,6 +452,43 @@ get_entry_symlink(struct archive_write *a, struct archive_entry *entry,
|
|||||||
return (ARCHIVE_OK);
|
return (ARCHIVE_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add ACL to pax header */
|
||||||
|
static int
|
||||||
|
add_pax_acl(struct archive_write *a,
|
||||||
|
struct archive_entry *entry, struct pax *pax, int flags)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
const char *attr;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS)
|
||||||
|
attr = "SCHILY.acl.access";
|
||||||
|
else if (flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
|
||||||
|
attr = "SCHILY.acl.default";
|
||||||
|
else if (flags & ARCHIVE_ENTRY_ACL_TYPE_NFS4)
|
||||||
|
attr = "SCHILY.acl.ace";
|
||||||
|
else
|
||||||
|
return(ARCHIVE_FATAL);
|
||||||
|
|
||||||
|
r = archive_entry_acl_text_l(entry, flags, &p, NULL,
|
||||||
|
pax->sconv_utf8);
|
||||||
|
if (r != 0) {
|
||||||
|
if (errno == ENOMEM) {
|
||||||
|
archive_set_error(&a->archive, ENOMEM, "%s %s",
|
||||||
|
"Can't allocate memory for ", attr);
|
||||||
|
return (ARCHIVE_FATAL);
|
||||||
|
}
|
||||||
|
archive_set_error(&a->archive,
|
||||||
|
ARCHIVE_ERRNO_FILE_FORMAT, "%s %s %s",
|
||||||
|
"Can't translate ", attr, " to UTF-8");
|
||||||
|
return(ARCHIVE_WARN);
|
||||||
|
} else if (p != NULL && *p != '\0') {
|
||||||
|
add_pax_attr(&(pax->pax_header),
|
||||||
|
attr, p);
|
||||||
|
}
|
||||||
|
return(ARCHIVE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: Consider adding 'comment' and 'charset' fields to
|
* TODO: Consider adding 'comment' and 'charset' fields to
|
||||||
* archive_entry so that clients can specify them. Also, consider
|
* archive_entry so that clients can specify them. Also, consider
|
||||||
@ -466,6 +505,7 @@ archive_write_pax_header(struct archive_write *a,
|
|||||||
const char *p;
|
const char *p;
|
||||||
const char *suffix;
|
const char *suffix;
|
||||||
int need_extension, r, ret;
|
int need_extension, r, ret;
|
||||||
|
int acl_access, acl_default, acl_nfs4;
|
||||||
int sparse_count;
|
int sparse_count;
|
||||||
uint64_t sparse_total, real_size;
|
uint64_t sparse_total, real_size;
|
||||||
struct pax *pax;
|
struct pax *pax;
|
||||||
@ -1017,16 +1057,6 @@ archive_write_pax_header(struct archive_write *a,
|
|||||||
if (!need_extension && p != NULL && *p != '\0')
|
if (!need_extension && p != NULL && *p != '\0')
|
||||||
need_extension = 1;
|
need_extension = 1;
|
||||||
|
|
||||||
/* If there are non-trivial ACL entries, we need an extension. */
|
|
||||||
if (!need_extension && archive_entry_acl_count(entry_original,
|
|
||||||
ARCHIVE_ENTRY_ACL_TYPE_ACCESS) > 0)
|
|
||||||
need_extension = 1;
|
|
||||||
|
|
||||||
/* If there are non-trivial ACL entries, we need an extension. */
|
|
||||||
if (!need_extension && archive_entry_acl_count(entry_original,
|
|
||||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) > 0)
|
|
||||||
need_extension = 1;
|
|
||||||
|
|
||||||
/* If there are extended attributes, we need an extension */
|
/* If there are extended attributes, we need an extension */
|
||||||
if (!need_extension && archive_entry_xattr_count(entry_original) > 0)
|
if (!need_extension && archive_entry_xattr_count(entry_original) > 0)
|
||||||
need_extension = 1;
|
need_extension = 1;
|
||||||
@ -1035,6 +1065,17 @@ archive_write_pax_header(struct archive_write *a,
|
|||||||
if (!need_extension && sparse_count > 0)
|
if (!need_extension && sparse_count > 0)
|
||||||
need_extension = 1;
|
need_extension = 1;
|
||||||
|
|
||||||
|
acl_access = archive_entry_acl_count(entry_original,
|
||||||
|
ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
|
||||||
|
acl_default = archive_entry_acl_count(entry_original,
|
||||||
|
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
|
||||||
|
acl_nfs4 = archive_entry_acl_count(entry_original,
|
||||||
|
ARCHIVE_ENTRY_ACL_TYPE_NFS4);
|
||||||
|
|
||||||
|
/* If there are any ACL entries, we need an extension */
|
||||||
|
if (!need_extension && (acl_access + acl_default + acl_nfs4) > 0)
|
||||||
|
need_extension = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Libarchive used to include these in extended headers for
|
* Libarchive used to include these in extended headers for
|
||||||
* restricted pax format, but that confused people who
|
* restricted pax format, but that confused people who
|
||||||
@ -1086,43 +1127,26 @@ archive_write_pax_header(struct archive_write *a,
|
|||||||
add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);
|
add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);
|
||||||
|
|
||||||
/* I use star-compatible ACL attributes. */
|
/* I use star-compatible ACL attributes. */
|
||||||
r = archive_entry_acl_text_l(entry_original,
|
if (acl_access > 0) {
|
||||||
ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
|
ret = add_pax_acl(a, entry_original, pax,
|
||||||
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID,
|
ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
|
||||||
&p, NULL, pax->sconv_utf8);
|
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
|
||||||
if (r != 0) {
|
if (ret == ARCHIVE_FATAL)
|
||||||
if (errno == ENOMEM) {
|
|
||||||
archive_set_error(&a->archive, ENOMEM,
|
|
||||||
"Can't allocate memory for "
|
|
||||||
"ACL.access");
|
|
||||||
return (ARCHIVE_FATAL);
|
return (ARCHIVE_FATAL);
|
||||||
}
|
|
||||||
archive_set_error(&a->archive,
|
|
||||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
|
||||||
"Can't translate ACL.access to UTF-8");
|
|
||||||
ret = ARCHIVE_WARN;
|
|
||||||
} else if (p != NULL && *p != '\0') {
|
|
||||||
add_pax_attr(&(pax->pax_header),
|
|
||||||
"SCHILY.acl.access", p);
|
|
||||||
}
|
}
|
||||||
r = archive_entry_acl_text_l(entry_original,
|
if (acl_default > 0) {
|
||||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
|
ret = add_pax_acl(a, entry_original, pax,
|
||||||
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID,
|
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
|
||||||
&p, NULL, pax->sconv_utf8);
|
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
|
||||||
if (r != 0) {
|
if (ret == ARCHIVE_FATAL)
|
||||||
if (errno == ENOMEM) {
|
return (ARCHIVE_FATAL);
|
||||||
archive_set_error(&a->archive, ENOMEM,
|
}
|
||||||
"Can't allocate memory for "
|
if (acl_nfs4 > 0) {
|
||||||
"ACL.default");
|
ret = add_pax_acl(a, entry_original, pax,
|
||||||
|
ARCHIVE_ENTRY_ACL_TYPE_NFS4 |
|
||||||
|
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
|
||||||
|
if (ret == ARCHIVE_FATAL)
|
||||||
return (ARCHIVE_FATAL);
|
return (ARCHIVE_FATAL);
|
||||||
}
|
|
||||||
archive_set_error(&a->archive,
|
|
||||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
|
||||||
"Can't translate ACL.default to UTF-8");
|
|
||||||
ret = ARCHIVE_WARN;
|
|
||||||
} else if (p != NULL && *p != '\0') {
|
|
||||||
add_pax_attr(&(pax->pax_header),
|
|
||||||
"SCHILY.acl.default", p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We use GNU-tar-compatible sparse attributes. */
|
/* We use GNU-tar-compatible sparse attributes. */
|
||||||
|
@ -182,7 +182,7 @@ safe_fprintf(FILE *f, const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If our output buffer is full, dump it and keep going. */
|
/* If our output buffer is full, dump it and keep going. */
|
||||||
if (i > (sizeof(outbuff) - 20)) {
|
if (i > (sizeof(outbuff) - 128)) {
|
||||||
outbuff[i] = '\0';
|
outbuff[i] = '\0';
|
||||||
fprintf(f, "%s", outbuff);
|
fprintf(f, "%s", outbuff);
|
||||||
i = 0;
|
i = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user