MFV r340938:
Sync libarchive with vendor. Relevant vendor changes: Issue #1096: Support extracting ACLs with in-entry comments (GNU tar) PR #1023: Support extracting extattrs as non-root on non-user-writeable files MFC after: 1 week
This commit is contained in:
parent
8894b8e317
commit
c4065f2d8a
@ -1585,17 +1585,29 @@ next_field_w(const wchar_t **wp, const wchar_t **start,
|
||||
|
||||
/* Scan for the separator. */
|
||||
while (**wp != L'\0' && **wp != L',' && **wp != L':' &&
|
||||
**wp != L'\n') {
|
||||
**wp != L'\n' && **wp != L'#') {
|
||||
(*wp)++;
|
||||
}
|
||||
*sep = **wp;
|
||||
|
||||
/* Trim trailing whitespace to locate end of field. */
|
||||
*end = *wp - 1;
|
||||
while (**end == L' ' || **end == L'\t' || **end == L'\n') {
|
||||
(*end)--;
|
||||
/* Locate end of field, trim trailing whitespace if necessary */
|
||||
if (*wp == *start) {
|
||||
*end = *wp;
|
||||
} else {
|
||||
*end = *wp - 1;
|
||||
while (**end == L' ' || **end == L'\t' || **end == L'\n') {
|
||||
(*end)--;
|
||||
}
|
||||
(*end)++;
|
||||
}
|
||||
|
||||
/* Handle in-field comments */
|
||||
if (*sep == L'#') {
|
||||
while (**wp != L'\0' && **wp != L',' && **wp != L'\n') {
|
||||
(*wp)++;
|
||||
}
|
||||
*sep = **wp;
|
||||
}
|
||||
(*end)++;
|
||||
|
||||
/* Adjust scanner location. */
|
||||
if (**wp != L'\0')
|
||||
@ -1646,7 +1658,7 @@ archive_acl_from_text_l(struct archive_acl *acl, const char *text,
|
||||
ret = ARCHIVE_OK;
|
||||
types = 0;
|
||||
|
||||
while (text != NULL && *text != '\0') {
|
||||
while (text != NULL && *text != '\0') {
|
||||
/*
|
||||
* Parse the fields out of the next entry,
|
||||
* advance 'text' to start of next entry.
|
||||
@ -2057,23 +2069,30 @@ next_field(const char **p, const char **start,
|
||||
*start = *p;
|
||||
|
||||
/* Scan for the separator. */
|
||||
while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n') {
|
||||
while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n' &&
|
||||
**p != '#') {
|
||||
(*p)++;
|
||||
}
|
||||
*sep = **p;
|
||||
|
||||
/* If the field is only whitespace, bail out now. */
|
||||
if (**p == '\0') {
|
||||
/* Locate end of field, trim trailing whitespace if necessary */
|
||||
if (*p == *start) {
|
||||
*end = *p;
|
||||
return;
|
||||
} else {
|
||||
*end = *p - 1;
|
||||
while (**end == ' ' || **end == '\t' || **end == '\n') {
|
||||
(*end)--;
|
||||
}
|
||||
(*end)++;
|
||||
}
|
||||
|
||||
/* Trim trailing whitespace to locate end of field. */
|
||||
*end = *p - 1;
|
||||
while (**end == ' ' || **end == '\t' || **end == '\n') {
|
||||
(*end)--;
|
||||
/* Handle in-field comments */
|
||||
if (*sep == '#') {
|
||||
while (**p != '\0' && **p != ',' && **p != '\n') {
|
||||
(*p)++;
|
||||
}
|
||||
*sep = **p;
|
||||
}
|
||||
(*end)++;
|
||||
|
||||
/* Adjust scanner location. */
|
||||
if (**p != '\0')
|
||||
|
@ -1704,6 +1704,20 @@ _archive_write_disk_finish_entry(struct archive *_a)
|
||||
if (r2 < ret) ret = r2;
|
||||
}
|
||||
|
||||
/*
|
||||
* HYPOTHESIS:
|
||||
* If we're not root, we won't be setting any security
|
||||
* attributes that may be wiped by the set_mode() routine
|
||||
* below. We also can't set xattr on non-owner-writable files,
|
||||
* which may be the state after set_mode(). Perform
|
||||
* set_xattrs() first based on these constraints.
|
||||
*/
|
||||
if (a->user_uid != 0 &&
|
||||
(a->todo & TODO_XATTR)) {
|
||||
int r2 = set_xattrs(a);
|
||||
if (r2 < ret) ret = r2;
|
||||
}
|
||||
|
||||
/*
|
||||
* set_mode must precede ACLs on systems such as Solaris and
|
||||
* FreeBSD where setting the mode implicitly clears extended ACLs
|
||||
@ -1717,8 +1731,10 @@ _archive_write_disk_finish_entry(struct archive *_a)
|
||||
* Security-related extended attributes (such as
|
||||
* security.capability on Linux) have to be restored last,
|
||||
* since they're implicitly removed by other file changes.
|
||||
* We do this last only when root.
|
||||
*/
|
||||
if (a->todo & TODO_XATTR) {
|
||||
if (a->user_uid == 0 &&
|
||||
(a->todo & TODO_XATTR)) {
|
||||
int r2 = set_xattrs(a);
|
||||
if (r2 < ret) ret = r2;
|
||||
}
|
||||
@ -2223,6 +2239,15 @@ create_filesystem_object(struct archive_write_disk *a)
|
||||
*/
|
||||
mode = final_mode & 0777 & ~a->user_umask;
|
||||
|
||||
/*
|
||||
* Always create writable such that [f]setxattr() works if we're not
|
||||
* root.
|
||||
*/
|
||||
if (a->user_uid != 0 &&
|
||||
a->todo & (TODO_HFS_COMPRESSION | TODO_XATTR)) {
|
||||
mode |= 0200;
|
||||
}
|
||||
|
||||
switch (a->mode & AE_IFMT) {
|
||||
default:
|
||||
/* POSIX requires that we fall through here. */
|
||||
|
@ -49,7 +49,6 @@ DEFINE_TEST(test_extattr_freebsd)
|
||||
struct archive_entry *ae;
|
||||
ssize_t n;
|
||||
int fd;
|
||||
int extattr_privilege_bug = 0;
|
||||
|
||||
/*
|
||||
* First, do a quick manual set/read of an extended attribute
|
||||
@ -73,24 +72,6 @@ DEFINE_TEST(test_extattr_freebsd)
|
||||
assertEqualInt(4, n);
|
||||
close(fd);
|
||||
|
||||
/*
|
||||
* Repeat the above, but with file permissions set to 0000.
|
||||
* This should work (extattr_set_fd() should follow fd
|
||||
* permissions, not file permissions), but is known broken on
|
||||
* some versions of FreeBSD.
|
||||
*/
|
||||
fd = open("pretest2", O_RDWR | O_CREAT, 00000);
|
||||
failure("Could not create test file?!");
|
||||
if (!assert(fd >= 0))
|
||||
return;
|
||||
|
||||
n = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, "testattr", "1234", 4);
|
||||
if (n != 4) {
|
||||
skipping("Restoring xattr to an unwritable file seems to be broken on this platform");
|
||||
extattr_privilege_bug = 1;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
/* Create a write-to-disk object. */
|
||||
assert(NULL != (a = archive_write_disk_new()));
|
||||
archive_write_disk_set_options(a,
|
||||
@ -120,16 +101,12 @@ DEFINE_TEST(test_extattr_freebsd)
|
||||
archive_entry_free(ae);
|
||||
|
||||
/* Close the archive. */
|
||||
if (extattr_privilege_bug)
|
||||
/* If the bug is here, write_close will return warning. */
|
||||
assertEqualIntA(a, ARCHIVE_WARN, archive_write_close(a));
|
||||
else
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
|
||||
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
|
||||
|
||||
/* Verify the data on disk. */
|
||||
assertEqualInt(0, stat("test0", &st));
|
||||
assertEqualInt(st.st_mtime, 123456);
|
||||
assertEqualInt(st.st_mode & 0777, 0755);
|
||||
/* Verify extattr */
|
||||
n = extattr_get_file("test0", EXTATTR_NAMESPACE_USER,
|
||||
"foo", buff, sizeof(buff));
|
||||
@ -141,17 +118,20 @@ DEFINE_TEST(test_extattr_freebsd)
|
||||
/* Verify the data on disk. */
|
||||
assertEqualInt(0, stat("test1", &st));
|
||||
assertEqualInt(st.st_mtime, 12345678);
|
||||
assertEqualInt(st.st_mode & 0777, 0);
|
||||
/*
|
||||
* If we are not root, we have to make test1 user readable
|
||||
* or extattr_get_file() will fail
|
||||
*/
|
||||
if (geteuid() != 0) {
|
||||
chmod("test1", S_IRUSR);
|
||||
}
|
||||
/* Verify extattr */
|
||||
n = extattr_get_file("test1", EXTATTR_NAMESPACE_USER,
|
||||
"bar", buff, sizeof(buff));
|
||||
if (extattr_privilege_bug) {
|
||||
/* If we have the bug, the extattr won't have been written. */
|
||||
assertEqualInt(n, -1);
|
||||
} else {
|
||||
if (assertEqualInt(n, 6)) {
|
||||
buff[n] = '\0';
|
||||
assertEqualString(buff, "123456");
|
||||
}
|
||||
if (assertEqualInt(n, 6)) {
|
||||
buff[n] = '\0';
|
||||
assertEqualString(buff, "123456");
|
||||
}
|
||||
|
||||
/* Use libarchive APIs to read the file back into an entry and
|
||||
|
@ -90,7 +90,7 @@ int verify_data(const uint8_t* data_ptr, int magic, int size) {
|
||||
|
||||
static
|
||||
int extract_one(struct archive* a, struct archive_entry* ae, uint32_t crc) {
|
||||
la_ssize_t fsize, read;
|
||||
la_ssize_t fsize, bytes_read;
|
||||
uint8_t* buf;
|
||||
int ret = 1;
|
||||
uint32_t computed_crc;
|
||||
@ -100,9 +100,9 @@ int extract_one(struct archive* a, struct archive_entry* ae, uint32_t crc) {
|
||||
if(buf == NULL)
|
||||
return 1;
|
||||
|
||||
read = archive_read_data(a, buf, fsize);
|
||||
if(read != fsize) {
|
||||
assertEqualInt(read, fsize);
|
||||
bytes_read = archive_read_data(a, buf, fsize);
|
||||
if(bytes_read != fsize) {
|
||||
assertEqualInt(bytes_read, fsize);
|
||||
goto fn_exit;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user