From 9bccbe92f19dc84496ce677a231e9c093d02ae20 Mon Sep 17 00:00:00 2001 From: Michihiro NAKAJIMA Date: Tue, 6 Nov 2012 20:20:38 +0900 Subject: [PATCH] Fix issue 271; Handle the central directory including a zip comment. --- Makefile.am | 3 + libarchive/archive_read_support_format_zip.c | 45 +++++++++++- libarchive/test/CMakeLists.txt | 1 + .../test_read_format_zip_comment_stored.c | 66 +++++++++++++++++ ...st_read_format_zip_comment_stored_1.zip.uu | 12 ++++ ...st_read_format_zip_comment_stored_2.zip.uu | 71 +++++++++++++++++++ 6 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 libarchive/test/test_read_format_zip_comment_stored.c create mode 100644 libarchive/test/test_read_format_zip_comment_stored_1.zip.uu create mode 100644 libarchive/test/test_read_format_zip_comment_stored_2.zip.uu diff --git a/Makefile.am b/Makefile.am index c81baaf45..3fd14cfa3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -402,6 +402,7 @@ libarchive_test_SOURCES= \ libarchive/test/test_read_format_ustar_filename.c \ libarchive/test/test_read_format_xar.c \ libarchive/test/test_read_format_zip.c \ + libarchive/test/test_read_format_zip_comment_stored.c \ libarchive/test/test_read_format_zip_filename.c \ libarchive/test/test_read_large.c \ libarchive/test/test_read_pax_truncated.c \ @@ -633,6 +634,8 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_ustar_filename_eucjp.tar.Z.uu \ libarchive/test/test_read_format_ustar_filename_koi8r.tar.Z.uu \ libarchive/test/test_read_format_zip.zip.uu \ + libarchive/test/test_read_format_zip_comment_stored_1.zip.uu \ + libarchive/test/test_read_format_zip_comment_stored_2.zip.uu \ libarchive/test/test_read_format_zip_filename_cp866.zip.uu \ libarchive/test/test_read_format_zip_filename_cp932.zip.uu \ libarchive/test/test_read_format_zip_filename_koi8r.zip.uu \ diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index b55f1213e..db4f781eb 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -257,8 +257,49 @@ archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid) /* First four bytes are signature for end of central directory record. Four zero bytes ensure this isn't a multi-volume Zip file (which we don't yet support). */ - if (memcmp(p, "PK\005\006\000\000\000\000", 8) != 0) - return 0; + if (memcmp(p, "PK\005\006\000\000\000\000", 8) != 0) { + int64_t i, tail; + int found; + + /* + * If there is a comment in the end of central directory + * record, 22 bytes are too short. we have to read more + * to properly detect the end of central directory record. + * Hopefully, a length of the comment is not longer than + * 1002 bytes. should we read more? + */ + if (filesize + 22 > 1024) { + tail = 1024; + filesize = __archive_read_seek(a, tail * -1, SEEK_END); + } else { + tail = filesize + 22; + filesize = __archive_read_seek(a, 0, SEEK_SET); + } + if (filesize < 0) + return 0; + if ((p = __archive_read_ahead(a, tail, NULL)) == NULL) + return 0; + for (found = 0, i = 0;!found && i < tail - 22;) { + switch (p[i]) { + case 'P': + if (memcmp(p+i, + "PK\005\006\000\000\000\000", 8) == 0) { + p += i; + filesize += tail - + (22 + archive_le16dec(p+20)); + found = 1; + } else + i += 8; + break; + case 'K': i += 7; break; + case 005: i += 6; break; + case 006: i += 5; break; + default: i += 1; break; + } + } + if (!found) + return 0; + } /* Since we've already done the hard work of finding the end of central directory record, let's save the important diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index a55a8842a..e39b8c13c 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -137,6 +137,7 @@ IF(ENABLE_TEST) test_read_format_ustar_filename.c test_read_format_xar.c test_read_format_zip.c + test_read_format_zip_comment_stored.c test_read_format_zip_filename.c test_read_large.c test_read_pax_truncated.c diff --git a/libarchive/test/test_read_format_zip_comment_stored.c b/libarchive/test/test_read_format_zip_comment_stored.c new file mode 100644 index 000000000..5394cebc0 --- /dev/null +++ b/libarchive/test/test_read_format_zip_comment_stored.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +/* + * Read a zip file that has a zip comment in the end of the central + * directory record. + */ +static void +verify(const char *refname) +{ + char *p; + size_t s; + struct archive *a; + struct archive_entry *ae; + + extract_reference_file(refname); + p = slurpfile(&s, refname); + + /* Symlinks can only be extracted with the seeking reader. */ + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); + assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 1)); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString("file0", archive_entry_pathname(ae)); + assertEqualInt(AE_IFREG | 0644, archive_entry_mode(ae)); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString("build.sh", archive_entry_pathname(ae)); + assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae)); + assertEqualInt(23, archive_entry_size(ae)); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_zip_comment_stored) +{ + verify("test_read_format_zip_comment_stored_1.zip"); + verify("test_read_format_zip_comment_stored_2.zip"); +} diff --git a/libarchive/test/test_read_format_zip_comment_stored_1.zip.uu b/libarchive/test/test_read_format_zip_comment_stored_1.zip.uu new file mode 100644 index 000000000..9b6449ec6 --- /dev/null +++ b/libarchive/test/test_read_format_zip_comment_stored_1.zip.uu @@ -0,0 +1,12 @@ +begin 644 test_read_format_zip_comment_stored_1.zip +M4$L#!`H``````.&`9D$````````````````%`!P`9FEL93!55`D``Q:WF%`6 +MMYA0=7@+``$$]0$```04````4$L#!`H``````+Q[9D'J6.I]%P```!<````( +M`!P`8G5I;&0N`L``03U`0``!!0` +M``!02P$"'@,*``````"\>V9!ZECJ?1<````7````"``8```````!````[8$_ +M````8G5I;&0N`L``03U`0``!!0```!02P4&``````(` +M`@"9````F````"0`5&AIN38PH``+H9```%`!P`9FEL93!55`D``V^VF%`M +MMIA0=7@+``$$]0$```04````Q5A;D]/(&7V.?T677PR4[4FRRV[MY&$S#!0X +M-3!DAL`N+UMMJ6UW+*FUZM88\^MSSM>MBPVA4GE(J)K"DOJ[G>_>=R^NGK]^ +MH3:N485=ZR;;V0>CUFV5%V8YF?R]-3Y85_F?E5IYCZ>?)TJI)VH70GUY<3'0 +M++A9U1.U<:8>VJK;/5EJ1J+"VRHHVQS&5 +MNZSE.TW1B.D +M\JA"H[.]:90.D7LR*7,YC'%N"P!H3#TR\D(H_04%]6)\NRZMB#'53E>9H>K4 +M0CD\-;HYBO\:H\4Q +M\(0Z-#;P-^087V,;F: +M\4`T5_[!985."*Y;6P2$SDBO*"&KK1M$\.E,1FXW&].0AZV":3;@"'^,Q!CO +M\=7JHC@*'Z\9J&V5$39=V'",DLPG7<)S_E+=,Y1]"8KN92>2L.J@CJY%'`(N +M"XP0:+!S>N5#0;R?8HW:+BF/;;)5:V;8(W_R\CH%(+D0M&T6[=AYQJO#@@Q./>H?N_R +M?QV5^`O +M>-H&7E0Z0[YLN\"YOGW[Z^K-2YP]=(!F2*K<1?5@5SJX>G/_[NKF!@>A18!+ +MHE`^-*VX,!V\B\5M(;2B5`_DQFX1@/C4_8X\?-;8&K7(&].+80+D!B8776VY +M?JWWYD:*3?@41(^Z#7)PFI7X-I7@S0&?*TZ8150'T`0HD`N67P-;0TG$0QX] +M:R:S7O=94C;!3)7(;:E+5,RL<)DNEN7W\\'8I?_,LFF^>/$;0-_+V]CC +MQM3I&Q5[(%8Q!H$,/"OMSK-SH-]XB3RJ1#)AD^JT45=O5WZL%H!NCF":`EJH +MIC%O3L],%0*!E5!EA?8G/*2HHDSZ03FXB042\#+%67;'[6\F,=.1J2B.P4`] +M76UB\BU/H5_$6G6[R17`+*?X=M,*&#$I,%$TE +MZG0JJ`=4<%UQ6F%!*'75`IA:;XW000H3/VF9=P5B!B!FH^*`;-.J:LLUIA@$ +MY=#V.N@FDU]11?W.M4AR.,Q)A`BOS-720M")(K20,>VB?C>-BJ+@>-G+I%)O8[,I3$"N3?:5.R18V65,T[#K<#`L,5&Q8$NY)WS0 +M^;IM:$5QG)_F61L8?`GJ$13T:',N\0%*A//Z&R!%/135^7<75]DTAN +MX87W/\JQTPQ[+D<2L(H3#I131C=7_[TP\__%%= +M/U_8/(W5UA$@@`E[HZ,/J[>]D`D>LQ@ +M&(T:#F@Y*:>YV;"53-7H/0N4[?Q`%])#S^Z?JQG'S1-H9Y+\LS%X/RX^VOKT +MU&N;-70GSFX^O3BGNKNY.7_PR?B%)W<2YEEA48#(>H58]D3SZK%\SON3(A>[SLL_RTXORG.3NMS"&;#B_] +M[KQ2_'\RIDOX;R?1:09\V)D4`N,5<9[&%-]BM6.0K*6FPK-0LM]"SD/D-.S_ +MIT']Q@7CAXE@2&H:Q)3&&',YX;0AZ[>LGSNC'RQ:5-R0!V?'21;-$9G2\!9" +M52YU[0W&^G2[M,.< +M`;NCT2<;-)&ZK433^3D$G3$BKSCHHT_U&K"=3!V1S6K&^2QPRPD19V[VI?V, +MR8AK3!:GAQKA*\L4[%EM9,#)73437U-KFUG,.##\P>T-;X/$5!DUT_V(>N1; +MPN5/8D/+4#H<'AOCNI+S&.-I4`?*4UNT7MX1R2`I*^RJ&C'`R9%V8]50X<21 +MH\.D/A.8F_&+I.E<.$;YW"+C?5BUEVC;<@\+:0S%K.=K5^7=E=2_Y1QC'%5, +M3)!T2R-MWF;I=LO3"2@?T0]TV8)2N1YPQ+'2AL0!U8-M7!5'WX-$F\1G2;\V +M_BQ>3C(_8]OP\.)-];:VS/?-G@]I*+&KL +M5*=LL<"P6R(*5;"EY`3'ZE+7MSM!PZ[#2O +M8E'8+9>#3M%8`&0!Q*97]=JI;EG'*N[CIH\!P0+8Z5\3[71HO8,F'5^<-,6& +MD!+C"UJ)L^`F<=0AWMWI^BSYV#][J1RR4:0)U2M=Z3082]1T$O<%QO1=AXZHO;F%!M1#!O3)U?RH1FX(`D&HU42,1^FZN +M`\WBPG.BZ+D=.K-]'1,._`%!+`P0*``````"\>V9!ZECJ?1<````7 +M````"``<`&)U:6QD+G-H550)``-CKIA0+;:84'5X"P`!!/4!```$%````",A +M+V)I;B]S:`IE8VAO(")T97-T+B(*4$L!`AX#%`````@`B(!F01)=ZY-C"@`` +MNAD```4`&````````0```*2!`````&9I;&4P550%``-OMIA0=7@+``$$]0$` +M``04````4$L!`AX#"@``````O'MF0>I8ZGT7````%P````@`&````````0`` +M`.V!H@H``&)U:6QD+G-H550%``-CKIA0=7@+``$$]0$```04````4$L%!@`` +M```"``(`F0```/L*```D`%1H:7,@:7,@82!S86UP;&4@9FEL92!F;W(@:7-S +'=64@,C