diff options
author | Tim Kientzle <kientzle@FreeBSD.org> | 2004-09-04 21:49:42 +0000 |
---|---|---|
committer | Tim Kientzle <kientzle@FreeBSD.org> | 2004-09-04 21:49:42 +0000 |
commit | 8a95c5cb6ec5734b0df67f440db3e00ec6da1c8e (patch) | |
tree | 90bfca819433b9d784bd966e8387dcda0b6dee2d /lib/libarchive/archive_read_support_format_tar.c | |
parent | ea0f517b92c83078c659b23f31f6218b68d22b5b (diff) | |
download | src-8a95c5cb6ec5734b0df67f440db3e00ec6da1c8e.tar.gz src-8a95c5cb6ec5734b0df67f440db3e00ec6da1c8e.zip |
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
Notes
Notes:
svn path=/head/; revision=134775
Diffstat (limited to 'lib/libarchive/archive_read_support_format_tar.c')
-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 ecc42ad55f15..e8a769cf9882 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); } |