Some old tar archives rely on "regular-file-plus-trailing-slash" to

denote a directory.  Unfortunately, in the presence of GNU or POSIX
extensions, this code was checking the truncated filename stored in the
regular header rather than the full filename stored in the extended
attribute.  As a result, long filenames with '/' in just the right
position would trigger this check and be erroneously marked as
directories.  Move the check so it only considers the full filename.
Note: the check can't simply be disabled for archives that contain
these extensions because there are some very broken archivers out
there.

Thanks to: Will Froning
MFC after: 3 days
This commit is contained in:
Tim Kientzle 2004-09-04 21:49:42 +00:00
parent ea0f517b92
commit 8a95c5cb6e

View File

@ -351,12 +351,33 @@ archive_read_format_tar_read_header(struct archive *a,
{
struct stat st;
struct tar *tar;
const char *p;
int r;
size_t l;
memset(&st, 0, sizeof(st));
tar = *(a->pformat_data);
tar->entry_offset = 0;
return (tar_read_header(a, tar, entry, &st));
r = tar_read_header(a, tar, entry, &st);
if (r == ARCHIVE_OK) {
/*
* "Regular" entry with trailing '/' is really
* directory: This is needed for certain old tar
* variants and even for some broken newer ones.
*/
p = archive_entry_pathname(entry);
l = strlen(p);
if (S_ISREG(st.st_mode) && p[l-1] == '/') {
st.st_mode &= ~S_IFMT;
st.st_mode |= S_IFDIR;
}
/* Copy the final stat data into the entry. */
archive_entry_copy_stat(entry, &st);
}
return (r);
}
static int
@ -421,8 +442,6 @@ tar_read_header(struct archive *a, struct tar *tar,
ssize_t bytes;
int err;
const void *h;
const char *p;
size_t l;
const struct archive_entry_header_ustar *header;
/* Read 512-byte header record */
@ -513,16 +532,7 @@ tar_read_header(struct archive *a, struct tar *tar,
a->archive_format_name = "tar (non-POSIX)";
err = header_old_tar(a, tar, entry, st, h);
}
/* "Regular" entry with trailing '/' is really directory. */
p = archive_entry_pathname(entry);
l = strlen(p);
if (S_ISREG(st->st_mode) && p[l-1] == '/') {
st->st_mode &= ~S_IFMT;
st->st_mode |= S_IFDIR;
}
}
archive_entry_copy_stat(entry, st);
--tar->header_recursion_depth;
return (err);
}