diff options
author | kientzle <kientzle@FreeBSD.org> | 2004-09-04 21:49:42 +0000 |
---|---|---|
committer | kientzle <kientzle@FreeBSD.org> | 2004-09-04 21:49:42 +0000 |
commit | 2a0558f74f8c424f58d3e404474e9e1361b7c9ea (patch) | |
tree | 90bfca819433b9d784bd966e8387dcda0b6dee2d /lib | |
parent | bc3177594847c472e25979621a8b83457fbf3eb6 (diff) | |
download | FreeBSD-src-2a0558f74f8c424f58d3e404474e9e1361b7c9ea.zip FreeBSD-src-2a0558f74f8c424f58d3e404474e9e1361b7c9ea.tar.gz |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libarchive/archive_read_support_format_tar.c | 34 |
1 files changed, 22 insertions, 12 deletions
diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c index ecc42ad..e8a769c 100644 --- a/lib/libarchive/archive_read_support_format_tar.c +++ b/lib/libarchive/archive_read_support_format_tar.c @@ -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); } |