From 8a95c5cb6ec5734b0df67f440db3e00ec6da1c8e Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Sat, 4 Sep 2004 21:49:42 +0000 Subject: [PATCH] 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 --- .../archive_read_support_format_tar.c | 34 ++++++++++++------- 1 file 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 ecc42ad55f1..e8a769cf988 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); }