diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-11-11 19:56:45 +0300 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-11-11 19:56:45 +0300 |
commit | 9655f95d0f501b03b33c7896b7b0c23d090aff81 (patch) | |
tree | 66ea6ffe5d8a5791b7bb8fcb8b7eebaceea5d96e | |
parent | 87e039d0160be16a9a242f74af2e90cdb9f97e12 (diff) |
tar: handle pax-encoded utf8 filenames and link names. Closes 9406
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | archival/libarchive/get_header_tar.c | 32 | ||||
-rwxr-xr-x | testsuite/tar.tests | 20 | ||||
-rw-r--r-- | testsuite/tar.utf8.tar.bz2 | bin | 0 -> 519 bytes |
3 files changed, 45 insertions, 7 deletions
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c index ea91a883e..c7e3bc16e 100644 --- a/archival/libarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c @@ -113,11 +113,19 @@ static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int g value = end + 1; # if ENABLE_FEATURE_TAR_GNU_EXTENSIONS - if (!global && is_prefixed_with(value, "path=")) { - value += sizeof("path=") - 1; - free(archive_handle->tar__longname); - archive_handle->tar__longname = xstrdup(value); - continue; + if (!global) { + if (is_prefixed_with(value, "path=")) { + value += sizeof("path=") - 1; + free(archive_handle->tar__longname); + archive_handle->tar__longname = xstrdup(value); + continue; + } + if (is_prefixed_with(value, "linkpath=")) { + value += sizeof("linkpath=") - 1; + free(archive_handle->tar__linkname); + archive_handle->tar__linkname = xstrdup(value); + continue; + } } # endif @@ -179,7 +187,13 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) * the message and we don't check whether we indeed * saw zero block directly before this. */ if (i == 0) { - bb_error_msg("short read"); + /* GNU tar 1.29 will be silent if tar archive ends abruptly + * (if there are no zero blocks at all, and last read returns zero, + * not short read 0 < len < 512). Complain only if + * the very first read fails. Grrr. + */ + if (archive_handle->offset == 0) + bb_error_msg("short read"); /* this merely signals end of archive, not exit(1): */ return EXIT_FAILURE; } @@ -195,7 +209,11 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) archive_handle->offset += i; /* If there is no filename its an empty header */ - if (tar.name[0] == 0 && tar.prefix[0] == 0) { + if (tar.name[0] == 0 && tar.prefix[0] == 0 + /* Have seen a tar archive with pax 'x' header supplying UTF8 filename, + * with actual file having all name fields NUL-filled. Check this: */ + && !p_longname + ) { if (archive_handle->tar__end) { /* Second consecutive empty header - end of archive. * Read until the end to empty the pipe from gz or bz2 diff --git a/testsuite/tar.tests b/testsuite/tar.tests index c44b7ad07..ffcbe9ba9 100755 --- a/testsuite/tar.tests +++ b/testsuite/tar.tests @@ -299,6 +299,26 @@ l4/V8LDoe90yiWJhOJvIypgEfxdyRThQkBVn/bI= " SKIP= +optional UNICODE_SUPPORT +testing "Pax-encoded UTF8 names and symlinks" '\ +tar xvf ../tar.utf8.tar.bz2 2>&1; echo $? +export LANG=en_US.UTF-8 +ls -l etc/ssl/certs/* | sed "s:.*etc/:etc/:" +unset LANG +rm -rf etc usr +' "\ +etc/ssl/certs/3b2716e5.0 +etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem +etc/ssl/certs/f80cc7f6.0 +usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt +0 +etc/ssl/certs/3b2716e5.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem +etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem -> /usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt +etc/ssl/certs/f80cc7f6.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem +" \ +"" "" +SKIP= + cd .. && rm -rf tar.tempdir || exit 1 diff --git a/testsuite/tar.utf8.tar.bz2 b/testsuite/tar.utf8.tar.bz2 Binary files differnew file mode 100644 index 000000000..0398e1aea --- /dev/null +++ b/testsuite/tar.utf8.tar.bz2 |